日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

双线性插值理论与代码实例

發(fā)布時間:2023/12/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 双线性插值理论与代码实例 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 雙線性插值

? ? ? 假設(shè)源圖像大小為mxn,目標(biāo)圖像為axb。那么兩幅圖像的邊長比分別為:m/a和n/b。注意,通常這個比例不是整數(shù),編程存儲的時候要用浮點型。目標(biāo)圖像的第(i,j)個像素點(i行j列)可以通過邊長比對應(yīng)回源圖像。其對應(yīng)坐標(biāo)為(i*m/a,j*n/b)。顯然,這個對應(yīng)坐標(biāo)一般來說不是整數(shù),而非整數(shù)的坐標(biāo)是無法在圖像這種離散數(shù)據(jù)上使用的。雙線性插值通過尋找距離這個對應(yīng)坐標(biāo)最近的四個像素點,來計算該點的值(灰度值或者RGB值)。

? 若圖像為灰度圖像,那么(i,j)點的灰度值的數(shù)學(xué)計算模型是:

f(x,y)=b1+b2x+b3y+b4xy

其中b1,b2,b3,b4是相關(guān)的系數(shù)。關(guān)于其的計算過程如下如下:

? ? ? 如圖,已知Q12,Q22,Q11,Q21,但是要插值的點為P點,這就要用雙線性插值了,首先在x軸方向上,對R1和R2兩個點進行插值,這個很簡單,然后根據(jù)R1和R2對P點進行插值,這就是所謂的雙線性插值。

?

? ? ? 雙線性插值,又稱為雙線性內(nèi)插。在數(shù)學(xué)上,雙線性插值是有兩個變量的插值函數(shù)的線性插值擴展,其核心思想是在兩個方向分別進行一次線性插值。

假如我們想得到未知函數(shù)??在點??的值,假設(shè)我們已知函數(shù)??在?,?,?, 及??四個點的值。

首先在?x?方向進行線性插值,得到

然后在?y?方向進行線性插值,得到

這樣就得到所要的結(jié)果?,

如果選擇一個坐標(biāo)系統(tǒng)使得??的四個已知點坐標(biāo)分別為 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化簡為

或者用矩陣運算表示為

與這種插值方法名稱不同的是,這種插值方法的結(jié)果通常不是線性的,它的形式是

{\displaystyle b_{1}+b_{2}x+b_{3}y+b_{4}xy.\,}

常數(shù)的數(shù)目都對應(yīng)于給定的?f?的數(shù)據(jù)點數(shù)目

{\displaystyle b_{1}=f(0,0)}
{\displaystyle b_{2}=f(1,0)-f(0,0)}
{\displaystyle b_{3}=f(0,1)-f(0,0)}
{\displaystyle b_{4}=f(1,1)-f(1,0)-f(0,1)+f(0,0)}

線性插值的結(jié)果與插值的順序無關(guān)。首先進行?y?方向的插值,然后進行?x?方向的插值,所得到的結(jié)果是一樣的。

2.存在的問題

這部分的前提是,你已經(jīng)明白什么是雙線性插值并且在給定源圖像和目標(biāo)圖像尺寸的情況下,可以用筆計算出目標(biāo)圖像某個像素點的值。當(dāng)然,最好的情況是你已經(jīng)用某種語言實現(xiàn)了網(wǎng)上一大堆博客上原創(chuàng)或轉(zhuǎn)載的雙線性插值算法,然后發(fā)現(xiàn)計算出來的結(jié)果和matlab、openCV對應(yīng)的resize()函數(shù)得到的結(jié)果完全不一樣。

那這個究竟是怎么回事呢?

其實答案很簡單,就是坐標(biāo)系的選擇問題,或者說源圖像和目標(biāo)圖像之間的對應(yīng)問題。

按照網(wǎng)上一些博客上寫的,源圖像和目標(biāo)圖像的原點(0,0)均選擇左上角,然后根據(jù)插值公式計算目標(biāo)圖像每點像素,假設(shè)你需要將一幅5x5的圖像縮小成3x3,那么源圖像和目標(biāo)圖像各個像素之間的對應(yīng)關(guān)系如下:

只畫了一行,用做示意,從圖中可以很明顯的看到,如果選擇右上角為原點(0,0),那么最右邊和最下邊的像素實際上并沒有參與計算,而且目標(biāo)圖像的每個像素點計算出的灰度值也相對于源圖像偏左偏上。

那么,讓坐標(biāo)加1或者選擇右下角為原點怎么樣呢?很不幸,還是一樣的效果,不過這次得到的圖像將偏右偏下。

最好的方法就是,兩個圖像的幾何中心重合,并且目標(biāo)圖像的每個像素之間都是等間隔的,并且都和兩邊有一定的邊距,這也是matlab和openCV的做法。如下圖:

如果你不懂我上面說的什么,沒關(guān)系,只要在計算對應(yīng)坐標(biāo)的時候改為以下公式即可,?

int x=(i+0.5)*m/a-0.5

int y=(j+0.5)*n/b-0.5?

instead of??

int x=i*m/a

int y=j*n/b?

利用上述公式,將得到正確的雙線性插值結(jié)果

總結(jié):

總結(jié)一下,我得到的教訓(xùn)有這么幾條。

1.網(wǎng)上的一些資料有的時候并不靠譜,自己還是要多做實驗。

2.不要小瞧一些簡單的、基本的算法,讓你寫你未必會寫,而且其中可能還藏著一些玄妙。

3.要多動手編程,多體會算法,多看大牛寫的源碼(雖然有的時候很吃力,但是要堅持看)。

源碼:

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是判斷放大后圖像對應(yīng)到原圖像的坐標(biāo)是否越界的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);}}} }//sx=1.2,sy=1.6

//圖像基本信息輸出int image_height = image.size().height;int image_width = image.size().width;cout << "Image Info: height:" << image_height << " width:" << image_width << endl;//===============================================================================================================================//圖像處理-----雙線性插值cout << "Please input the Sx and Sy:" << endl;float Sx, Sy;cin >> Sx >> Sy;cout << "Sx = " << Sx << "; Sy = " << Sy << ";" << endl;Mat final_img;int final_img_height, final_img_width;final_img_height = image.size().height * Sx;final_img_width = image.size().width * Sy;final_img.create(final_img_height, final_img_width, CV_8UC1);int y, x;int x1, x2, y1, y2;float temp1, temp2;for (y = 0; y < final_img_height; y++){for (x = 0; x < final_img_width; x++){x1 = (int)(x / Sx);x2 = x1 + 1;y1 = (int)(y / Sy);y2 = y1 + 1;//判斷邊界if (y2 >= image_height || x2 >= image_width){final_img.at<uchar>(y, x) = image.at<uchar>(y1, x1);continue;}temp1 = (x2 - x / Sx) * image.at<uchar>(y1, x1) + (x / Sx - x1) * image.at<uchar>(y1, x2);temp2 = (x2 - x / Sx) * image.at<uchar>(y2, x1) + (x / Sx - x1) * image.at<uchar>(y2, x2);final_img.at<uchar>(y, x) = (uchar)((y2 - y / Sy) * temp1 + (y / Sy - y1) * temp2);}}//===============================================================================================================================//顯示處理前后的圖像namedWindow("original_image");imshow("original_image", image);namedWindow("final_image");cout << "Final image Info: height:" << final_img.size().height << " width:" << final_img.size().width << endl;imshow("final_image", final_img); //sx=1.2,sy=1.2

總結(jié)

以上是生活随笔為你收集整理的双线性插值理论与代码实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。