目录
图像内插
内插通常在图像放大、缩小、旋转和几何校正等任务中使用。内插并用它来调整图像的大小(缩小和放大),缩小和放大基本上采用图像重取样方法
最近邻内插,这种方法将原图像中最近邻的灰度赋给了每个新位置,这种方法简单,但会产生我们不想要的人为失真,如严重的直边失真。更合适的方法是双线性内插,它使用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−x1x2−xf(Q11)+x2−x1x−x1f(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−x1x2−xf(Q12)+x2−x1x−x1f(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−y1y2−yf(R1)+y2−y1y−y1f(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∑3j=0∑3aijxiyi
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 - 图像内插 - 最近邻内插 - 双线性插值 - 双三次内插 - 图像放大的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。