图像缩放示例
二维图像的缩放属于仿射变换或者透视变换的范畴,一般可以通过OpenCV的warpAffine()或者warpPerspective()函数实现。
出于兴趣,根据仿射变换公式自己简单写了一个函数实现图像的缩放,缩放中心设置为图像中心。
代码如下:
1 #include <iostream> 2 #include <string> 3 #include <opencv2/opencv.hpp> 4 5 using namespace std; 6 using namespace cv; 7 8 void zoomInAndOut(const float scale, const Mat srcImg, Mat &dstImg) 9 { 10 Mat M=Mat::eye(3,3,CV_32FC1); 11 int imgHeight=srcImg.rows; 12 int imgWidth=srcImg.cols; 13 14 uchar* pSrcData = (uchar*)srcImg.data; 15 uchar* pDstData = (uchar*)dstImg.data; 16 17 Point2f center(imgWidth / 2.0, imgHeight / 2.0); 18 //计算仿射矩阵 19 M.at<float>(0, 0) = scale; 20 M.at<float>(0, 2) = (1 - scale)*center.x; 21 M.at<float>(1, 1) = scale; 22 M.at<float>(1, 2) = (1 - scale)*center.y; 23 24 float a11 = M.at<float>(0, 0); 25 float a12 = M.at<float>(0, 1); 26 float a13 = M.at<float>(0, 2); 27 float a21 = M.at<float>(1, 0); 28 float a22 = M.at<float>(1, 1); 29 float a23 = M.at<float>(1, 2); 30 float a31 = M.at<float>(2, 0); 31 float a32 = M.at<float>(2, 1); 32 float a33 = M.at<float>(2, 2); 33 34 float bx = a11*a22 - a21*a12; 35 float by = a12*a21 - a11*a22; 36 if ( abs(bx) > 1e-3 && abs(by) > 1e-3) 37 { 38 bx = 1.0 / bx; 39 by = 1.0 / by; 40 float cx = a13*a22 - a23*a12; 41 float cy = a13*a21 - a23*a11; 42 43 for (int j =0; j < imgHeight; j++) 44 { 45 for (int i = 0; i < imgWidth; i++) 46 { 47 float u = (a22*i - a12*j - cx) *bx; 48 float v = (a21*i - a11*j - cy) *by; 49 50 int u0 = floor(u); 51 int v0 = floor(v); 52 int u1 = floor(u0 + 1); 53 int v1 = floor(v0 + 1); 54 if (u0 >= 0 && v0 >= 0 && u1 < imgWidth && v1 < imgHeight) 55 { 56 float dx = u - u0; 57 float dy = v - v0; 58 float weight1 = (1 - dx)*(1 - dy); 59 float weight2 = dx*(1 - dy); 60 float weight3 = (1 - dx)*dy; 61 float weight4 = dx*dy; 62 63 pDstData[j*imgWidth * 3 + i * 3 + 0] = weight1*pSrcData[v0*imgWidth * 3 + u0 * 3 + 0] + 64 weight2*pSrcData[v0*imgWidth * 3 + u1 * 3 + 0] + 65 weight3*pSrcData[v1*imgWidth * 3 + u0 * 3 + 0] + 66 weight4*pSrcData[v1*imgWidth * 3 + u1 * 3 + 0]; 67 pDstData[j*imgWidth * 3 + i * 3 + 1] = weight1*pSrcData[v0*imgWidth * 3 + u0 * 3 + 1] + 68 weight2*pSrcData[v0*imgWidth * 3 + u1 * 3 + 1] + 69 weight3*pSrcData[v1*imgWidth * 3 + u0 * 3 + 1] + 70 weight4*pSrcData[v1*imgWidth * 3 + u1 * 3 + 1]; 71 pDstData[j*imgWidth * 3 + i * 3 + 2] = weight1*pSrcData[v0*imgWidth * 3 + u0 * 3 + 2] + 72 weight2*pSrcData[v0*imgWidth * 3 + u1 * 3 + 2] + 73 weight3*pSrcData[v1*imgWidth * 3 + u0 * 3 + 2] + 74 weight4*pSrcData[v1*imgWidth * 3 + u1 * 3 + 2]; 75 } 76 else 77 { 78 pDstData[j*imgWidth * 3 + i * 3 + 0] =0; 79 pDstData[j*imgWidth * 3 + i * 3 + 1] =0; 80 pDstData[j*imgWidth * 3 + i * 3 + 2] =0; 81 } 82 83 } 84 } 85 } 86 } 87 88 void main() 89 { 90 string imgPath="data/source_images/"; 91 Mat srcImg = imread(imgPath+"moon.jpg"); 92 pyrDown(srcImg, srcImg); 93 pyrDown(srcImg, srcImg); 94 95 Mat dstImg = srcImg.clone(); 96 dstImg.setTo(0); 97 98 namedWindow("showImg"); 99 imshow("showImg", srcImg); 100 waitKey(10); 101 102 float scale = 0; 103 while (scale <= 2) 104 { 105 scale += 0.1; 106 zoomInAndOut(scale, srcImg, dstImg); 107 108 imshow("showImg", dstImg); 109 waitKey(10); 110 } 111 112 }
代码中采用反向映射方法,使用用双线性插值技术得到目标图像像素值
---------------------------------
业精于勤而荒于嬉 行成于思而毁于随
---------------------------------