SurfaceLayerDetectionAlgorithm.cpp
3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "SurfaceLayerDetectionAlgorithm.hpp"
#include "algorithm/common/PfcSegmenter.hpp"
#include "algorithm/gpu/common/MedianFilter.hpp"
#include "algorithm/gpu/common/MedianFilter3x3.hpp"
cv::cuda::GpuMat
SurfaceLayerDetectionAlgorithm::setMinimumTemperature(ushort temperature) {
deviceMinTemperature.setTo(temperature);
return deviceMinTemperature;
}
void SurfaceLayerDetectionAlgorithm::setup(const cv::Size &frameSize,
const CVMatLoader &loader) {
currentFrameSize = frameSize;
medianFilter = createMedianFilter(3);
deviceRegionMask.upload(loader.asMat("/scene_model/FOV", CV_8UC1) &
PfcSegmenter(loader, frameSize).mask("Divertors"));
medianFilterInput = std::make_unique<ContinuousGpuMat>(frameSize, CV_16UC1);
medianFilterOutput =
std::make_unique<ContinuousGpuMat>(frameSize, CV_16UC1);
deviceFrame = medianFilterInput->device();
deviceFiltered = medianFilterOutput->device();
deviceMinTemperature.create(frameSize, CV_16UC1);
setMinimumTemperature(434);
deviceFloatInput.create(frameSize, CV_32F);
deviceDifference.create(frameSize, CV_32F);
deviceDifference.setTo(cv::Scalar::all(0));
deviceDifferenceAbs.create(frameSize, CV_32F);
deviceDifferenceAbs.setTo(cv::Scalar::all(0));
deviceSurfaceLayers.create(frameSize, CV_8UC1);
deviceSurfaceLayers.setTo(cv::Scalar::all(0));
}
void SurfaceLayerDetectionAlgorithm::handleFrame(const cv::Mat &hostFrame,
unsigned long timestamp) {
currentTimestamp = timestamp;
deviceFrame.upload(hostFrame);
/* Apply median filter */
medianFilter->apply(deviceFrame, deviceFiltered);
/* Apply detection PFC mask */
cv::cuda::bitwise_and(deviceFiltered, deviceFiltered, deviceInput,
deviceRegionMask);
/* Trim noise at minimum temperature */
cv::cuda::max(deviceInput, deviceMinTemperature, deviceInput);
/* Convert to float */
deviceInput.convertTo(deviceFloatInput, CV_32F);
/* Calculate normalized derivative of the temperature evolution */
normalizedDerivative(); /* Result in deviceDifference & deviceDifferenceAbs */
/* Threshold rapidly evolving pixels */
cv::cuda::compare(deviceDifferenceAbs, derivativeThreshold, deviceResult,
cv::CMP_GE);
/* Merge surface layers */
cv::cuda::bitwise_or(deviceResult, deviceSurfaceLayers,
deviceSurfaceLayers);
}
void SurfaceLayerDetectionAlgorithm::normalizedDerivative() {
if (devicePreviousPreviousFrame.empty()) {
previousPreviousTimestamp = currentTimestamp;
deviceFloatInput.copyTo(devicePreviousPreviousFrame);
return;
}
if (devicePreviousFrame.empty()) {
previousTimestamp = currentTimestamp;
deviceFloatInput.copyTo(devicePreviousFrame);
return;
}
cv::cuda::subtract(deviceFloatInput, devicePreviousPreviousFrame,
deviceDifference);
cv::cuda::multiply(
deviceDifference,
cv::Scalar::all((currentTimestamp - previousPreviousTimestamp) *
NS_TO_S),
deviceDifference);
cv::cuda::divide(deviceDifference, devicePreviousFrame, deviceDifference);
cv::cuda::abs(deviceDifference, deviceDifferenceAbs);
previousPreviousTimestamp = previousTimestamp;
previousTimestamp = currentTimestamp;
devicePreviousFrame.copyTo(devicePreviousPreviousFrame);
deviceFloatInput.copyTo(devicePreviousFrame);
}
std::unique_ptr<cv::cuda::Filter>
SurfaceLayerDetectionAlgorithm::createMedianFilter(int kernel) const {
if (kernel == 3) {
/* Implementation optimised for the small kernel size */
return std::make_unique<MedianFilter3x3<ushort>>(currentFrameSize);
}
return CudaFilter::createMedianFilter16U(currentFrameSize, kernel);
}