數字圖像中實現縮放的方法有很多種,其中一種就是雙線性插值,在實現圖像縮放時,有兩種方法來確定縮放后的圖像的像素值,第一種是根據原圖像中的的像素找到對應的縮放后的圖像中的像素,第二種是根據縮放后的圖像找到對應的原圖像中的像素,如下圖
但是第一種方法有缺點,因為小圖中的像素點到大圖中的像素點不是滿射,因此大圖中的點不能完全有像素值,第二種方法也有缺點,大圖中的點逆映射為小圖中的點時,得到的像素坐標值可能不是整數,一種辦法是采用最近鄰方法,即將得到的坐標值與相鄰的原圖像中的像素坐標值比較,取離得最近的坐標值對應的像素值作為縮放后的圖像對應的坐標值的像素值,這種辦法可能導致圖像失真,因此采用雙線性差值的辦法來進行計算相應的像素值。
右側是最一般的雙線性插值,下面舉一個實際的例子來說明雙線性插值在圖像縮放中的應用。
假設一個圖像的大小是485x647,放大分別放大1.3倍和1.7倍,即485x1.3=630.5,647x1.7=1099.9,根據四舍五入的原則確定放大后的圖像為631x1100,接下來就是計算放大后圖像各個位置的像素值,例如計算放大后圖像位於(136,345)位置的像素值,則136/1.3=104.615,345/1.7=202.941,這里由於示例的原因取小數點后三位,則原圖像中相鄰的四個位置分別是(104,202),(104,203),(105,202),(105,203)這四個點,
如圖我畫出了這個點對應的周圍的四個點,203.941-203=0.941
所以f(R1)=(1-0.941)xf(104,203)+0.941xf(104,204),
f(R2)=(1-0.941)xf(105,203)+0.941xf(105,204),
104.615-104=0.615
所以f(P)=(1-0.615)xf(R1)+0.615xf(R2),
其中f表示的那一點的像素值,這樣就計算出了f(P),實際上就是放大后圖像(136,345)處對應的像素值。
下面還是先看Mat的存儲形式。Mat和Matlab里的數組格式有點像,但一般是二維向量,如果是灰度圖,一般存放<uchar>類型;如果是RGB彩色圖,存放<Vec3b>類型。


#include<iostream> #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> using namespace cv; using namespace std; int x, y; void scale(Mat &srcmat, Mat &desmat, double sx, double sy); int main(int argc ,char** argv){ Mat srcimg = imread("opencv.jpg", IMREAD_COLOR);// Read the file if (!srcimg.data) // Check for invalid input { cout << "Could not open or find the image" << std::endl; return -1; } double sx = 0, sy = 0; cout << "please input scale x and scale y" << endl; cin >> sx >> sy; namedWindow("source img",WINDOW_AUTOSIZE); imshow("source img", srcimg); y = int(srcimg.cols*sy), x = int(srcimg.rows*sx); Mat scaimg(x, y, CV_8UC3, Scalar::all(0)); scale(srcimg, scaimg, sx, sy); imshow("scaled img", scaimg); waitKey(); return 0; } void scale(Mat &srcmat, Mat &desmat, double sx, double sy){ int nc = x, nl = y,srccol=0,srcrow=0; double alph = 0.0, beta = 0.0; for (int i = 0; i < nc; i++){ uchar* desdata = desmat.ptr<uchar>(i); for (int j = 0; j < nl; j++){ srcrow = int(i / sx); //下面的的幾個if是判斷放大后圖像對應到原圖像的坐標是否越界的 if (srcrow >= srcmat.rows-1){ srcrow = srcmat.rows - 2; } alph = i / sx - srcrow; if (alph >= 1) alph = 1; srccol = int(j / sy); if (srccol >= srcmat.cols-1) srccol = srcmat.cols-2; beta = j / sy - srccol; if (beta >= 1) beta=1; for (int k = 0; k < 3; k++){ double kk=srcmat.at<Vec3b>(srcrow, srccol)[k] + beta*(srcmat.at<Vec3b>(srcrow, srccol+1)[k] - srcmat.at<Vec3b>(srcrow, srccol)[k]); double jj = srcmat.at<Vec3b>(srcrow+1, srccol)[k] + beta*(srcmat.at<Vec3b>(srcrow+1, srccol + 1)[k] - srcmat.at<Vec3b>(srcrow+1, srccol)[k]); desdata[j*3+k] = kk + alph*(jj - kk); } } } }
結果如下: