5

I have the following MATLAB code which I want to transport into C++

Assume Gr is 2d matrix and 1/newscale == 0.5

Gr = imresize(Gr, 1 / newScale);

in the MATLAB documentation:

B = imresize(A, scale) returns image B that is scale times the size of A. The input image A can be a grayscale, RGB, or binary image. If scale is between 0 and 1.0, B is smaller than A. If scale is greater than 1.0, B is larger than A.

So this means I will get a 2D matrix == matrix_width/2 and matrix_height/2
How do I calculate the values? The default according to the docs are coming from cubic interpolation for nearest 4X4.

I can't find a sample code for C++ that does the same. Can you please provide a link to such code?

I also found this OpenCV function, resize.

Does it do the same as the MATLAB one?

chappjc
  • 30,359
  • 6
  • 75
  • 132
Gilad
  • 6,437
  • 14
  • 61
  • 119

2 Answers2

15

Yes, just be aware that MATLAB's imresize has anti-aliasing enabled by default:

imresize(A,scale,'bilinear')

vs. what you would get with cv::resize(), which does not have anti-aliasing:

imresize(A,scale,'bilinear','AntiAliasing',false)

And as Amro mentioned, the default in MATLAB is bicubic, so be sure to specify.

Bilinear

No code modifications are necessary to get matching results with bilinear interpolation.

Example OpenCV snippet:

cv::Mat src(4, 4, CV_32F);
for (int i = 0; i < 16; ++i)
    src.at<float>(i) = i;

std::cout << src << std::endl;

cv::Mat dst;
cv::resize(src, dst, Size(0, 0), 0.5, 0.5, INTER_LINEAR);

std::cout << dst << std::endl;

Output (OpenCV)

[0, 1, 2, 3;
  4, 5, 6, 7;
  8, 9, 10, 11;
  12, 13, 14, 15]

[2.5, 4.5;
  10.5, 12.5]

MATLAB

>> M = reshape(0:15,4,4).';
>> imresize(M,0.5,'bilinear','AntiAliasing',true)
ans =
                     3.125                     4.875
                    10.125                    11.875
>> imresize(M,0.5,'bilinear','AntiAliasing',false)
ans =
                       2.5                       4.5
                      10.5                      12.5

Note that the results are the same with anti-aliasing turned off.

Bicubic Difference

However, between 'bicubic' and INTER_CUBIC, the results are different on account of the weighting scheme! See here for details on the mathematical difference. The issue is in the interpolateCubic() function that computes the cubic interpolant's coefficients, where a constant of a = -0.75 is used rather than a = -0.5 like in MATLAB. However, if you edit imgwarp.cpp and change the code :

static inline void interpolateCubic( float x, float* coeffs )
{
    const float A = -0.75f;
    ...

to:

static inline void interpolateCubic( float x, float* coeffs )
{
    const float A = -0.50f;
    ...

and rebuild OpenCV (tip: disable CUDA and the gpu module for short compile time), then you get the same results:

MATLAB

>> imresize(M,0.5,'bicubic','AntiAliasing',false)
ans =
                    2.1875                    4.3125
                   10.6875                   12.8125

OpenCV

[0, 1, 2, 3;
  4, 5, 6, 7;
  8, 9, 10, 11;
  12, 13, 14, 15]
[2.1875, 4.3125;
  10.6875, 12.8125]

More about cubic HERE.

Community
  • 1
  • 1
chappjc
  • 30,359
  • 6
  • 75
  • 132
  • I need something bit exact so should i just try to implement it on my own ? – Gilad Nov 08 '14 at 00:58
  • @Gilad For bilinear, just use OpenCV. For bicubic, I guess you'll have to roll your own. – chappjc Nov 08 '14 at 00:59
  • the results in bicubic are not even close. can you suggest a place to start looking for c++ implmentation like matlab for that? – Gilad Nov 08 '14 at 01:27
  • 1
    This was one of my biggest gotchas when switching between OpenCV and MATLAB. Darn anti-aliasing! Your previous post saved me about a month ago. Thanks btw! – rayryeng Nov 08 '14 at 08:03
  • 1
    @rayryeng With cubic, modifications to imgwarp.cpp in OpenCV are necessary to get matching results. [Amro and I have been hammering away](http://stackoverflow.com/q/26823140/2778484) at the issue to our own amusement. :) – chappjc Nov 10 '14 at 19:05
  • @chappjc so I think all that is left for me is to decide what do i do now? change the opencv implementation which will suite me, or try to implement imresize.I might need the regular openCV for something else. although I might just copy some code from there. it is opensource after all.. – Gilad Nov 10 '14 at 21:52
  • 1
    @Gilad Yeah, open under the BSD license, which is extremely permissive. You can also grab cubic interpolation code from somewhere else and verify that it uses the same constant and the equations work out the same way. For example, you can change the equation in the paulinternet.nl implementation of `cubicInterpolate` you found to correspond the the correct coefficient. (that function combined the coeffs and the summation). – chappjc Nov 10 '14 at 22:52
  • @chappjc http://stackoverflow.com/questions/27851389/opencv-image-resize-comparison-to-matlab can you have a look here? – Gilad Jan 09 '15 at 00:53
3

In OpenCV, the call would be:

cv::Mat dst;
cv::resize(src, dst, Size(0,0), 0.5, 0.5, INTER_CUBIC);

You might then have to do some smoothing/blurring to emulate the anti-aliasing which MATLAB also performs by default (see @chappjc's answer)

Community
  • 1
  • 1
Amro
  • 123,847
  • 25
  • 243
  • 454
  • 1
    a related post about MATLAB's `imresize`: http://stackoverflow.com/a/7759981/97160 (also check out the linked posts) – Amro Nov 08 '14 at 00:47
  • 1
    I updated my post with an example using `bilinear`, but I'm not able to get identical results with `bicubic` regardless of the anti-aliasing setting. Do you know what's the deal with that? Wait... just saw [your link](http://stackoverflow.com/a/22093004/2778484). That explains it! – chappjc Nov 08 '14 at 00:49
  • @Amro can you have a look here please http://stackoverflow.com/questions/27851389/opencv-image-resize-comparison-to-matlab – Gilad Jan 09 '15 at 00:54