一、最近邻插值原理
原理:根据缩放后的位置,最近邻的像素作为缩放后位置的像素
公式如下:
f
(
m
p
o
s
,
n
p
o
s
)
=
h
(
m
p
o
s
s
r
c
宽
d
s
t
宽
,
n
p
o
s
s
r
c
长
d
s
t
长
)
\begin{array}{c} f(m_{pos}, n_{pos}) = h(\frac{m_{pos}src_{宽}} {dst_{宽}}, \frac{n_{pos}src_{长}} {dst_{长}}) \end{array}
f(mpos,npos)=h(dst宽mpossrc宽,dst长npossrc长)
f() 为缩放后像素位置 对应原图的像素的位置
h() 为原图像的像素位置
可以分布化简:
原图片宽 / 缩放后图片的宽
宽
f
=
s
r
c
宽
/
d
s
t
宽
宽_{f} = src_{宽}/dst_{宽}
宽f=src宽/dst宽
原图片长 / 缩放后图片的长
长
f
=
s
r
c
长
/
d
s
t
长
长_{f} = src_{长}/dst_{长}
长f=src长/dst长
那么公式就变成
f
(
m
,
n
)
=
h
(
宽
f
∗
m
,
长
f
∗
n
)
f(m, n)=h(宽_{f} * m,长_{f} * n)
f(m,n)=h(宽f∗m,长f∗n)
在
numpy.array.shape
中 (m ,n ,z) m为行(y-宽 垂直方向), n为列(x-长 水平方向)
这有助于 后面用numpy去实现
例如:
将 3 * 3 数组 用近邻方法 转化成 4 * 4
宽
f
=
长
f
=
3
/
4
=
0.75
宽_{f}=长_{f}=3/4=0.75
宽f=长f=3/4=0.75
- 新图 第一个点(0,0)对应的像素位置
f ( 0 , 1 ) = h ( 0 ∗ 0.75 , 1 ∗ 0.75 ) = h ( 0 , 1 ) f(0,1) = h(0*0.75, 1 * 0.75) = h(0, 1) f(0,1)=h(0∗0.75,1∗0.75)=h(0,1) - 新图 最后个点(3,3)
f ( 3 , 3 ) = h ( 3 ∗ 0.75 , 3 ∗ 0.75 ) = h ( 2 , 2 ) f(3,3) = h(3*0.75, 3 * 0.75) = h(2, 2) f(3,3)=h(3∗0.75,3∗0.75)=h(2,2)
二、最近邻插值numpy实现
import numpy as np
def near_insert_1color(pic_dt, resize, x_scale=None, y_scale=None):
"""
最近邻插值(图片 m * n * 图层)
param pic_dt: 为一个图片的一个图层的数据 len(pic_dt) == 2
param resize: set (长, 宽)
param x_scale: float 长度缩放大小
param y_scale: float 宽带缩放大小
"""
m, n = pic_dt.shape
# 获取新的图像的大小
if resize is None:
n_new, m_new = np.round(x_scale * n).astype(int), np.round(y_scale * m).astype(int)
else:
n_new, m_new = resize
fx, fy = n / n_new, m / m_new # src_{长}/dst_{长}, src_{宽}/dst_{宽}
# 初始化X, Y的位置点
idx_x_orign = np.array(list(range(n_new)) * m_new).reshape(m_new, n_new)
idx_y_orign = np.repeat(list(range(m_new)), n_new).reshape(m_new, n_new)
# 需要的近邻的位置
x_indx = np.round(idx_x_orign * fx).astype(int)
y_indx = np.round(idx_y_orign * fy).astype(int)
return pic_dt[y_indx, x_indx]
def near_insert(pic_dt_, resize, fx=None, fy=None):
# 三个通道分开处理再合并
if len(pic_dt_.shape) == 3:
out_img0 = near_insert_1color(pic_dt_[:,:,0], resize=resize, x_scale=fx, y_scale=fy)
out_img1 = near_insert_1color(pic_dt_[:,:,1], resize=resize, x_scale=fx, y_scale=fy)
out_img2 = near_insert_1color(pic_dt_[:,:,2], resize=resize, x_scale=fx, y_scale=fy)
out_img_all = np.c_[out_img0[:,:,np.newaxis], out_img1[:,:,np.newaxis], out_img2[:,:,np.newaxis]]
else:
out_img_all = near_insert_1color(pic_dt_, resize=resize, x_scale=fx, y_scale=fy)
return out_img_all
2-1 对例子的3*3用near_insert_1color
实现
pic_3_3 = np.array([[56, 23, 15],
[65, 32, 78],
[12, 45, 62]])
pic_new = near_insert(pic_3_3, (4, 4))
"""
显然和想象的一样
>>> pic_new
array([[56, 23, 15, 15],
[65, 32, 78, 78],
[12, 45, 62, 62],
[12, 45, 62, 62]])
"""
三、openCV2实现
import cv2
"""
v2.resize(
src 【必需】原图像
dsize 【必需】输出图像所需大小 (长 , 宽) (shape[1], shape[0])
fx 【可选】沿水平轴的比例因子
fy 【可选】沿垂直轴的比例因子
interpolation 【可选】插值方式
)
cv.INTER_NEAREST 最近邻插值
cv.INTER_LINEAR 双线性插值
cv.INTER_CUBIC 基于4x4像素邻域的3次插值法
cv.INTER_AREA 基于局部像素的重采样
"""
# 读取图片
img = cv2.imread(pic_fil, cv2.IMREAD_UNCHANGED)
# cv2.resize 方法 放大1.5倍
resized1_5_img_near = cv2.resize(img
, dsize=None
, fx=1.5
, fy=1.5)
, interpolation=cv2.INTER_NEAREST)
# 用自己写的函数实现近邻插值
out_img_all = near_insert(img, resize=None, fx=1.5, fy=1.5)
四、实现比对
cv2.imshow('Origin', img)
cv2.imshow('near_insert*1.5', out_img_all)
cv2.imshow('Origin-[INTER_NEAREST] * 1.5', resized1_5_img_near)
cv2.waitKey(0)
-
原始图片
-
两种方式放大的图片(左边是numpy写的, 右边是cv的包)