设x0处的函数值为f(x0), x1处的函数值为f(x1), 设x0 < x < x1,对f(x)进行线性插值可得:
f(x) = f(x0)*(x1-x)/(x1-x0) + f(x1)*(x-x0)/(x1-x0)
实现代码:
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> #include <cmath> using namespace cv; using namespace std; #define PI 3.14159265 void MyScale(Mat& src, Mat& dst, float TransMat[3][3]); /** * @function main */ int main( int argc, char** argv ) { // load image char* imageName = "images/Lenna_256.png"; Mat image; image = imread(imageName,1); if(!image.data) { cout << "No image data" << endl; return -1; } // show image namedWindow("image", CV_WINDOW_AUTOSIZE); imshow("image", image); Mat dst; float transMat[3][3] = { {2.0, 0, 0}, {0, 2.0, 0}, {0, 0, 1} }; MyScale(image, dst, transMat); namedWindow("out_image", CV_WINDOW_AUTOSIZE); imshow("out_image", dst); //imwrite("Lenna_scale_bilinear.jpg", dst); waitKey(0); return 0; } void MyScale(Mat& src, Mat& dst, float TransMat[3][3]) { CV_Assert(src.data); CV_Assert(src.depth() != sizeof(uchar)); // calculate margin point of dst image float left = 0; float right = 0; float top = 0; float down = 0; float x = src.cols * 1.0f; float y = 0.0f; float u1 = x * TransMat[0][0] + y * TransMat[0][1]; float v1 = x * TransMat[1][0] + y * TransMat[1][1]; x = src.cols * 1.0f; y = src.rows * 1.0f; float u2 = x * TransMat[0][0] + y * TransMat[0][1]; float v2 = x * TransMat[1][0] + y * TransMat[1][1]; x = 0.0f; y = src.rows * 1.0f; float u3 = x * TransMat[0][0] + y * TransMat[0][1]; float v3 = x * TransMat[1][0] + y * TransMat[1][1]; left = min( min( min(0.0f,u1), u2 ), u3); right = max( max( max(0.0f,u1), u2 ), u3); top = min( min( min(0.0f,v1), v2 ), v3); down = max( max( max(0.0f,v1), v2 ), v3); // create dst image dst.create(int(abs(right-left)), int(abs(down-top)), src.type()); CV_Assert( dst.channels() == src.channels() ); int channels = dst.channels(); int i,j; uchar* p; uchar* q0; uchar* q1; for( i = 0; i < dst.rows; ++i) { p = dst.ptr<uchar>(i); for ( j = 0; j < dst.cols; ++j) { // x = (j+left)/TransMat[0][0] ; // NOTE: adverse rotation here!!! y = (i+top)/TransMat[1][1] ; int x0 = int(x); int y0 = int(y); int x1 = int(x) + 1; int y1 = int(y) + 1; if( (x0 >= 0) && (x0 < src.cols) && (y0 >= 0) && (y0 < src.rows) && (x1 >= 0) && (x1 < src.cols) && (y1 >= 0) && (y1 < src.rows) ) { q0 = src.ptr<uchar>(y0); q1 = src.ptr<uchar>(y1); switch(channels) { case 1: { //p[j] = q[x]; break; } case 3: { float b0 = q0[3*x0] ; float g0 = q0[3*x0+1]; float r0 = q0[3*x0+2]; float b1 = q0[3*x1] ; float g1 = q0[3*x1+1]; float r1 = q0[3*x1+2]; float b2 = q1[3*x0] ; float g2 = q1[3*x0+1]; float r2 = q1[3*x0+2]; float b3 = q1[3*x1] ; float g3 = q1[3*x1+1]; float r3 = q1[3*x1+2]; float b4 = b0 * (x1-x) / (x1-x0) + b1 * (x-x0) / (x1-x0); float g4 = g0 * (x1-x) / (x1-x0) + g1 * (x-x0) / (x1-x0); float r4 = r0 * (x1-x) / (x1-x0) + r1 * (x-x0) / (x1-x0); float b5 = b2 * (x1-x) / (x1-x0) + b3 * (x-x0) / (x1-x0); float g5 = g2 * (x1-x) / (x1-x0) + g3 * (x-x0) / (x1-x0); float r5 = r2 * (x1-x) / (x1-x0) + r3 * (x-x0) / (x1-x0); p[3*j] = b4 * (y1-y) / (y1-y0) + b5 * (y-y0) / (y1-y0); p[3*j+1] = g4 * (y1-y) / (y1-y0) + g5 * (y-y0) / (y1-y0); p[3*j+2] = r4 * (y1-y) / (y1-y0) + r5 * (y-y0) / (y1-y0); break; } } } } } }
图1为原图,图2为放大2倍的图像,直接对计算坐标取整;图3为放大二倍的图像,对坐标进行双线性插值。