Skip to content

Commit cb145ef

Browse files
committed
Adapt DFT-based convolution to fit the direct one
1 parent 72325c2 commit cb145ef

File tree

2 files changed

+23
-51
lines changed

2 files changed

+23
-51
lines changed

SEImplementation/SEImplementation/Segmentation/BackgroundConvolution.h

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,7 @@ class BgDFTConvolutionImageSource : public ProcessingImageSource<DetectionImage:
9494
std::shared_ptr<VectorImage<SeFloat>> kernel)
9595
: ProcessingImageSource<DetectionImage::PixelType>(image),
9696
m_variance(variance), m_threshold(threshold), m_convolution(kernel) {
97-
m_kernel_min = std::numeric_limits<DetectionImage::PixelType>::max();
98-
for (int y = 0; y < kernel->getHeight(); ++y) {
99-
for (int x = 0; x < kernel->getWidth(); ++x) {
100-
auto v = std::abs(kernel->getValue(x, y));
101-
if (v > 0. && v < m_kernel_min) {
102-
m_kernel_min = v;
103-
}
104-
}
10597
}
106-
}
10798

10899
protected:
109100

@@ -135,7 +126,7 @@ class BgDFTConvolutionImageSource : public ProcessingImageSource<DetectionImage:
135126
}
136127
);
137128

138-
// Get the mask, and the negative
129+
// Get the mask
139130
// For instance, with a threshold of 0.5
140131
// Variance Mask Negative
141132
// 1 1 1 0 0 0 1 1 1
@@ -147,60 +138,41 @@ class BgDFTConvolutionImageSource : public ProcessingImageSource<DetectionImage:
147138
return clipped_variance->getValue(x, y) < m_threshold;
148139
}
149140
);
150-
auto mask_neg = FunctionalImage<DetectionImage::PixelType>::create(
151-
mask->getWidth(), mask->getHeight(),
152-
[mask](int x, int y) -> DetectionImage::PixelType {
153-
return mask->getValue(x, y) == 0.;
154-
}
155-
);
156141

157142
// Get the image masking out values where the variance is greater than the threshold
158143
auto masked_img = MultiplyImage<DetectionImage::PixelType>::create(clipped_img, mask);
159144

160-
// Convolve the original image with the kernel, padding with 0
161-
auto conv_img = VectorImage<DetectionImage::PixelType>::create(clipped_img);
162-
m_convolution.convolve(conv_img);
163-
164-
// Convolve the masked image, padding with 0 as well
145+
// Convolve the masked image, padding with 0
165146
auto conv_masked = VectorImage<DetectionImage::PixelType>::create(masked_img);
166147
m_convolution.convolve(conv_masked);
167148

168-
// Convolve the mask, and the negative
149+
// Convolve the mask
169150
// This gives us in each cell the sum of the kernel values that have been used,
170-
// so we can divide the previous convolutions.
151+
// so we can divide the previous convolution.
171152
auto conv_mask = VectorImage<DetectionImage::PixelType>::create(mask);
172-
auto conv_mask_neg = VectorImage<DetectionImage::PixelType>::create(mask_neg);
173153
m_convolution.convolve(conv_mask);
174-
m_convolution.convolve(conv_mask_neg);
175154

176-
// Copy out the value of the convolved image, divided by the negative mask, replacing
177-
// any non-masked cell
155+
// Copy out the value of the convolved image, divided by the negative mask, applying
156+
// again the mask to the convolved result
178157
int off_x = start_x - clip_x;
179158
int off_y = start_y - clip_y;
180159
for (int y = 0; y < height; ++y) {
181160
for (int x = 0; x < width; ++x) {
182-
// We want to use the masked convolution only if the resulting convolved mask
183-
// is not 0. Since we are dealing with floats, we can not just compare to 0, because
184-
// there will likely be a very small value greater than 0
185-
if (std::abs(conv_mask->getValue(x + off_x, y + off_y)) > m_kernel_min / 2.) {
161+
if (mask->getValue(x + off_x, y + off_y)) {
186162
tile.setValue(
187163
x + start_x, y + start_y,
188164
conv_masked->getValue(x + off_x, y + off_y) / conv_mask->getValue(x + off_x, y + off_y)
189165
);
190-
}
191-
else {
192-
tile.setValue(
193-
x + start_x, y + start_y,
194-
conv_img->getValue(x + off_x, y + off_y) / conv_mask_neg->getValue(x + off_x, y + off_y)
195-
);
166+
} else {
167+
tile.setValue(x + start_x, y + start_y, 0);
196168
}
197169
}
198170
}
199171
}
200172

201173
private:
202174
std::shared_ptr<DetectionImage> m_variance;
203-
DetectionImage::PixelType m_threshold, m_kernel_min;
175+
DetectionImage::PixelType m_threshold;
204176
ConvolutionType m_convolution;
205177
};
206178

SEImplementation/tests/src/Segmentation/BackgroundConvolution_test.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,17 @@ BOOST_AUTO_TEST_CASE_TEMPLATE (kernel3_background, T, convolution_types) {
4343
auto image_source = std::make_shared<T>(image, variance, 0.5, kernel);
4444
auto result = image_source->getImageTile(0, 0, 5, 5)->getImage();
4545

46-
// When applying the kernel for getting the value of a cell, is there is no value corresponding to a
47-
// variance below the threshold, the kernel is applied as one would normally expect.
48-
// Otherwise, *only* the values that are below the threshold are actually used for the given cell.
46+
// When applying the kernel for getting the value of a cell, the convolution is done only for pixels
47+
// with a variance below the threshold: basically, on a masked image.
48+
// The convolved image is masked again, so pixels that are next to a pixel below the threshold remain 0.
4949
// For this test, there are only two cells below the threshold (0.1 and 0.2, corresponding to 3.2 and 4.2)
5050
auto expected = VectorImage<SeFloat>::create(
5151
5, 5, std::vector<SeFloat>{
52-
1.275, 2.020, 3.02000, 4.02000, 4.775,
53-
1.300, 2.100, 3.20000, 4.20000, 4.900,
54-
1.400, 3.200, 3.53333, 3.86667, 4.200,
55-
1.500, 2.300, 3.20000, 4.20000, 5.100,
56-
1.625, 2.380, 3.38000, 4.38000, 5.125,
52+
0.00, 0.00, 0.00, 0.00, 0.00,
53+
0.00, 0.00, 0.00, 0.00, 0.00,
54+
0.00, 0.00, 3.53333, 3.86667, 0.00,
55+
0.00, 0.00, 0.00, 0.00, 0.00,
56+
0.00, 0.00, 0.00, 0.00, 0.00,
5757
}
5858
);
5959

@@ -94,10 +94,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE (kernel3_background_with_offset, T, convolution_ty
9494

9595
auto expected = VectorImage<SeFloat>::create(
9696
3, 4, std::vector<SeFloat>{
97-
2.100, 3.20000, 4.20000,
98-
3.200, 3.53333, 3.86667,
99-
2.300, 3.20000, 4.20000,
100-
2.380, 3.38000, 4.38000,
97+
0.00, 0.00, 0.00,
98+
0.00, 3.53333, 3.86667,
99+
0.00, 0.00, 0.00,
100+
0.00, 0.00, 0.00,
101101
}
102102
);
103103

@@ -127,7 +127,7 @@ struct KernelSize {
127127
typedef boost::mpl::list<KernelSize<5>, KernelSize<7>, KernelSize<9>, KernelSize<11>> kernel_sizes;
128128

129129
BOOST_AUTO_TEST_CASE_TEMPLATE (kerneln_background, T, kernel_sizes) {
130-
// For a big kernel, just compare both do the same
130+
// For a big kernel, just compare they both do the same
131131
// Doing it manually would be painful, but the previous test, with small sizes,
132132
// can be easily followed up by hand
133133

0 commit comments

Comments
 (0)