图像处理作业1-双线性插值实现图片放缩

在这里插入图片描述

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} P P 。其中四个红色点 Q Q 是原图的点,绿色点 P P 是目标图的像素点在原图上的投影!四个红色点 Q Q 就是投影点 P P 的四周最近的点。通过四个红色点 Q Q ,可以计算出投影点 P P 的像素值,这样目标图上的像素点的像素值也就得到了。

已知:
四个红色点 Q Q 的坐标值: h 0 h 1 w 0 w 1 h_0,h_1,w_0,w_1
四个红色点 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})
投影点 P P 的坐标值: h w h,w

目标图的点如何投影到原图上?

已知:

  1. 输入图的高和宽:height s r c , _{s r c}, width s r c _{s r c}
  2. 目标图的高和宽:height dst , _{\text {dst}}, width dst _{\text {dst}}

投影的公式是: h = h d s t g ( x ) h=h_{d s t} * \partial g(x) height s r c _{s r c} height 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}}

但是这个公式有一个问题,可能会导致目标图的中心跟原图的中心不对齐。例如:原图是3x3,中心点坐标(1, 1);目标图是9x9,中心点坐标(4, 4);通过上面的公式计算,目标图中心点在原图的投影坐标: h = 4 3 / 9 = 1.3333 1 h=4 * 3 / 9=1.3333 \neq 1 。之所以会出现中心点不对齐,原因是每个像素点实际上是一个边长为1的正方形,所以对于坐标为 ( h , w ) (h, w) ,的像素点,它的中心其实是 ( 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}}}

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}

转换一下得到正确的投影公式:

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

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

如何插值计算得到投影点的像素值?

已知:
四个红色点 Q Q 的坐标值: h 0 h 1 w 0 w 1 h_0,h_1,w_0,w_1
四个红色点 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})
投影点 P P 的坐标值: h w h,w
思路是:每个 Q Q 点的像素值乘以各自的权重,然后相加得到投影点 P P 像素值。 Q Q 点跟 P P 点的距离越近,它的权重就越大。
双线性插值给出的算法很是简单粗暴:先在横轴方向上进行两次线性插值计算,然后在纵轴方向上进行一次插值计算。结合最开始那个图例看,就是先求 R 0 R_0 R 1 R_1 这两个蓝色点的像素值,然后再通过这两个值,求得点 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 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 ( 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)
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)
= 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)

前面说了4个红色点 Q Q 是投影点 P P 四周最近的点,显然4个红色点彼此间的距离都是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) 再令 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

具体编程实现步骤

在这里插入图片描述

  1. 放大后图像的座标 ( x , y ) (x',y') 除以放大率 a a ,可以得到对应原图像的座标 ( x a , y a ) (\lfloor \frac{x'}{a}\rfloor , \lfloor \frac{y'}{a}\rfloor)

  2. 求原图像的座标 ( x a , y a ) (\lfloor \frac{x'}{a}\rfloor , \lfloor \frac{y'}{a}\rfloor) 周围 4 4 邻域的座标 I ( x , y ) I(x,y) I ( x + 1 , y ) I(x+1,y) I ( x , y + 1 ) I(x,y+1) I ( x + 1 , y + 1 ) I(x+1, y+1)

  3. 分别求这4个点与 ( x a , y a ) (\frac{x'}{a}, \frac{y'}{a}) 的距离,根据距离设置权重: w = d   d w = \frac{d}{\sum\ d}

  4. 根据下式求得放大后图像 ( 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)

输入与输出图像对比

输出(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):
	# 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]

	# cv.imshow需要将图片像素值转换为8位无符号数,否则无法正常显示
	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)
发布了24 篇原创文章 · 获赞 11 · 访问量 691

猜你喜欢

转载自blog.csdn.net/qq_42662568/article/details/105092913
今日推荐