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

asked 2013-09-09 04:30:20 -0500

ShadowTS gravatar image

Hello, I'm trying to rewrite 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 or 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.

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;
        //printf("-- Pos & val %d %d \n", i, i_val);
    }
}

return dst;
}
edit retag flag offensive close merge delete