Programming Assignment 1
Write a function “imresize” that gets the original image, original size, and target size as input and returns the output image at the target size using bilinear interpolation. Apply the imresize to one of the test images (256x256) to scale them to 1.5 and 0.75 (384x384 and 192x192 respectively).
提交報告內容包括實現原理,程序輸入與輸出圖像對比,結果分析,及代碼。編程語言不限。
實現原理:
首先,圖中有5個像素點:Q 00 , Q 01 , Q 10 , Q 11 Q_{00},Q_{01},Q_{10},Q_{11} Q 0 0 , Q 0 1 , Q 1 0 , Q 1 1 ,P P P 。其中四個紅色點Q Q Q 是原圖的點,綠色點P P P 是目標圖的像素點在原圖上的投影!四個紅色點Q Q Q 就是投影點P P P 的四周最近的點。通過四個紅色點Q Q Q ,可以計算出投影點P P P 的像素值,這樣目標圖上的像素點的像素值也就得到了。
已知:
四個紅色點Q Q Q 的座標值:h 0 , h 1 , w 0 , w 1 h_0,h_1,w_0,w_1 h 0 , h 1 , w 0 , w 1
四個紅色點Q Q Q 的像素值:f ( Q 00 ) , f ( Q 01 ) , f ( Q 10 ) , f ( Q 11 ) f(Q_{00}),f(Q_{01}),f(Q_{10}),f(Q_{11}) f ( Q 0 0 ) , f ( Q 0 1 ) , f ( Q 1 0 ) , f ( Q 1 1 )
投影點P P P 的座標值:h , w h,w h , w
目標圖的點如何投影到原圖上?
已知:
輸入圖的高和寬:height s r c , _{s r c}, s r c , width s r c _{s r c} s r c
目標圖的高和寬:height dst , _{\text {dst}}, dst , width dst _{\text {dst}} dst
投影的公式是:h = h d s t ∗ ∂ g ( x ) h=h_{d s t} * \partial g(x) h = h d s t ∗ ∂ g ( x ) height s r c _{s r c} s r c height d s t _{d s t} d s t
w = w d s t ∗ w i d t h s r c w i d t h d s t w=w_{d s t} * \frac{w i d t h_{s r c}}{w i d t h_{d s t}} w = w d s t ∗ w i d t h d s t w i d t h s r c
但是這個公式有一個問題,可能會導致目標圖的中心跟原圖的中心不對齊。例如:原圖是3x3,中心點座標(1, 1);目標圖是9x9,中心點座標(4, 4);通過上面的公式計算,目標圖中心點在原圖的投影座標:h = 4 ∗ 3 / 9 = 1.3333 ≠ 1 h=4 * 3 / 9=1.3333 \neq 1 h = 4 ∗ 3 / 9 = 1 . 3 3 3 3 = 1 。之所以會出現中心點不對齊,原因是每個像素點實際上是一個邊長爲1的正方形,所以對於座標爲( h , w ) (h, w) ( h , w ) ,的像素點,它的中心其實是( h + 0.5 , w + 0.5 ) (h+0.5, w+0.5) ( h + 0 . 5 , w + 0 . 5 ) 。所以精確計算應該是:h + 0.5 height src = h dst + 0.5 height dst \frac{h+0.5}{\text {height}_{\text {src}}}=\frac{h_{\text {dst}}+0.5}{\text {height}_{\text {dst}}} height src h + 0 . 5 = height dst h dst + 0 . 5
∂ g ( x ) w + 0.5 w i d t h s r c = ∂ g ( x ) w d s t + 0.5 w i d t h d s t \partial g(x) w+0.5 w i d t h_{s r c}=\partial g(x) w_{d s t}+0.5 w i d t h_{d s t} ∂ g ( x ) w + 0 . 5 w i d t h s r c = ∂ g ( x ) w d s t + 0 . 5 w i d t h d s t
轉換一下得到正確的投影公式:
h = ( h d s t + 0.5 ) ∗ h e i g h t s r c h e i g h t d s t − 0.5 h=\left(h_{d s t}+0.5\right) * \frac{h e i g h t_{s r c}}{h e i g h t_{d s t}}-0.5 h = ( h d s t + 0 . 5 ) ∗ h e i g h t d s t h e i g h t s r c − 0 . 5
w = ( w d s t + 0.5 ) ∗ w i d t h s r c w i d t h d s t − 0.5 w=\left(w_{d s t}+0.5\right) * \frac{w i d t h_{s r c}}{w i d t h_{d s t}}-0.5 w = ( w d s t + 0 . 5 ) ∗ w i d t h d s t w i d t h s r c − 0 . 5
如何插值計算得到投影點的像素值?
已知:
四個紅色點Q Q Q 的座標值:h 0 , h 1 , w 0 , w 1 h_0,h_1,w_0,w_1 h 0 , h 1 , w 0 , w 1
四個紅色點Q Q Q 的像素值:f ( Q 00 ) , f ( Q 01 ) , f ( Q 10 ) , f ( Q 11 ) f(Q_{00}),f(Q_{01}),f(Q_{10}),f(Q_{11}) f ( Q 0 0 ) , f ( Q 0 1 ) , f ( Q 1 0 ) , f ( Q 1 1 )
投影點P P P 的座標值:h , w h,w h , w
思路是:每個Q Q Q 點的像素值乘以各自的權重,然後相加得到投影點P P P 像素值。Q Q Q 點跟P P P 點的距離越近,它的權重就越大。
雙線性插值給出的算法很是簡單粗暴:先在橫軸方向上進行兩次線性插值計算,然後在縱軸方向上進行一次插值計算。結合最開始那個圖例看,就是先求R 0 R_0 R 0 和R 1 R_1 R 1 這兩個藍色點的像素值,然後再通過這兩個值,求得點P P P 的像素值。
具體計算如下:
f ( R 0 ) ≈ w 1 − w w 1 − w 0 f ( Q 00 ) + w − w 0 w 1 − w 0 f ( Q 01 ) f\left(R_{0}\right) \approx \frac{w_{1}-w}{w_{1}-w_{0}} f\left(Q_{00}\right)+\frac{w-w_{0}}{w_{1}-w_{0}} f\left(Q_{01}\right) f ( R 0 ) ≈ w 1 − w 0 w 1 − w f ( Q 0 0 ) + w 1 − w 0 w − w 0 f ( Q 0 1 )
f ( R 1 ) ≈ w 1 − w w 1 − w 0 f ( Q 10 ) + w − w 0 w 1 − w 0 f ( Q 11 ) f\left(R_{1}\right) \approx \frac{w_{1}-w}{w_{1}-w_{0}} f\left(Q_{10}\right)+\frac{w-w_{0}}{w_{1}-w_{0}} f\left(Q_{11}\right) f ( R 1 ) ≈ w 1 − w 0 w 1 − w f ( Q 1 0 ) + w 1 − w 0 w − w 0 f ( Q 1 1 )
f ( P ) ≈ h 1 − h h 1 − h 0 f ( R 0 ) + h − h 0 h 1 − h 0 f ( R 1 ) f(P) \approx \frac{h_{1}-h}{h_{1}-h_{0}} f\left(R_{0}\right)+\frac{h-h_{0}}{h_{1}-h_{0}} f\left(R_{1}\right) f ( P ) ≈ h 1 − h 0 h 1 − h f ( R 0 ) + h 1 − h 0 h − h 0 f ( R 1 )
≈ h 1 − h h 1 − h 0 ( w 1 − w w 1 − w 0 f ( Q 00 ) + w − w 0 w 1 − w 0 f ( Q 01 ) ) + h − h 0 h 1 − h 0 ( w 1 − w w 1 − w 0 f ( Q 10 ) + w − w 0 w 1 − w 0 f ( Q 11 ) ) \approx \frac{h_{1}-h}{h_{1}-h_{0}}\left(\frac{w_{1}-w}{w_{1}-w_{0}} f\left(Q_{00}\right)+\frac{w-w_{0}}{w_{1}-w_{0}} f\left(Q_{01}\right)\right)+\frac{h-h_{0}}{h_{1}-h_{0}}\left(\frac{w_{1}-w}{w_{1}-w_{0}} f\left(Q_{10}\right)+\frac{w-w_{0}}{w_{1}-w_{0}} f\left(Q_{11}\right)\right) ≈ h 1 − h 0 h 1 − h ( w 1 − w 0 w 1 − w f ( Q 0 0 ) + w 1 − w 0 w − w 0 f ( Q 0 1 ) ) + h 1 − h 0 h − h 0 ( w 1 − w 0 w 1 − w f ( Q 1 0 ) + w 1 − w 0 w − w 0 f ( Q 1 1 ) )
= 1 ( w 1 − w 0 ) ( h 1 − h 0 ) ( ( h 1 − h ) ( w 1 − w ) f ( Q 00 ) + ( h 1 − h ) ( w − w 0 ) f ( Q 01 ) + ( h − h 0 ) ( w 1 − w ) f ( Q 10 ) + ( h − h 0 ) ( w − w 0 ) f ( Q 11 ) ) =\frac{1}{\left(w_{1}-w_{0}\right)\left(h_{1}-h_{0}\right)}\left(\left(h_{1}-h\right)\left(w_{1}-w\right) f\left(Q_{00}\right)+\left(h_{1}-h\right)\left(w-w_{0}\right) f\left(Q_{01}\right)+\left(h-h_{0}\right)\left(w_{1}-w\right) f\left(Q_{10}\right)+\left(h-h_{0}\right)\left(w-w_{0}\right) f\left(Q_{11}\right)\right) = ( w 1 − w 0 ) ( h 1 − h 0 ) 1 ( ( h 1 − h ) ( w 1 − w ) f ( Q 0 0 ) + ( h 1 − h ) ( w − w 0 ) f ( Q 0 1 ) + ( h − h 0 ) ( w 1 − w ) f ( Q 1 0 ) + ( h − h 0 ) ( w − w 0 ) f ( Q 1 1 ) )
前面說了4個紅色點Q Q Q 是投影點P P P 四周最近的點,顯然4個紅色點彼此間的距離都是1,也即w 1 − w 0 = 1 , h 1 − h 0 = 1 w_1-w_0=1,h_1-h_0=1 w 1 − w 0 = 1 , h 1 − h 0 = 1 。因此上式可寫成f ( P ) ≈ ( h 1 − h ) ( w 1 − w ) f ( Q 00 ) + ( h 1 − h ) ( w − w 0 ) f ( Q 01 ) + ( h − h 0 ) ( w 1 − w ) f ( Q 10 ) + ( h − h 0 ) ( w − w 0 ) f ( Q 11 ) f(P) \approx\left(h_{1}-h\right)\left(w_{1}-w\right) f\left(Q_{00}\right)+\left(h_{1}-h\right)\left(w-w_{0}\right) f\left(Q_{01}\right)+\left(h-h_{0}\right)\left(w_{1}-w\right) f\left(Q_{10}\right)+\left(h-h_{0}\right)\left(w-w_{0}\right) f\left(Q_{11}\right) f ( P ) ≈ ( h 1 − h ) ( w 1 − w ) f ( Q 0 0 ) + ( h 1 − h ) ( w − w 0 ) f ( Q 0 1 ) + ( h − h 0 ) ( w 1 − w ) f ( Q 1 0 ) + ( h − h 0 ) ( w − w 0 ) f ( Q 1 1 ) 再令u = h − h 0 , v = w − w 0 u=h-h_0,v=w-w_0 u = h − h 0 , v = w − w 0 式子可進一步寫成:f ( P ) ≈ f ( Q 00 ) ( 1 − u ) ( 1 − v ) + f ( Q 01 ) ( 1 − u ) v + f ( Q 10 ) u ( 1 − v ) + f ( Q 11 ) u v f(P) \approx f\left(Q_{00}\right)(1-u)(1-v)+f\left(Q_{01}\right)(1-u) v+f\left(Q_{10}\right) u(1-v)+f\left(Q_{11}\right) u v f ( P ) ≈ f ( Q 0 0 ) ( 1 − u ) ( 1 − v ) + f ( Q 0 1 ) ( 1 − u ) v + f ( Q 1 0 ) u ( 1 − v ) + f ( Q 1 1 ) u v
具體編程實現步驟
放大後圖像的座標( x ′ , y ′ ) (x',y') ( x ′ , y ′ ) 除以放大率a a a ,可以得到對應原圖像的座標( ⌊ x ′ a ⌋ , ⌊ y ′ a ⌋ ) (\lfloor \frac{x'}{a}\rfloor , \lfloor \frac{y'}{a}\rfloor) ( ⌊ a x ′ ⌋ , ⌊ a y ′ ⌋ ) 。
求原圖像的座標( ⌊ x ′ a ⌋ , ⌊ y ′ a ⌋ ) (\lfloor \frac{x'}{a}\rfloor , \lfloor \frac{y'}{a}\rfloor) ( ⌊ a x ′ ⌋ , ⌊ a y ′ ⌋ ) 周圍4 4 4 鄰域的座標I ( x , y ) I(x,y) I ( x , y ) ,I ( x + 1 , y ) I(x+1,y) I ( x + 1 , y ) ,I ( x , y + 1 ) I(x,y+1) I ( x , y + 1 ) ,I ( x + 1 , y + 1 ) I(x+1, y+1) I ( x + 1 , y + 1 ) :
分別求這4個點與( x ′ a , y ′ a ) (\frac{x'}{a}, \frac{y'}{a}) ( a x ′ , a y ′ ) 的距離,根據距離設置權重:w = d ∑ d w = \frac{d}{\sum\ d} w = ∑ d d
根據下式求得放大後圖像( x ′ , y ′ ) (x',y') ( x ′ , y ′ ) 處的像素值:
d x = x ′ a − x d y = y ′ a − y I ′ ( x ′ , y ′ ) = ( 1 − d x ) ( 1 − d y ) I ( x , y ) + d x ( 1 − d y ) I ( x + 1 , y ) + ( 1 − d x ) d y I ( x , y + 1 ) + d x d y I ( x + 1 , y + 1 )
d_x = \frac{x'}{a} - x\\
d_y = \frac{y'}{a} - y\\
I'(x',y') = (1-d_x)\ (1-d_y)\ I(x,y) + d_x\ (1-d_y)\ I(x+1,y) + (1-d_x)\ d_y\ I(x,y+1) + d_x\ d_y\ I(x+1,y+1)
d x = a x ′ − x d y = a y ′ − y I ′ ( x ′ , y ′ ) = ( 1 − d x ) ( 1 − d y ) I ( x , y ) + d x ( 1 − d y ) I ( x + 1 , y ) + ( 1 − d x ) d y I ( x , y + 1 ) + d x d y I ( x + 1 , y + 1 )
輸入與輸出圖像對比
輸出(0.75倍)
輸入原始圖像
輸出(1.5倍)
輸出(0.75倍)
輸入原始圖像
輸出(1.5倍)
代碼
"""
AUTHOR: Tian YJ
CREATE: 2020-03-15
FUNCTION: Bi-Linear interpolation
"""
import cv2
import numpy as np
def imresize ( img, shape_s, shape_d) :
print ( "原始圖片大小:" , shape_s)
print ( "目標圖片大小:" , shape_d)
H_s, W_s = shape_s
H_d, W_d = shape_d
y = np. arange( H_d) . repeat( W_d) . reshape( W_d, - 1 )
x = y. T
y = ( ( y+ 0.5 ) / ( H_d / H_s) ) - 0.5
x = ( ( x+ 0.5 ) / ( W_d / W_s) ) - 0.5
x_int = np. floor( x) . astype( np. int )
y_int = np. floor( y) . astype( np. int )
x_int = np. minimum( x_int, W_s- 2 )
y_int = np. minimum( y_int, H_s- 2 )
dx = x - x_int
dy = y - y_int
dx = np. repeat( np. expand_dims( dx, axis= - 1 ) , 3 , axis= - 1 )
dy = np. repeat( np. expand_dims( dy, axis= - 1 ) , 3 , axis= - 1 )
out = ( 1 - dx) * ( 1 - dy) * img[ y_int, x_int] + dx * ( 1 - dy) * img[ y_int, x_int+ 1 ] + (
1 - dx) * dy * img[ y_int+ 1 , x_int] + dx * dy * img[ y_int + 1 , x_int+ 1 ]
out = out. astype( np. uint8)
return out
if __name__ == '__main__' :
ratio = str ( input ( "請輸入需要放大的倍數:" ) )
path_work = 'C:/Users/86187/Desktop/image_result/'
img_name = 'CARTOON'
file_in = path_work + str ( img_name) + '.jpg'
file_out = path_work + str ( img_name) + '_resize_' + ratio + '.jpg'
img = cv2. imread( file_in) . astype( np. float )
ratio = float ( ratio)
shape_s = ( img. shape[ 0 ] , img. shape[ 1 ] )
shape_d = ( int ( ratio* shape_s[ 0 ] ) , int ( ratio* shape_s[ 1 ] ) )
out = imresize( img, shape_s, shape_d)
cv2. imshow( "result" , out)
cv2. waitKey( 0 )
cv2. destroyAllWindows( )
cv2. imwrite( file_out, out)