2

Using the open CV's remap function with different types of source images has given me some interesting results.

The following types work as expected: CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1, CV_64FC1.

The two types that are giving me an error are: CV_8SC1, CV_32SC1.

The interesting part is that CV_16SC1 is working while CV_8SC1 is not.

Does anyone have any insights as why this is happening?

This is my code that I use:

cv::Mat remapX, remapY;
remapX.create(output_cv_mat.rows, output_cv_mat.cols, CV_32FC1);
remapY.create(output_cv_mat.rows, output_cv_mat.cols, CV_32FC1);

for(int x = 0; x < remapX.cols; x++) //Column iteration
{ 
    for(int y = 0; y < remapX.rows; y++) //Row iteration
    {                                   
        remapX.at<float>(y, x) = (float)(x);
        remapY.at<float>(y, x) = (float)(remapX.rows - y);
    }
}

cv::remap(source_cv_mat, output_cv_mat, remapX, remapY, cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));

The code uses source cv::Mat (the one who's types I am trying out) and output cv::Mat. I create the maps X and Y, use them in for loops and then finish with remap function.

The error I receive with these two types is:

terminate called after throwing an instance of 'cv::Exception' what(): OpenCV(4.0.1-dev) /home/aljaz/opencv_build/opencv/modules/imgproc/src/imgwarp.cpp:1805: error: (-215:Assertion failed) ifunc != 0 in function 'remap'

A. Cimet
  • 87
  • 7
  • 1
    Because those variants are not implemented. See [source code](https://github.com/opencv/opencv/blob/master/modules/imgproc/src/imgwarp.cpp#L1669). I don't know why they are not implemented, but you can convert you image to a broader type and use available implementations – Miki Mar 14 '19 at 08:13
  • The type of output is the same as the type of input (I set this when I create the ouput cv::Mat) – A. Cimet Mar 14 '19 at 08:14
  • 1
    yes, then do a narrow conversion to the original type – Miki Mar 14 '19 at 08:16

1 Answers1

2

If you look in the code of cv::remap, you can see the following check of compatible data types with interpolation types:

    static RemapNNFunc nn_tab[] =
    {
        remapNearest<uchar>, remapNearest<schar>, remapNearest<ushort>, remapNearest<short>,
        remapNearest<int>, remapNearest<float>, remapNearest<double>, 0
    };

    static RemapFunc linear_tab[] =
    {
        remapBilinear<FixedPtCast<int, uchar, INTER_REMAP_COEF_BITS>, RemapVec_8u, short>, 0,
        remapBilinear<Cast<float, ushort>, RemapNoVec, float>,
        remapBilinear<Cast<float, short>, RemapNoVec, float>, 0,
        remapBilinear<Cast<float, float>, RemapNoVec, float>,
        remapBilinear<Cast<double, double>, RemapNoVec, float>, 0
    };

So despite signed char type is allowed for nearest neighbor interpolation, it's not the case for the bilinear interpolation. All combinations are not implemented.

IPP (Intel library for image processing) which can be used with OpenCV does not allow signed char operation either: https://software.intel.com/en-us/ipp-dev-reference-remap. In my understanding, Intel does not provide such implementations when they don't make sense in terms of performance (i.e. they don't provide a function that convert 8s to 16s inside the function, compute something and convert back in 8s). Besides, supporting all combinations of data type, interpolation types, number of channels surely requires some work, so it's also fine to focus on the most used types.

If you don't have a performance bottleneck that absolutely requires to work with integers, I would recommend to convert to float. Also with integers you have to take care of the quantification.

When you get "assert" errors, it's usually because you didn't comply with the expected/implemented input data types or shapes (image size/number of channels).

Hope this helps!

87VN0
  • 775
  • 3
  • 10