0

I am working on a C++ implement of Felzenszwalb segmentation algorithm and now I am in trouble with the Gaussian convolution. What I need is a convolution which keeps precision after decimal but so far, the program still seems to cut away numbers after points even if the Mat was converted to float. Here is my code:

#include <opencv2/opencv.hpp>
int main(int argc, char **argv)
{
  if (argc != 3) {
    std::cout << "Usage: ./a.out image sigma ..." << std::endl;
    return -1;
  } 
  double sigma = std::stod(argv[2]);
  cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR);
  cv::Mat f_image;
  cv::Mat f_filtered;
  image.convertTo(f_image, CV_32FC3);
  // cv::GaussianBlur(f_image, f_filtered, cv::Size(9, 9), sigma);
  cv::Mat kernel_1D = cv::getGaussianKernel(9, sigma);
  cv::sepFilter2D(f_image, f_filtered, -1, kernel_1D, kernel_1D);

  std::cout << f_filtered.type() << std::endl;
  for (int i = 0; i != f_filtered.rows; ++i) {
    for (int j = 0; j != f_filtered.cols; ++j) {
      std::cout << f_filtered.at<cv::Vec3b>(i, j) << std::endl;
    }
  }

My first try was use cv::GaussianBlur directly (which was commented out above), although the type of f_filtered was 21 (from this table it should be a 32 bit float) but the following loop output something like

21
...
[137, 231, 66]
[154, 231, 248]
[65, 10, 102]
[62, 65, 101]
[201, 228, 66]
[91, 136, 246]
[65, 119, 226]
[66, 65, 249]
[185, 229, 66]
[120, 233, 238]
[65, 137, 40]
[79, 65, 100]
[174, 234, 66]
[78, 194, 219]
[65, 136, 198]
[96, 65, 152]
[87, 245, 66]
[23, 101, 193]
...

And I do not really believe these are float numbers as there is not any decimal points. And after that I use cv::sepFilter2D with cv::getGaussianKernel but the result seems to be same. Another thing that convince me there are problems on data types as I have previously implemented this algorithm with Python. At that time I got into a quite similar trouble and I solved by converting data to float (img = img.astype(np.float)) before (img = cv2.filter2D(img, ddepth=-1, kernel=gaussain_kernel)). But this time type convert seems will not change result precision and I do not know what to do. So, any suggestions?

Page David
  • 1,309
  • 2
  • 14
  • 25
  • 1
    You using 3 channels in the Mat, try `f_filtered.at(i, j)[0]` in the cout for first channel. – seccpur Aug 12 '18 at 06:30
  • Indeed, without changing the part @seccpur mentioned you probably just get some random numbers because your program is reading now the wrong parts of the physical memory. – Barney Szabolcs Aug 12 '18 at 07:59
  • @BarnabasSzabolcs Sorry, I do not understand that very much. I have feed `f_filtered` into `sepFiltered2D` function as `dst`, why will it read wrong parts. – Page David Aug 12 '18 at 08:34
  • Hi, @seccpur, It suddenly struck me that I need to call later in the algorithm `cv::norm(_I(i, j), _I(i + 1, j))` where `_I` was defined by `cv::Mat_ _I = f_filtered;`. As there is no `[0]` behind, I wonder will this also cut away numbers after points? If that is the case, could you explain why this truncating take place? Thanks. – Page David Aug 12 '18 at 12:14
  • @PageDavid because a float number takes up more space in memory than a char number (usually four times as many bytes). Although this depends on your system, compiler and optimization settings. – Barney Szabolcs Aug 12 '18 at 19:36

1 Answers1

0

Hay David, Everything is OK with your code.

You just need to print our outcome with an appropriate type: std::cout << f_filtered.at<Vec3f >(i, j) << std::endl;

I would recommend you to use Image Watch plugin which shows you in debug time the image and all of its metadata (type, channels, etc).

Shmuel Fine
  • 351
  • 1
  • 5
  • Everything worked fine after I switch `cv::Mat_ _I = f_filtered;` to `cv::Mat_ _I = f_filtered;`. Thank you for your help and suggestion. – Page David Aug 12 '18 at 22:47