Wolfus
Wolfus

Reputation: 9

Use imfilter (matlab) in C++

i have a matlab code with an imfilter. Now i want to convert it to c++. I read this here But i can't implement the filterEngine with openCV3.3 (there is no filterEngine anymore).

That is the filter in matlab:

imfilter(im2double(image),k,'same','replicate');

That is my kernel k:

k = fspecial('disk',3)

The result of this line is a 7x7 matrix with values between 0 - 1.

So the filter gets an input image. This has values between 0 and 1 (im2double). So I have to convert my 8bit image to this range, I think it works like this:

cv::normalize(inImage,outImage,0,1,cv::NORM_MINMAX);

Then the image is filtered with the kernel. Finally I want to output an 8bit image again.

So I want to convert the two given Matlab lines to C++.

I read in the link that you cannot simply use filter2D. But how can i do that? has anybody an idea?

++++ Edit ++++ (testing Code snippet from zteffi)

I have tested the code. The result is a different one so far.

The structure of the kernel "disk" wis a bit different (more zeros). the values in it are also different than in Matlab.

Matlabkernel:

0   0.000280919186665314    0.0110250278796606  0.0171905962763014  0.0110250278796606  0.000280919186665314    0
0.000280919186665314    0.0245167426505023  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0245167426505023  0.000280919186665314
0.0110250278796606  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0110250278796606
0.0171905962763014  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0171905962763014
0.0110250278796606  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0110250278796606
0.000280919186665314    0.0245167426505023  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0245167426505023  0.000280919186665314
0   0.000280919186665314    0.0110250278796606  0.0171905962763014  0.0110250278796606  0.000280919186665314    0

c++ kernel:

[0, 0, 0, 0.0303030303030303, 0, 0, 0;
 0, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0;
 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303;
 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303;
 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303;
 0, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0;
 0, 0, 0, 0.0303030303030303, 0, 0, 0]

I don't know how the values are calculated in matlab.

The following line should be create a "circle" of values in tha matrix. But in the row dimension there are 3*2 zeros on the edge and in the column dimension 2 *2 zeros. But there should be only one zero in each corner.

Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(radius * 2 + 1, radius * 2 + 1));

Upvotes: 0

Views: 532

Answers (2)

Andrey  Smorodov
Andrey Smorodov

Reputation: 10850

You can see matlab's implemrntation of functions by clicking right mouse key on function name in editor and select "open 'function name' " item in menu. It will show matlab code for the function, and you can port it accurately to C++.

Upvotes: 0

zteffi
zteffi

Reputation: 670

Equivalent of fspecial('disk',3) would be cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(radius * 2 + 1, radius * 2 + 1)), divided by the sum of the kernel, so the total sum is equal to 1. So something like:

Mat m = cv::imread("lena.jpg");
int radius = 3;
Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(radius * 2 + 1, radius * 2 + 1));
double sum = cv::sum(cv::sum(kernel))[0]; // use cv::sum twice to get sum of all elements
kernel.convertTo(kernel, CV_64F, 1 / sum);
cv::filter2D(m, m, CV_64F, kernel);
m.convertTo(m, CV_8U);

You don't need to convert the image into <0, 1> range unless you need to display it. You also don't really need to convert it into double in this case and swap the last two lines for:

cv::filter2D(m, m, CV_8U, kernel);

Upvotes: 1

Related Questions