2 #ifndef CVD_CONVOLUTION_H_ 3 #define CVD_CONVOLUTION_H_ 10 #include <cvd/config.h> 11 #include <cvd/exceptions.h> 12 #include <cvd/image.h> 13 #include <cvd/internal/pixel_operations.h> 14 #include <cvd/utility.h> 31 unsigned int i, argmax = 0;
32 std::vector<double> kernel(k.size());
33 for(i = 0; i < k.size(); i++)
35 double x = i + 0.5 - k.size() / 2.0;
36 sum += kernel[i] = exp(-x * x / (2 * stddev * stddev));
37 if(kernel[i] > kernel[argmax])
41 for(i = 0; i < k.size(); i++)
42 finalSum += k[i] = (T)(kernel[i] * maxval / kernel[argmax]);
53 template <
class S,
class T>
54 T
scaleKernel(
const std::vector<S>& k, std::vector<T>& scaled, T maxval)
56 unsigned int i, argmax = 0;
57 for(i = 1; i < k.size(); i++)
60 scaled.resize(k.size());
62 for(i = 0; i < k.size(); i++)
63 sum += (scaled[i] = (T)((k[i] * maxval) / k[argmax]));
73 for(j = 0; j < w; j++)
75 T* src = I.
data() + j;
76 T* end = src + w * (h - 4);
79 T sum = (T)(0.0544887 * (src[0] + src[4 * w])
80 + 0.2442010 * (src[w] + src[3 * w])
81 + 0.4026200 * src[2 * w]);
86 for(i = h - 5; i >= 0; i--)
88 T* src = I.
data() + i * w;
92 T sum = (T)(0.0544887 * (src[0] + src[4])
93 + 0.2442010 * (src[1] + src[3])
94 + 0.4026200 * src[2]);
95 *(src + 2 * w + 2) = sum;
106 namespace Convolution
112 using CVD::Exceptions::All::All;
120 :
All(
"Incompatible image sizes in " +
function)
130 :
All(
"Odd sized kernel required in " +
function) {};
143 typedef typename Pixel::traits<T>::wider_type sum_type;
151 const double factor = 1.0 / (win.
x * win.
y);
152 std::vector<sum_type> buffer(w * win.
y);
153 std::vector<sum_type> sums_v(w);
154 sum_type* sums = &sums_v[0];
155 sum_type* next_row = &buffer[0];
156 sum_type* oldest_row = &buffer[0];
158 const T* input = I.
data();
159 T* output = J[hwin.
y] - hwin.
x;
160 for(
int i = 0; i < h; i++)
162 sum_type hsum = sum_type();
163 const T* back = input;
165 for(j = 0; j < win.
x - 1; j++)
177 differences(sums + win.
x - 1, oldest_row + win.
x - 1, sums + win.
x - 1, w - win.
x + 1);
180 if(oldest_row == &buffer[0] + w * win.
y)
181 oldest_row = &buffer[0];
185 if(next_row == &buffer[0] + w * win.
y)
186 next_row = &buffer[0];
208 template <
class T,
int A,
int B,
int C>
211 typedef typename Pixel::traits<T>::wider_type wider;
212 static const wider S = (A + B + C + B + A);
213 int width = I.
size().x;
214 int height = I.
size().y;
217 for(i = 0; i < height; i++)
223 p[0] = (T)(((c + c) * A + (b + b) * B + a * C) / S);
224 p[1] = (T)(((b + d) * A + (a + c) * B + b * C) / S);
225 for(j = 0; j < width - 4; j++, p++)
228 p[2] = (T)(((a + e) * A + (b + d) * B + c * C) / S);
234 p[2] = (T)(((a + c) * A + (b + d) * B + c * C) / S);
235 p[3] = (T)(((b + b) * A + (c + c) * B + d * C) / S);
238 for(j = 0; j < width; j++)
243 p[0] = (T)(((p[2 * width] + p[2 * width]) * A + (b + b) * B + a * C) / S);
244 p[width] = (T)(((b + p[width * 3]) * A + (a + p[2 * width]) * B + b * C) / S);
245 for(i = 0; i < height - 4; i++)
247 wider c = p[2 * width];
248 p[2 * width] = (T)(((a + p[4 * width]) * A + (b + p[3 * width]) * B + c * C) / S);
253 wider c = p[2 * width];
254 p[2 * width] = (T)(((a + c) * A + (b + p[width * 3]) * B + c * C) / S);
255 p[3 * width] = (T)(((b + b) * A + (c + c) * B + p[width * 3] * C) / S);
259 template <
class T,
int A,
int B,
int C,
int D>
262 typedef typename Pixel::traits<T>::wider_type wider;
263 static const wider S = (A + B + C + D + C + B + A);
264 int width = I.
size().x;
265 int height = I.
size().y;
268 for(i = 0; i < height; i++)
274 p[0] = (T)(((d + d) * A + (c + c) * B + (b + b) * C + a * D) / S);
275 p[1] = (T)(((c + p[4]) * A + (b + d) * B + (a + c) * C + b * D) / S);
276 p[2] = (T)(((b + p[5]) * A + (a + p[4]) * B + (b + d) * C + c * D) / S);
277 for(j = 0; j < width - 6; j++, p++)
280 p[3] = (T)(((a + p[6]) * A + (b + p[5]) * B + (c + p[4]) * C + d * D) / S);
287 p[3] = (T)(((a + e) * A + (b + p[5]) * B + (c + e) * C + d * D) / S);
288 p[4] = (T)(((b + d) * A + (c + e) * B + (d + p[5]) * C + e * D) / S);
289 p[5] = (T)(((c + c) * A + (d + d) * B + (e + e) * C + p[5] * D) / S);
292 for(j = 0; j < width; j++)
297 wider c = p[2 * width];
298 wider d = p[3 * width];
299 p[0] = (T)(((d + d) * A + (c + c) * B + (b + b) * C + a * D) / S);
300 p[width] = (T)(((c + p[4 * width]) * A + (b + d) * B + (a + c) * C + b * D) / S);
301 p[2 * width] = (T)(((b + p[5 * width]) * A + (a + p[4 * width]) * B + (b + d) * C + c * D) / S);
302 for(i = 0; i < height - 6; i++)
305 p[3 * width] = (T)(((a + p[width * 6]) * A + (b + p[width * 5]) * B + (c + p[width * 4]) * C + d * D) / S);
312 wider e = p[4 * width];
313 p[3 * width] = (T)(((a + e) * A + (b + p[5 * width]) * B + (c + e) * C + d * D) / S);
314 p[4 * width] = (T)(((b + d) * A + (c + e) * B + (d + p[5 * width]) * C + e * D) / S);
315 p[5 * width] = (T)(((c + c) * A + (d + d) * B + (e + e) * C + p[5 * width] * D) / S);
319 template <
class T,
class K>
320 void convolveSeparableSymmetric(
Image<T>& I,
const std::vector<K>& kernel, K divisor)
322 typedef typename Pixel::traits<T>::wider_type sum_type;
325 int r = (int)kernel.size() / 2;
328 double factor = 1.0 / divisor;
329 for(j = 0; j < w; j++)
331 T* src = I.
data() + j;
332 for(i = 0; i < h - 2 * r; i++, src += w)
334 sum_type sum = src[r * w] * kernel[r], v;
335 for(m = 0; m < r; m++)
336 sum += (src[m * w] + src[(2 * r - m) * w]) * kernel[m];
337 *(src) = static_cast<T>(sum * factor);
340 int offset = r * w + r;
341 for(i = h - 2 * r - 1; i >= 0; i--)
344 for(j = 0; j < w - 2 * r; j++, src++)
346 sum_type sum = src[r] * kernel[r], v;
347 for(m = 0; m < r; m++)
348 sum += (src[m] + src[2 * r - m]) * kernel[m];
349 *(src + offset) = static_cast<T>(sum * factor);
354 template <
class A,
class B>
357 static inline const B*
get(
const A* row,
int w, B* rowbuf)
367 static inline const T*
get(
const T* row, int, T*)
373 template <
class A,
class B>
374 const B* getPixelRowTyped(
const A* row,
int n, B* rowbuf)
379 template <
class T,
class S>
382 static inline void cast_copy(
const T* from, S* to,
int count)
384 for(
int i = 0; i < count; i++)
385 to[i] = static_cast<S>(from[i]);
392 static inline void cast_copy(
const T* from, T* to,
int count)
398 template <
class T,
class S>
408 template <
class T,
int N>
412 static inline T at(
const T* input,
const S& factor,
const S* kernel) {
return ConvolveMiddle<T, N - 1>::at(input, factor, kernel) + (input[-N] + input[N]) * kernel[N - 1]; }
419 static inline T at(
const T* input,
const S& factor,
const S* kernel,
int ksize)
421 T hsum = *input * factor;
422 for(
int k = 0; k < ksize; k++)
423 hsum += (input[-k - 1] + input[k + 1]) * kernel[k];
428 template <
class T,
int C>
432 static inline T at(
const T* input,
const S& factor,
const S* kernel,
int ksize)
434 T hsum = *input * factor;
435 for(
int k = 0; k < ksize; k++)
436 hsum += (input[-k - 1] + input[k + 1]) * kernel[k];
445 static inline T at(
const T* input,
const S& factor,
const S*) {
return *input * factor; }
448 template <
class T,
class S>
449 inline const T* convolveMiddle(
const T* input,
const S& factor,
const S* kernel,
int ksize,
int n, T* output)
452 for(int j = 0; j < n; ++j, ++input, ++output) \ 454 *output = ConvolveMiddle<T, I>::at(input, factor, kernel); \ 479 for(
int j = 0; j < n; j++, input++)
489 inline void convolveGaussian(
BasicImage<T>& I,
double sigma,
double sigmas = 3.0)
491 convolveGaussian(I, I, sigma, sigmas);
498 typedef typename Pixel::traits<T>::float_type sum_type;
500 int ksize = (int)ceil(sigmas * sigma);
502 std::vector<sum_comp_type> kernel(ksize);
503 sum_comp_type ksum = sum_comp_type();
504 for(
int i = 1; i <= ksize; i++)
505 ksum += (kernel[i - 1] = static_cast<sum_comp_type>(exp(-i * i / (2 * sigma * sigma))));
506 for(
int i = 0; i < ksize; i++)
507 kernel[i] /= (2 * ksum + 1);
508 double factor = 1.0 / (2 * ksum + 1);
511 int swin = 2 * ksize;
513 if(w < ksize || h < ksize)
519 std::vector<sum_type> buffer(std::max(w, ksize) * (swin + 1));
520 std::vector<sum_type> aligned_rowbuf(w);
521 std::vector<sum_type> aligned_outbuf(w);
523 sum_type* rowbuf = aligned_rowbuf.data();
524 sum_type* outbuf = aligned_outbuf.data();
526 std::vector<sum_type*> rows(swin + 1);
527 for(
int k = 0; k < swin + 1; k++)
528 rows[k] = buffer.data() + k * std::max(w, ksize);
530 T* output = out.
data();
531 for(
int i = 0; i < h; i++)
533 sum_type* next_row = rows[swin];
534 const sum_type* input = getPixelRowTyped(I[i], w, rowbuf);
536 for(
int j = 0; j < ksize; j++)
538 sum_type hsum =
static_cast<sum_type
>(input[j] * factor);
539 for(
int k = 0; k < ksize; k++)
540 hsum += (input[std::max(j - k - 1, 0)] + input[j + k + 1]) * kernel[k];
545 input = convolveMiddle<sum_type, sum_comp_type>(input,
static_cast<sum_comp_type
>(factor), &kernel.front(), ksize, w - swin, next_row + ksize);
547 for(
int j = w - ksize; j < w; j++, input++)
549 sum_type hsum =
static_cast<sum_type
>(*input * factor);
550 const int room = w - j;
551 for(
int k = 0; k < ksize; k++)
553 hsum += (input[-k - 1] + input[std::min(k + 1, room - 1)]) * kernel[k];
560 const sum_type* middle_row = rows[ksize];
562 for(
int k = 0; k < ksize; k++)
564 const sum_comp_type m = kernel[k];
565 const sum_type* row1 = rows[ksize - k - 1];
566 const sum_type* row2 = rows[ksize + k + 1];
569 cast_copy(outbuf, output, w);
573 for(
int r = 0; r < ksize; r++)
575 const sum_type* middle_row = rows[ksize + r + 1];
577 for(
int k = 0; k < ksize; k++)
579 const sum_comp_type m = kernel[k];
580 const sum_type* row1 = rows[ksize + r - k];
581 const sum_type* row2 = rows[std::min(ksize + r + k + 2, swin)];
584 cast_copy(outbuf, output, w);
589 else if(i == swin - 1)
591 for(
int r = 0; r < ksize; r++)
593 const sum_type* middle_row = rows[r + 1];
595 for(
int k = 0; k < ksize; k++)
597 const sum_comp_type m = kernel[k];
598 const sum_type* row1 = rows[std::max(r - k - 1, 0) + 1];
599 const sum_type* row2 = rows[r + k + 2];
602 cast_copy(outbuf, output, w);
607 sum_type* tmp = rows[0];
608 for(
int r = 0; r < swin; r++)
609 rows[r] = rows[r + 1];
614 void compute_van_vliet_b(
double sigma,
double b[]);
615 void compute_triggs_M(
const double b[],
double M[][3]);
621 template <
class T,
class O,
class K>
625 const T* a = I.
data();
626 const int w = I.
size().x;
627 O* o = out.
data() + w + 1;
628 int total = I.totalsize() - 2 * w - 2;
629 const double cross = k1 * k2;
634 const double sum = k1 * (a[0] + a[2] + a[w * 2] + a[w * 2 + 2]) + cross * (a[1] + a[w * 2 + 1] + a[w] + a[w + 2]) + k2 * a[w + 1];
635 *o++ = Pixel::scalar_convert<O, T, double>(sum);
T gaussianKernel(std::vector< T > &k, T maxval, double stddev)
creates a Gaussian kernel with given maximum value and standard deviation.
Definition: convolution.h:28
All classes and functions are within the CVD namespace.
Definition: argb.h:6
Input images have incompatible dimensions.
Definition: convolution.h:127
ImageRef size() const
What is the size of this image?
Definition: image.h:557
void add_multiple_of_sum(const A *a, const A *b, const C &c, B *out, size_t count)
Compute pointwise (a_i + b_i) * c and add to out_i This is accelerated using SIMD for some platforms ...
Definition: utility.h:157
Base class for all Image_IO exceptions.
Definition: convolution.h:110
void convolveWithBox(const BasicImage< T > &I, BasicImage< T > &J, ImageRef hwin)
convolves an image with a box of given size.
Definition: convolution.h:141
Definition: convolution.h:380
void copy(const BasicImage< S > &in, BasicImage< T > &out, ImageRef size=ImageRef(-1, -1), ImageRef begin=ImageRef(), ImageRef dst=ImageRef())
Generic image copy function for copying sub rectangles of images into other images.
Definition: utility.h:30
Definition: convolution.h:355
ConstPointerType data() const
Returns the raw image data.
Definition: image.h:535
int x
The x co-ordinate.
Definition: image_ref.h:172
Base class for all CVD exceptions.
Definition: exceptions.h:15
Input images have incompatible dimensions.
Definition: convolution.h:117
Definition: image_ref.h:29
Definition: convolution.h:402
A generic image class to manage a block of arbitrarily padded data as an image.
Definition: image.h:273
int y
The y co-ordinate.
Definition: image_ref.h:173
A full image which manages its own data.
Definition: image.h:623
void assign_multiple(const A *a, const B &c, C *out, size_t count)
Compute pointwise a_i * c and store in out_i This is accelerated using SIMD for some platforms and da...
Definition: utility.h:167
Definition: builtin_components.h:38
T scaleKernel(const std::vector< S > &k, std::vector< T > &scaled, T maxval)
scales a GaussianKernel to a different maximum value.
Definition: convolution.h:54
void differences(const A *a, const A *b, B *diff, size_t count)
Compute pointwise differences (a_i - b_i) and store in diff_i This is accelerated using SIMD for some...
Definition: utility.h:147
Definition: pixel_traits.h:16
void zeroPixels(T *pixels, int count)
Set many pixels to the default value (typically 0) For multi-component pixels, this zeros all compone...
Definition: utility.h:105