1
votes

I'm trying to apply 8X8 separable mean filter on top of an image The filter is 2D separable.

I'm converting the following code from Matlab,

Kernel = ones(n);
% for conv 2 without zeropadding
LimgLarge = padarray(Limg,[n n],'circular');
LimgKer = conv2(LimgLarge,Kernel,'same')/(n^2);
LKerCorr = LimgKer(n+1:end-n,n+1:end-n);

1st I pad the image with the filter size, than correlate 2d, and finally crop the image region.

Now, I'm trying to implement the same thing in C++ using opencv

I have loaded the image, than called the following commands:

m_kernelSize = 8;   
m_kernelX = Mat::ones(m_kernelSize,1,CV_32FC1);
m_kernelX = m_kernelX / m_kernelSize;

m_kernelY = Mat::ones(1,m_kernelSize,CV_32FC1);
m_kernelY = m_kernelY / m_kernelSize;

sepFilter2D(m_logImage,m_filteredImage,m_logImage.depth(),m_kernelX,m_kernelY,Point(-1,-1),0,BORDER_REPLICATE);

I expected to receive the same results, but I'm still getting totally different results from Matlab.

I'd rather not to pad the image , do the correlation and finally crop the image again, I expected the same results using BORDER_REPLICATE argument.

Incidentally, I'm aware of copyMakeBorder function, but rather not use it, because sepFilter2D handles the regions by itself.

2
Could you upload the original image, matlab result and OpenCV result? - scap3y
Sure, but it would take me couple hours, you can use any dummy image instead - TripleS
Define "different results" - David Nilosek
Those are not a numerical differences, significantly algorithmic difference, I'll update the post shortly - TripleS

2 Answers

0
votes

Since you said you are only loading the image before the code snippet you showed, I can see two potential flaws.

First, if you do nothing between the loading of the source image and your code snippet, then your source image would be an 8-bit image and, since you set the function argument ddepth to m_logImage.depth(), you are also requesting a 8-bit destination image.

However, after reading the documentation of sepFilter2D, I am not sure that this is a valid combination of src.depth() and ddepth.

Can you try using the following line:

sepFilter2D(m_logImage,m_filteredImage,CV_32F,m_kernelX,m_kernelY,Point(-1,-1),0,BORDER_REPLICATE);

Second, check that you loaded your source image using the flag CV_LOAD_IMAGE_GRAYSCALE, so that it only has one channel and not three.

0
votes

I followed Matlab line by line, The mistake was somewhere else.

Anyways , The following two methods return the same results

Using a 8X8 filter

// Big filter mode - now used only for debug mode 
m_kernel = Mat::ones(m_kernelSize,m_kernelSize,type);
cv::Mat LimgLarge(m_logImage.rows + m_kernelSize*2, m_logImage.cols + m_kernelSize*2,m_logImage.depth());
cv::copyMakeBorder(m_logImage, LimgLarge, m_kernelSize, m_kernelSize,
    m_kernelSize, m_kernelSize, BORDER_REPLICATE);

// Big filter 
filter2D(LimgLarge,m_filteredImage,LimgLarge.depth(),m_kernel,Point(-1,-1),0,BORDER_CONSTANT );
m_filteredImage = m_filteredImage /  (m_kernelSize*m_kernelSize); 

cv::Rect roi(cv::Point(0+m_kernelSize,0+m_kernelSize),cv::Point(m_filteredImage.cols-m_kernelSize, m_filteredImage.rows-m_kernelSize));
cv::Mat croppedImage = m_filteredImage(roi);
m_diffImage = m_logImage - croppedImage;

Second method, using separable 8x8 filter

sepFilter2D(m_logImage,m_filteredImage,m_logImage.depth(),m_kernelX,m_kernelY,Point(-1,-1),0,BORDER_REPLICATE);

m_filteredImage = m_filteredImage / (m_kernelSize*m_kernelSize);