目錄
圖像內插
內插通常在圖像放大、縮小、旋轉和幾何校正等任務中使用。內插并用它來調整圖像的大小(縮小和放大),縮小和放大基本上采用圖像重取樣方法
最近鄰內插,這種方法將原圖像中最近鄰的灰度賦給了每個新位置,這種方法簡單,但會產生我們不想要的人為失真,如嚴重的直邊失真。更合適的方法是雙線性內插,它使用4個最近鄰的灰度來計算給定位置的灰度。令(x,y)(x, y)(x,y)表示待賦灰度值的位置(可將它相像為前面描述的網格點)的坐標,令v(x,y)v(x, y)v(x,y)表示灰度值。對于雙線性內插方法,所賦的值由如下公式得到:
v(x,y)=ax+by+cxy+d(2.17)v(x, y) = ax + by + cxy + d \tag{2.17} v(x,y)=ax+by+cxy+d(2.17)
4 個系數可由點(x, y)的4個最近鄰點寫出的4個未知方程求出。雙線性內插的結果要比最近鄰內插的結果好得多,但計算量會隨之增大。
def nearest_neighbor_interpolation(img
, new_h
, new_w
):"""get nearest_neighbor_interpolation for image, can up or down scale image into any ratioparam: img: input image, grady image, 1 channel, shape like [512, 512]param: new_h: new image height param: new_w: new image widthreturn a nearest_neighbor_interpolation up or down scale image"""new_img
= np
.zeros
([new_h
, new_w
])src_height
, src_width
= img
.shape
[:2]r
= new_h
/ src_heightl
= new_w
/ src_width
for i
in range(new_h
):for j
in range(new_w
):x0
= int(i
/ r
)y0
= int(j
/ l
)new_img
[i
, j
] = img
[x0
, y0
]return new_img
img
= cv2
.imread
('DIP_Figures/DIP3E_Original_Images_CH06/Fig0638(a)(lenna_RGB).tif', 0)img_up
= nearest_neighbor_interpolation
(img
, 1000, 1000)plt
.figure
(figsize
=(16, 8))
plt
.subplot
(121), plt
.imshow
(img
, 'gray')
plt
.subplot
(122), plt
.imshow
(img_up
, 'gray')
plt
.tight_layout
()
plt
.show
()
img
= cv2
.imread
('DIP_Figures/DIP3E_Original_Images_CH06/Fig0638(a)(lenna_RGB).tif', -1)
img
= img
[..., ::-1]
img_up_1
= nearest_neighbor_interpolation
(img
[..., 0], 800, 800)
img_up_2
= nearest_neighbor_interpolation
(img
[..., 1], 800, 800)
img_up_3
= nearest_neighbor_interpolation
(img
[..., 2], 800, 800)
img_up
= np
.uint8
(np
.dstack
((img_up_1
, img_up_2
, img_up_3
)))plt
.figure
(figsize
=(16, 8))
plt
.subplot
(121), plt
.imshow
(img
, 'gray')
plt
.subplot
(122), plt
.imshow
(img_up
, 'gray')
plt
.tight_layout
()
plt
.show
()
雙線性插值
又稱為雙線性內挺。在數學上,雙線性插值是有兩個變量的插值函數的線性插值擴展,其核心思想是在兩個方向分別進行一次線性插值。
假設我們想得到未知函數f在點P=(x,y)f在點 P=(x,y)f在點P=(x,y)的值,假設我們已知函數f在Q11=(x1,y1),Q12=(x1,y2),Q21=(x2,y1),Q22=(x2,y2)f在Q_{11} = (x_1, y_1),Q_{12}=(x_1, y_2), Q_{21} = (x_2, y_1),Q_{22} = (x_2, y_2)f在Q11?=(x1?,y1?),Q12?=(x1?,y2?),Q21?=(x2?,y1?),Q22?=(x2?,y2?)四個點的值。首先在x方向進行線性插值,得到:
f(R1)≈x2?xx2?x1f(Q11)+x?x1x2?x1f(Q21),whereR1=(x,y1)f(R_1) \approx \frac{x_2 - x}{x_2 - x_1} f(Q_{11}) + \frac{x-x_1}{x_2 - x_1} f(Q_{21}), where R_1 = (x, y_1) f(R1?)≈x2??x1?x2??x?f(Q11?)+x2??x1?x?x1??f(Q21?),whereR1?=(x,y1?)
f(R2)≈x2?xx2?x1f(Q12)+x?x1x2?x1f(Q22),whereR2=(x,y2)f(R_2) \approx \frac{x_2 - x}{x_2 - x_1} f(Q_{12}) + \frac{x-x_1}{x_2 - x_1} f(Q_{22}), where R_2 = (x, y_2) f(R2?)≈x2??x1?x2??x?f(Q12?)+x2??x1?x?x1??f(Q22?),whereR2?=(x,y2?)
然后在y方向進行線性插值,得到
f(P)≈y2?yy2?y1f(R1)+y?y1y2?y1f(R2)f(P) \approx \frac{y_2 - y}{y_2 - y_1} f(R_{1}) + \frac{y-y_1}{y_2 - y_1} f(R_{2})f(P)≈y2??y1?y2??y?f(R1?)+y2??y1?y?y1??f(R2?)
def bilinear_interpolation(img
, new_h
, new_w
):"""get nearest_neighbor_interpolation for image, can up or down scale image into any ratioparam: img: input image, grady image, 1 channel, shape like [512, 512]param: new_h: new image height param: new_w: new image widthreturn a nearest_neighbor_interpolation up or down scale image"""src_height
, src_width
= img
.shape
[:2]if new_h
== src_height
and new_w
== src_width
:return img
.copy
()new_img
= np
.zeros
([new_h
, new_w
])for i
in range(new_h
):for j
in range(new_w
):x
= (i
+0.5) * src_height
/ new_h
- 0.5y
= (j
+0.5) * src_width
/ new_w
- 0.5src_x0
= int(np
.floor
(x
))src_x1
= min(src_x0
+ 1 , src_height
- 1)src_y0
= int(np
.floor
(y
))src_y1
= min(src_y0
+ 1, src_width
- 1)temp0
= (src_x1
- x
) * img
[src_x0
, src_y0
] + (x
- src_x0
) * img
[src_x1
, src_y0
]temp1
= (src_x1
- x
) * img
[src_x0
, src_y1
] + (x
- src_x0
) * img
[src_x1
, src_y1
]new_img
[i
, j
] = int((src_y1
- y
) * temp0
+ (y
- src_y0
) * temp1
)return new_img
img
= cv2
.imread
('DIP_Figures/DIP3E_Original_Images_CH06/Fig0638(a)(lenna_RGB).tif', 0)img_up
= bilinear_interpolation
(img
, 800, 800)plt
.figure
(figsize
=(16, 8))
plt
.subplot
(121), plt
.imshow
(img
, 'gray')
plt
.subplot
(122), plt
.imshow
(img_up
, 'gray')
plt
.tight_layout
()
plt
.show
()
雙三次內插
雙三次插值的目的就是通過找到一種關系,或者說系數,可以把這16個像素對于P處像素值的影響因子找出來,從而根據這個影響因子來獲得目標圖像對應點的像素值,達到圖像縮放的目的。
Bicubic基函數形式如下:
W(x)={(a+2)∣x∣3?(a+3)∣x∣2+1,∣x∣≤1a∣x∣3?5a∣x∣2+8a∣x∣?4a,1<∣x∣<20,otherwiseW(x) =\begin{cases} (a+2) |x|^3 - (a+3)|x|^2 + 1, & |x| \leq 1 \\a|x|^3 -5a|x|^2 + 8a|x| -4a, & 1 < |x| < 2 \\ 0, & \text{otherwise}\end{cases} W(x)=??????(a+2)∣x∣3?(a+3)∣x∣2+1,a∣x∣3?5a∣x∣2+8a∣x∣?4a,0,?∣x∣≤11<∣x∣<2otherwise?
a=?1a=-1a=?1
注 a=?0.5a=-0.5a=?0.5才能完美的實現內插
插值計算公式:
∑i=03∑j=03aijxiyi\sum_{i=0}^3 \sum_{j=0}^3 a_{ij}x^iy^i i=0∑3?j=0∑3?aij?xiyi
def bicubic(x
):"""BiCubic primary fuction"""x
= abs(x
)a
= -0.5if x
<= 1:return (a
+ 2) * (x
**3) - (a
+ 3) * (x
**2) + 1elif x
< 2:return a
* (x
**3) - 5 * a
* (x
**2) + (8 * a
* x
) - (4 * a
)else:return 0
def bicubic_interpolation(img
, new_h
, new_w
):src_height
, src_width
= img
.shape
[:2]new_img
= np
.zeros
([new_h
, new_w
])for h
in range(new_h
):for w
in range(new_w
):src_x
= h
* (src_height
/ new_h
)src_y
= w
* (src_width
/ new_w
)x
= int(np
.floor
(src_x
))y
= int(np
.floor
(src_y
))u
= src_x
- xv
= src_y
- ytemp
= 0for i
in range(-1, 2):for j
in range(-1, 2):if x
+ i
< 0 or y
+ j
< 0 or x
+ i
>= src_height
or y
+ j
>= src_width
:continuetemp
+= img
[x
+i
, y
+j
] * bicubic
(i
- u
) * bicubic
(j
- v
)new_img
[h
, w
] = np
.clip
(temp
, 0, 255)return new_img
img
= cv2
.imread
('DIP_Figures/DIP3E_Original_Images_CH06/Fig0638(a)(lenna_RGB).tif', 0)img_up
= bicubic_interpolation
(img
, 800, 800)
plt
.figure
(figsize
=(16, 8))
plt
.subplot
(121), plt
.imshow
(img
, 'gray')
plt
.subplot
(122), plt
.imshow
(img_up
, 'gray')
plt
.tight_layout
()
plt
.show
()
img
= cv2
.imread
('DIP_Figures/DIP3E_Original_Images_CH02/Fig0220(a)(chronometer 3692x2812 2pt25 inch 1250 dpi).tif', 0)img
= img
[1100:3500, 200:2600]
img
= cv2
.resize
(img
, (200, 200), interpolation
=cv2
.INTER_CUBIC
)new_h
, new_w
= 2400, 2400
img_nearest
= nearest_neighbor_interpolation
(img
, new_h
, new_w
)
img_bilinear
= bilinear_interpolation
(img
, new_h
, new_w
)
img_bicubic
= bicubic_interpolation
(img
, new_h
, new_w
)plt
.figure
(figsize
=(18, 6))
plt
.subplot
(131), plt
.imshow
(img_nearest
, 'gray'), plt
.title
('Nearest'),
plt
.subplot
(132), plt
.imshow
(img_bilinear
, 'gray'), plt
.title
('Bilinear'),
plt
.subplot
(133), plt
.imshow
(img_bicubic
, 'gray'), plt
.title
('Bicubic'),
plt
.tight_layout
()
plt
.show
()
放大圖像
def up_sample_2d(img
):"""up sample 2d image, if your image is RGB, you could up sample each channel, then use np.dstack to merge a RGB imageparam: input img: it's a 2d gray imagereturn a 2x up sample image"""height
, width
= img
.shape
[:2]temp
= np
.zeros
([height
*2, width
*2])temp
[::2, ::2] = imgtemp
[1::2, 1::2] = imgtemp
[0::2, 1::2] = imgtemp
[1::2, 0::2] = img
return temp
img
= np
.random
.random
([12, 12])
up
= up_sample_2d
(img
)
down
= np
.zeros
([12, 12])
down
= up
[::2, ::2]
plt
.figure
(figsize
=(15, 5))
plt
.subplot
(1,3,1), plt
.imshow
(img
),
plt
.subplot
(1,3,2), plt
.imshow
(up
),
plt
.subplot
(1,3,3), plt
.imshow
(down
),
plt
.show
()
img_ori
= cv2
.imread
("DIP_Figures/DIP3E_Original_Images_CH06/Fig0638(a)(lenna_RGB).tif")
img_ori
= img_ori
[:, :, ::-1]temp
= []
for i
in range(img_ori
.shape
[-1]):temp
.append
(up_sample_2d
(img_ori
[:, :, i
]))
up1
= np
.uint8
(np
.dstack
(temp
))temp
= []
for i
in range(up1
.shape
[-1]):temp
.append
(up_sample_2d
(up1
[:, :, i
]))
up2
= np
.uint8
(np
.dstack
(temp
))plt
.figure
(figsize
=(21, 7))
plt
.subplot
(1,3,1), plt
.imshow
(img_ori
), plt
.title
("Original"),
plt
.subplot
(1,3,2), plt
.imshow
(up1
), plt
.title
("2X"),
plt
.subplot
(1,3,3), plt
.imshow
(up2
), plt
.title
("4X"),
plt
.tight_layout
()
plt
.show
()
總結
以上是生活随笔為你收集整理的第2章 Python 数字图像处理(DIP) --数字图像基础3 - 图像内插 - 最近邻内插 - 双线性插值 - 双三次内插 - 图像放大的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。