雙線性插值作為opencv中預設使用的影象縮放演算法,其效果和速度都是不錯的。並且效果也比較穩定,計算複雜度並不算太高。我看了很多網上的演算法,自己也沒看太懂,下面是從網上找的雙線性插值 演算法的講解。
「影象的雙線性插值放大演算法中,目標影象中新創造的象素值,是由源影象位置在它附近的2*2區域4個鄰近象素的值通過加權平均計算得出的。雙線性內插值演算法放大後的影象質量較高,不會出現畫素值不連續的的情況。然而次演算法具有低通濾波器的性質,使高頻分量受損,所以可能會使影象輪廓在一定程度上變得模糊。」
下面還是根據我自己的理解來繼續講述吧,相信讀者中有很多高手,希望讀者能給予我指點一下,讓我也能更明白一些。
雙線性插值 演算法和最近鄰插值演算法比較類似。在最近鄰插值演算法中,目標影象中的某個點(x,y)是去源影象中找最鄰近的乙個點(x0, y0)即可。目標影象中的點(x, y)對應於源影象中的點(x0',y0'),x0'、y0'很可能不是整數,而是小數,而最近鄰插值演算法是找其鄰近整型值(int(x0'+0.5f),int(y0'+0.5f))(上篇文章中沒有進行四捨五入)。我們現在找x0', y0'所在位置旁邊的四個點,根據這四個點與(x0',y0')距離的關係計算目標影象中(x,y)一點的畫素值。演算法描述如下:
(1)計算源影象與目標影象寬與高的比例
w0 : 表示源影象的寬度
h0 : 表示源影象的高度
w1 : 表示目標影象的寬度
h1 : 表示目標影象的高度
float fw = float(w0-1)/(w1-1);
float fh = float(h0-1)/(h1-1);
(2)針對目標影象的乙個點(x, y),計算在源影象中的對應座標,結果為浮點數。
float x0 = x * fw;
float y0 = y * fh;
int x1 = int(x0);
int x2 = x1 + 1;
int y1 = int(y0);
int y2 = y1+1;
所求的源影象中的四個點座標為(x1, y1) (x1, y2) (x2, y1) (x2,y2)
(3)求周圍四個點所佔的權重比值
如上圖,
fx1 = x0 - x1;
fx2 = 1.0f - fx1;
fy1 = y0 - y1;
fy2 = 1.0f - fy1;
float s1 = fx1*fy1;
float s2 = fx2*fy1;
float s3 = fx2*fy2;
float s4 = fx1*fy2;
我們以value(座標)來代表取得此點的座標值,則:
value(x0,y0) = value(x2,y2)*s1+value(x1,y2)*s2+value(x1,y1)*s3+value(x2,y1)*s4;
如果 對上述運算不夠明白 的話,可以這樣來求。
我們先要求得(x0, y1) 和(x0,y2)的畫素值。
則float value(x0,y1) = value(x1,y1)*fx2 + value(x2,y1)*fx1;
float value(x0,y2) = value(x1,y2)*fx2 + value(x2,y2)*fx1;
注釋:離某點越近,離權重越大,故取其與1的差值。
float value(x0,y0) = value(x0,y1)*fy2 + value(x0,y2)*fy1;
驗證後與上邊公式一樣。
(4)求得值後填充到目標影象上就可以了。
為了能讓人更容易理解,咱還是使用getpixel和setpixel進行取值和賦值。
void resizelinear01(cimage& src, cimage& dst)}}測試程式仍是將670*503尺寸的縮放為200*160。經過測試,上邊的演算法執行一次就需要0.5秒左右,可以說是非常的慢。如果將其縮放成2000*1600大小的,一次就需要50秒。這是非常可怕的,假如現在我們做乙個類似photoshop的軟體,使用者想將其擴大若干倍,卻要等50秒,估計使用者已經沒有耐心使用您的軟體了。
我們來分析一下怎樣可以優化程式。在每一步優化演算法後,我們都再用上邊同樣的程式和步驟進行測試,觀察執行所用時間。
(1)改函式呼叫 為指標操作如第1節。(進行完此步後,程式只需要0.2秒左右,速度提高了250倍,哈哈!)
(2)將x0,y0座標的計算提取到 迴圈外,因為第二層迴圈裡的x座標每次迴圈都要重複一次,並且是重複的。(仍然是需要0.2秒左右。我們讓其迴圈一百次,再比較下所用時間。使用resizelinear02方法用時19.6秒,使用resizelinear02方法都是用時17.4秒,看來還是有作用的。)
下面是最終的**。
void resizelinear04(cimage& src, cimage& dst)for(int y=0; yint(y0);
y2 = int(y0+0.5f);
fy1 = y0-y1;
fy2 = 1.0f - fy1;
//trace(l"y=%6d; y0=%6.3f; y1=%6d; y2=%6d; fy1=%6.3f;\n", y, y0, y1, y2, fy1);
for(int x=0; x1.0f-fx1;
float s1 = fx2*fy2;
float s2 = fx1*fy2;
float s3 = fx1*fy1;
float s4 = fx2*fy1;
//trace(l"s1=%6.3f; s2=%6.3f; s3=%6.3f; s4=%6.3f; sum=%6.3f\n", s1,s2,s3,s4, s1+s2+s3+s4);
byte* p11 = psrc + pitch0*y1 + 3*x1;
byte* p12 = psrc + pitch0*y1 + 3*x2;
byte* p21 = psrc + pitch0*y2 + 3*x1;
byte* p22 = psrc + pitch0*y2 + 3*x2;
*p1 = byte((*p11)*s1 + (*p12)*s2 + (*p21)*s4 + (*p22)*s3); p1++; p11++; p12++; p21++; p22++;
*p1 = byte((*p11)*s1 + (*p12)*s2 + (*p21)*s4 + (*p22)*s3); p1++; p11++; p12++; p21++; p22++;
*p1 = byte((*p11)*s1 + (*p12)*s2 + (*p21)*s4 + (*p22)*s3); p1++;
}p1 = pdst + y*pitch1;
}delete arr_x1;
delete arr_x2;
delete arr_fx1;
}
雙線性插值
雙線性插值作為opencv中預設使用的影象縮放演算法,其效果和速度都是不錯的。並且效果也比較穩定,計算複雜度並不算太高。我看了很多網上的演算法,自己也沒看太懂,下面是從網上找的雙線性插值 演算法的講解。影象的雙線性插值放大演算法中,目標影象中新創造的象素值,是由源影象位置在它附近的2 2區域4個鄰近...
雙線性插值
轉至 雙線性插值,這個名字咋一聽很高大上的樣紙,再在維基百科上一查 見文末,我去,一堆的公式嚇死人 像俺這種半文盲,看到公式腦子就懵的型別,真心給跪。雖然看著好複雜,但仔細一看道理再簡單不過了,所以還是自己梳理一下好。雙線性插值,顧名思義就是兩個方向的線性插值加起來 這解釋過於簡單粗暴,哈哈 所以只...
雙線性插值
雙線性插值就是在x軸和y軸兩個方向上進行插入操作。假設a b兩個點,要在ab中間插入乙個點c c座標在ab連線上 就直接讓c的值落在ab的連線上即可。例如a點座標 0,0 值為3,b點座標 0,2 值為5,要對座標 0,1 的點c進行插值,就讓c落在ab上,值就為4。如果c點不在ab線上,如圖所示 ...