Replicate OpenCV resize with bilinar interpolation in C (shrink only)

5k views Asked by At

I'm trying to make a copy of the resizing algorithm of OpenCV with bilinear interpolation in C. What I want to achieve is that the resulting image is exactly the same (pixel value) to that produced by OpenCV. I am particularly interested in shrinking and not in the magnification, and I'm interested to use it on single channel Grayscale images. On the net I read that the bilinear interpolation algorithm is different between shrinkings and enlargements, but I did not find formulas for shrinking-implementations, so it is likely that the code I wrote is totally wrong. What I wrote comes from my knowledge of interpolation acquired in a university course in Computer Graphics and OpenGL. The result of the algorithm that I wrote are images visually identical to those produced by OpenCV but whose pixel values are not perfectly identical (in particular near edges). Can you show me the shrinking algorithm with bilinear interpolation and a possible implementation?

Note: The code attached is as a one-dimensional filter which must be applied first horizontally and then vertically (i.e. with transposed matrix).

Mat rescale(Mat src, float ratio){

    float width = src.cols * ratio; //resized width
    int i_width = cvRound(width);
    float step = (float)src.cols / (float)i_width; //size of new pixels mapped over old image
    float center = step / 2; //V1 - center position of new pixel
    //float center = step / src.cols; //V2 - other possible center position of new pixel
    //float center = 0.099f; //V3 - Lena 512x512 lower difference possible to OpenCV

    Mat dst(src.rows, i_width, CV_8UC1);

    //cycle through all rows
    for(int j = 0; j < src.rows; j++){
        //in each row compute new pixels
        for(int i = 0; i < i_width; i++){
            float pos = (i*step) + center; //position of (the center of) new pixel in old map coordinates
            int pred = floor(pos); //predecessor pixel in the original image
            int succ = ceil(pos); //successor pixel in the original image
            float d_pred = pos - pred; //pred and succ distances from the center of new pixel
            float d_succ = succ - pos;
            int val_pred = src.at<uchar>(j, pred); //pred and succ values
            int val_succ = src.at<uchar>(j, succ);

            float val = (val_pred * d_succ) + (val_succ * d_pred); //inverting d_succ and d_pred, supposing "d_succ = 1 - d_pred"...
            int i_val = cvRound(val);
            if(i_val == 0) //if pos is a perfect int "x.0000", pred and succ are the same pixel
                i_val = val_pred;
            dst.at<uchar>(j, i) = i_val;
        }
    }

    return dst;
}
1

There are 1 answers

0
Adi Shavit On

Bilinear interpolation is not separable in the sense that you can resize vertically and the resize again vertically. See example here.

You can see OpenCV's resize code here.