Wednesday, 9 October 2013

Subpixel accuracy--00 : what is subpixel?


    In the world of digital image, the smallest unit(information) you can get is pixel, it is impossible for you to access the information between pixels(sub-pixel).Fortunately, with some simple mathematical tricks, we can get over this problem.

Why sub-pixel matter?
 
    Because sometimes we need more accuracy than the original image can provide.

 ex :
  • Camera calibration(ex : measure homography matrix)
  • Stereo matching
  • Tracking(ex : SIFT use it to measure feature point)


How to find subpixel
graph_00(from wikepedia)

    A graph is worth a thousand words. With the help of bilinear interpolation, we could measure the subpixel at ease. Our target is the value of the pixel located at (20.2, 14.5).As you see, the coordinate of the target is fractional but not integer.

    Equation (1), (2) and (3) show you how to measure the value of the target. If you need more details, please check out the wiki.



Implement by codes


float get_sub_pix(cv::Mat const &img, cv::Point2f const &pt)
{
    int x = static_cast<int>(pt.x);
    int y = static_cast<int>(pt.y);

    int x0 = cv::borderInterpolate(x,   img.cols, cv::BORDER_REPLICATE);
    int x1 = cv::borderInterpolate(x+1, img.cols, cv::BORDER_REPLICATE);
    int y0 = cv::borderInterpolate(y,   img.rows, cv::BORDER_REPLICATE);
    int y1 = cv::borderInterpolate(y+1, img.rows, cv::BORDER_REPLICATE);

    float a = pt.x - x;
    float c = pt.y - y;

    float x1_interpolate = (img.at<uchar>(y0, x0) * (1.0 - a) 
                          + img.at<uchar>(y0, x1) * a);
    float x2_interpolate = (img.at<uchar>(y1, x0) * (1.0 - a) 
                         + img.at<uchar>(y1, x1) * a);
    float target = x1_interpolate * (1.0 - c) + x2_interpolate * c;

    return target;
}

There are more than one way to find the subpixel, this is only one of them.As usual, the codes can download from github.