This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Separable Convolution

Tags: None
(comma "," separated)
hijokpayne
Registered Member
Posts
25
Karma
0

Separable Convolution

Tue Mar 17, 2015 5:44 am
Hi I wrote this small function for doing convolution (basically returns a valid convolved matrix)

Code: Select all
template<class Derived, class KernelDerived>
typename Derived::PlainObject convolve(const Eigen::MatrixBase<Derived>& image,
                                       const Eigen::MatrixBase<KernelDerived>& kernel) {
  static_assert(KernelDerived::SizeAtCompileTime != Eigen::Dynamic, "Only support fixed size kernels");
  static_assert(KernelDerived::RowsAtCompileTime % 2 != 0, "Only support Odd Sized Kernels");
  static_assert(KernelDerived::ColsAtCompileTime % 2 != 0, "Only support Odd Sized Kernels");
  assert(image.rows() > KernelDerived::RowsAtCompileTime);
  assert(image.cols() > KernelDerived::ColsAtCompileTime);
  typedef typename Derived::PlainObject OutputImageType;

  static const int KRows = KernelDerived::RowsAtCompileTime;
  static const int KCols = KernelDerived::ColsAtCompileTime;

  OutputImageType out(image.rows() - 2 * (KRows/2), image.cols() - 2 * (KCols/2));

  for (typename Derived::Index row = 0; row < out.rows(); ++row)
    for (typename Derived::Index col = 0; col < out.cols(); ++col) {
      out(row, col) = image.template block<KRows, KCols>(row, col).cwiseProduct(kernel).sum();
    }
  return out;
}


The results are valid at-least according to my tests. So for getting a gradient of an image using sobel filter i can now do the following:
Code: Select all
Eigen::Matrix3d sobel_kernel = (Eigen::Matrix3d() << -1, 0, 1, -2, 0, 2, -1, 0, 1).finished();
Eigen::MatrixXd deriv_x = convolve(image, sobel_x_kernel);


However I am obtaining an unexpected behavior while using doing convolution with a separable kernel.
As mentioned in the above articles, a sobel filter is separable (rank 1), so I should see a speedup if i do two 1D convolutions instead:
Code: Select all
Eigen::Vector3d sobel_x_v_kern(1, 2, 1);
Eigen::RowVector3d sobel_x_h_kern(-1, 0, 1);
Eigen::MatrixXd deriv_x = convolve(convolve(eigen_image, sobel_h_kern), sobel_v_kern);


But instead I see almost 2X slowdown compared to the previous single convolve call.. Is there something wrong with my function?
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS

Re: Separable Convolution

Tue Mar 17, 2015 9:38 am
Make sure you benchmarked with compiler optimization ON. Then my guess is that your application is memory bound and so you do not see the benefits of slightly fewer floating point operations but instead you see the cost of two passes on memory. Try on a small enough image so that it fits in L1 cache. If that helps, then you might process the big image block per block.


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Yahoo [Bot]