task1图像插值算法

Datawhale 计算机视觉基础-图像处理(上)-Task01 OpenCV框架与图像插值算法

1.1 简介

  在图像处理中,平移变换、旋转变换以及放缩变换是一些基础且常用的操作。这些几何变换并不改变图象的象素值,只是在图象平面上进行象素的重新排列。在一幅输入图象 [ u , v ] [u,v] [uv]中,灰度值仅在整数位置上有定义。然而,输出图象[x,y]的灰度值一般由处在非整数坐标上的 ( u , v ) (u,v) uv值来决定。这就需要插值算法来进行处理,常见的插值算法有最近邻插值、双线性插值和三次样条插值。

1.2 学习目标

  • 了解插值算法与常见几何变换之间的关系
  • 理解插值算法的原理
  • 掌握OpenCV框架下插值算法API的使用

1.3 内容介绍

  1. 插值算法原理介绍
    • 最近邻插值算法
    • 双线性插值算法
  2. OpenCV代码实践
    • cv.resize()各项参数及含义
  3. 动手实现(由读者自己完成)

1.4 算法理论介绍与推荐

1.4.1 最近邻插值算法原理

  最近邻插值,是指将目标图像中的点,对应到源图像中后,找到最相邻的整数点,作为插值后的输出。

  如上图所示,目标图像中的某点投影到原图像中的位置为点P,此时易知, f ( P ) = f ( Q 11 ) f(P) = f(Q11) f(P)=f(Q11).

一个例子:

  如下图所示,将一幅3X3的图像放大到4X4,用 f ( x , y ) f(x, y) f(x,y)表示目标图像, h ( x , y ) h(x, y) h(x,y)表示原图像,我们有如下公式:

f ( d s t X , d s t Y ) = h ( d s t X s r c W i d t h d s t W i d t h , d s t Y s r c H e i g h t d s t H e i g h t ) \begin{array}{c} f(dst_{X}, dst_{Y}) = h(\frac{dst_{X}src_{Width}} {dst_{Width}}, \frac{dst_{Y}src_{Height}} {dst_{Height}}) \end{array} f(dstX,dstY)=h(dstWidthdstXsrcWidth,dstHeightdstYsrcHeight)

f ( 0 , 0 ) = h ( 0 , 0 ) f ( 0 , 1 ) = h ( 0 , 0.75 ) = h ( 0 , 1 ) f ( 0 , 2 ) = h ( 0 , 1.50 ) = h ( 0 , 2 ) f ( 0 , 3 ) = h ( 0 , 2.25 ) = h ( 0 , 2 ) . . . \begin{array}{c} f(0,0)=h(0,0) \\ f(0,1)=h(0,0.75)=h(0,1) \\ f(0,2)=h(0,1.50)=h(0,2) \\ f(0,3)=h(0,2.25)=h(0,2) \\ ...\\ \end{array} f(0,0)=h(0,0)f(0,1)=h(0,0.75)=h(0,1)f(0,2)=h(0,1.50)=h(0,2)f(0,3)=h(0,2.25)=h(0,2)...

缺点:
用该方法作放大处理时,在图象中可能出现明显的块状效应

import cv2
import numpy as np
arr=np.random.randint(255,size=(500,500),dtype=np.uint8)
amplifier=cv2.resize(arr,dsize=None,fx=2,fy=2,interpolation=cv2.INTER_NEAREST)
minimise=cv2.resize(amplifier,dsize=None,fx=0.5,fy=0.5,interpolation=cv2.INTER_NEAREST)
print((minimise==arr).sum())

1.4.2 双线性插值

  在讲双线性插值之前先看以一下线性插值,线性插值多项式为:

f ( x ) = a 1 x + a 0 f(x)=a_{1} x+a_{0} f(x)=a1x+a0

y = y 0 + ( x − x 0 ) y 1 − y 0 x 1 − x 0 = y 0 + ( x − x 0 ) y 1 − ( x − x 0 ) y 0 x 1 − x 0 y=y_{0}+\left(x-x_{0}\right) \frac{y_{1}-y_{0}}{x_{1}-x_{0}}=y_{0}+\frac{\left(x-x_{0}\right) y_{1}-\left(x-x_{0}\right) y_{0}}{x_{1}-x_{0}} y=y0+(xx0)x1x0y1y0=y0+x1x0(xx0)y1(xx0)y0

  双线性插值就是线性插值在二维时的推广,在两个方向上做三次线性插值,具体操作如下图所示:

  令 f ( x , y ) f(x,y) f(xy)为两个变量的函数,其在单位正方形顶点的值已知。假设我们希望通过插值得到正方形内任意点的函数值。则可由双线性方程:
f ( x , y ) = a x + b y + c x y + d f(x, y)=a x+b y+c x y+d f(x,y)=ax+by+cxy+d

  来定义的一个双曲抛物面与四个已知点拟合。

  首先对上端的两个顶点进行线性插值得:

f ( x , 0 ) = f ( 0 , 0 ) + x [ f ( 1 , 0 ) − f ( 0 , 0 ) ] f(x, 0)=f(0,0)+x[f(1,0)-f(0,0)] f(x,0)=f(0,0)+x[f(1,0)f(0,0)]

  类似地,再对底端的两个顶点进行线性插值有:
f ( x , 1 ) = f ( 0 , 1 ) + x [ f ( 1 , 1 ) − f ( 0 , 1 ) ] f(x, 1)=f(0,1)+x[f(1,1)-f(0,1)] f(x,1)=f(0,1)+x[f(1,1)f(0,1)]

  最后,做垂直方向的线性插值,以确定:

f ( x , y ) = f ( x , 0 ) + y [ f ( x , 1 ) − f ( x , 0 ) ] f(x, y)=f(x, 0)+y[f(x, 1)-f(x, 0)] f(x,y)=f(x,0)+y[f(x,1)f(x,0)]

  整理得:

f ( x , y ) = [ f ( 1 , 0 ) − f ( 0 , 0 ) ] x + [ f ( 0 , 1 ) − f ( 0 , 0 ) ] y + [ f ( 1 , 1 ) + f ( 0 , 0 ) − f ( 0 , 1 ) − f ( 1 , 0 ) ] x y + f ( 0 , 0 ) \begin{array}{l} f(x, y)=[f(1,0)-f(0,0)] x+[f(0,1)-f(0,0)] y \\ +[f(1,1)+f(0,0)-f(0,1)-f(1,0)] x y+f(0,0) \end{array} f(x,y)=[f(1,0)f(0,0)]x+[f(0,1)f(0,0)]y+[f(1,1)+f(0,0)f(0,1)f(1,0)]xy+f(0,0)

1.4.3 三次样条插值

  给定 n + 1 n+1 n+1个点, a = x 0 < x 1 < . . . < x n = b a=x_{0}<x_{1}<...<x_{n}=b a=x0<x1<...<xn=b,以及他们的函数值 f ( x i ) , i = 0 , 1 , 2 , . . . n f(x_{i}),i=0,1,2,...n f(xi),i=0,1,2,...n,在每个区间 [ x i , x i + 1 ] [x_{i},x_{i+1}] [xi,xi+1]上,确定一个三次多项式:
S i ( x ) = a i + b i ( x − x i ) + c i ( x − x i ) 2 + d i ( x − x i ) 3 , i = 0 , 1 , . . . n − 1 S_{i}(x)=a_{i}+b_{i}(x-x_{i})+c_{i}(x-x_{i})^2+d_{i}(x-x_{i})^3,i=0,1,...n-1 Si(x)=ai+bi(xxi)+ci(xxi)2+di(xxi)3i=0,1,...n1
  每个三次多项式中有四个未知参数,有 n n n个区间, n n n个多项式,共 4 n 4n 4n个未知参数。我们知道“ n n n个未知数需要 n n n个已知条件确定唯一解”,所以要确定这 4 n 4n 4n个未知参数,共需要 4 n 4n 4n个已知条件。

  每个三次多项式满足如下条件:

  • S i S_{i} Si二阶可导,且 S i S_{i} Si S i ′ S_{i}^{'} Si S i ′ ′ S_{i}^{''} Si在区间 [ a , b ] [a,b] [a,b]内连续
  • S i ( x i ) = y i S_{i}(x_{i})=y_{i} Si(xi)=yi S i ( x i + 1 ) = y i + 1 S_{i}(x_{i+1})=y_{i+1} Si(xi+1)=yi+1 i = 0 , 1 , . . . n − 1 i=0,1,...n-1 i=0,1,...n1(共 n + 1 n+1 n+1个条件)
  • S i ( x i + 1 ) = S i + 1 ( x i + 1 ) S_{i}(x_{i+1})=S_{i+1}(x_{i+1}) Si(xi+1)=Si+1(xi+1) i = 0 , 1 , . . . n − 2 i=0,1,...n-2 i=0,1,...n2(共 n − 1 n-1 n1个条件)
  • S i ′ ( x i + 1 ) = S i + 1 ′ ( x i + 1 ) S_{i}^{'}(x_{i+1})=S_{i+1}^{'}(x_{i+1}) Si(xi+1)=Si+1(xi+1) i = 0 , 1 , . . . n − 2 i=0,1,...n-2 i=0,1,...n2(共 n − 1 n-1 n1个条件)
  • S i ′ ′ ( x i + 1 ) = S i + 1 ′ ′ ( x i + 1 ) S_{i}^{''}(x_{i+1})=S_{i+1}^{''}(x_{i+1}) Si(xi+1)=Si+1(xi+1) i = 0 , 1 , . . . n − 2 i=0,1,...n-2 i=0,1,...n2(共 n − 1 n-1 n1个条件)

  以上共 4 n − 2 4n-2 4n2个条件,还差2个条件,由如下三种边界条件确定:

  • 给定端点处一阶导数值: S 0 ′ ( x 0 ) = y 0 ′ , S n − 1 ′ ( x n ) = y n ′ S_{0}^{'}(x_{0})=y_{0}^{'},S_{n-1}^{'}(x_{n})=y_{n}^{'} S0(x0)=y0Sn1(xn)=yn,称为固定边界条件

  • 给定端点处二阶导数值: S 0 ′ ′ ( x 0 ) = y 0 ′ ′ , S n − 1 ′ ′ ( x n ) = y n ′ ′ S_{0}^{''}(x_{0})=y_{0}^{''},S_{n-1}^{''}(x_{n})=y_{n}^{''} S0(x0)=y0Sn1(xn)=yn,特别地, y 0 ′ ′ = y n ′ ′ = 0 y_{0}^{''}=y_{n}^{''}=0 y0=yn=0,称为自然边界条件

  • 周期性条件: S 0 ( x 0 − 0 ) = S n − 1 ( x n + 0 ) S_{0}(x_{0}-0)=S_{n-1}(x_{n}+0) S0(x00)=Sn1(xn+0) S 0 ′ ( x 0 − 0 ) = S n − 1 ′ ( x n + 0 ) S_{0}^{'}(x_{0}-0)=S_{n-1}^{'}(x_{n}+0) S0(x00)=Sn1(xn+0)
           S 0 ′ ′ ( x 0 − 0 ) = S n − 1 ′ ′ ( x n + 0 ) S_{0}^{''}(x_{0}-0)=S_{n-1}^{''}(x_{n}+0) S0(x00)=Sn1(xn+0)

   4 n 4n 4n个条件有了,就可以确定每个区间上的三次多项式。

  对于每个区间内的点,就可以用 S i ( x ) S_{i}(x) Si(x)得到插值结果。三次样条插值具有良好的收敛性,稳定性和光滑性,优点明显,是非常重要的插值工具。

  这里主要了解三次样条插值的作用,具体的推导过程比较繁琐,想了解的可以查阅资料。

源图像和目标图像几何中心的对齐。

源图像和目标图像几何中心的对齐

方法:在计算源图像的虚拟浮点坐标的时候,一般情况:

srcX=dstX* (srcWidth/dstWidth) ,
  srcY = dstY * (srcHeight/dstHeight)
  中心对齐(OpenCV也是如此):
  SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5
  SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5
  原理:
双线性插值算法及需要注意事项这篇博客解释说“如果选择右上角为原点(0,0),那么最右边和最下边的像素实际上并没有参与计算,而且目标图像的每个像 素点计算出的灰度值也相对于源图像偏左偏上。”我有点保持疑问。
  将公式变形:

srcX=dstX* (srcWidth/dstWidth)+0.5*(srcWidth/dstWidth-1)
  相当于我们在原始的浮点坐标上加上了0.5*(srcWidth/dstWidth-1)这样一个控制因子,这项的符号可正可负,与srcWidth/dstWidth的比值也就是当前插值是扩大还是缩小图像有关,有什么作用呢?看一个例子:假设源图像是33,中心点坐标(1,1)目标图像是99,中心点坐标(4,4),我们在进行插值映射的时候,尽可能希望均匀的用到源图像的像素信息,最直观的就是(4,4)映射到(1,1)现在直接计算srcX=4*3/9=1.3333!=1,也就是我们在插值的时候所利用的像素集中在图像的右下方,而不是均匀分布整个图像。现在考虑中心点对齐,srcX=(4+0.5)*3/9-0.5=1,刚好满足我们的要求。

将浮点运算转换成整数运算

将浮点运算转换成整数运算

参考图像处理界双线性插值算法的优化
  直接进行计算的话,由于计算的srcX和srcY 都是浮点数,后续会进行大量的乘法,而图像数据量又大,速度不会理想,解决思路是:
  浮点运算→→整数运算→→”<<左右移按位运算”。
  放大的主要对象是u,v这些浮点数,OpenCV选择的放大倍数是2048“如何取这个合适的放大倍数呢,要从三个方面考虑,
  第一:精度问题,如果这个数取得过小,那么经过计算后可能会导致结果出现较大的误差。
  第二,这个数不能太大,太大会导致计算过程超过长整形所能表达的范围。
  第三:速度考虑。假如放大倍数取为12,那么算式在最后的结果中应该需要除以1212=144,但是如果取为16,则最后的除数为1616=256,这个数字好,我们可以用右移来实现,而右移要比普通的整除快多了。”我们利用左移11位操作就可以达到放大目的。

1.4.3 映射方法

向前映射法

  可以将几何运算想象成一次一个象素地转移到输出图象中。如果一个输入象素被映射到四个输出象素之间的位置,则其灰度值就按插值算法在4个输出象素之间进行分配。称为向前映射法,或象素移交影射。

注:从原图象坐标计算出目标图象坐标镜像、平移变换使用这种计算方法

向后映射法

  向后映射法(或象素填充算法)是输出象素一次一个地映射回到输入象素中,以便确定其灰度级。如果一个输出象素被映射到4个输入象素之间,则其灰度值插值决定,向后空间变换是向前变换的逆。

注:从结果图象的坐标计算原图象的坐标

  • 旋转、拉伸、放缩可以使用
  • 解决了漏点的问题,出现了马赛克

1.5 基于OpenCV的实现

1.5.1 C++

函数原型:

void cv::resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )

src:输入图像
dst:输出图像
dsize:输出图像尺寸
fx、fy:x,y方向上的缩放因子
INTER_LINEAR:插值方法,总共五种
    1. INTER_NEAREST - 最近邻插值法
    2. INTER_LINEAR - 双线性插值法(默认)
    3. INTER_AREA - 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
    4. INTER_CUBIC - 基于4x4像素邻域的3次插值法
    5. INTER_LANCZOS4 - 基于8x8像素邻域的Lanczos插值

代码实践:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
	Mat img = imread("D:/image/yuner.jpg");
	if (img.empty())
	{
		cout << "无法读取图像" << endl;
		return 0;
	}

	int height = img.rows;
	int width = img.cols;
	// 缩小图像,比例为(0.2, 0.2)
	Size dsize = Size(round(0.2 * width), round(0.2 * height));
	Mat shrink;
    //使用双线性插值
	resize(img, shrink, dsize, 0, 0, INTER_LINEAR);

	// 在缩小图像的基础上,放大图像,比例为(1.5, 1.5)
	float fx = 1.5;
	float fy = 1.5;
	Mat enlarge1, enlarge2;
	resize(shrink, enlarge1, Size(), fx, fy, INTER_NEAREST);
	resize(shrink, enlarge2, Size(), fx, fy, INTER_LINEAR);

	// 显示
	imshow("src", img);
	imshow("shrink", shrink);
	imshow("INTER_NEAREST", enlarge1);
	imshow("INTER_LINEAR", enlarge2);
	waitKey(0);
    return 0;
}

原图

0.2倍缩小,双线性插值

1.5倍放大,最近邻插值

1.5倍放大,双线性插值

1.5.2 Python

函数原型:

cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])

参数:

参数描述
src【必需】原图像
dsize【必需】输出图像所需大小
fx【可选】沿水平轴的比例因子
fy【可选】沿垂直轴的比例因子
interpolation【可选】插值方式

插值方式:

cv.INTER_NEAREST最近邻插值
cv.INTER_LINEAR双线性插值
cv.INTER_CUBIC基于4x4像素邻域的3次插值法
cv.INTER_AREA基于局部像素的重采样

通常,缩小使用cv.INTER_AREA,放缩使用cv.INTER_CUBIC(较慢)和cv.INTER_LINEAR(较快效果也不错)。默认情况下,所有的放缩都使用cv.INTER_LINEAR。

代码实践:

import cv2
 
if __name__ == "__main__":
    img = cv2.imread('./data/yuner.jpg', cv2.IMREAD_UNCHANGED)
    
    print('Original Dimensions : ',img.shape)
    
    scale_percent = 30       # percent of original size
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
    # resize image
    resized = cv2.resize(img, dim, interpolation = cv2.INTER_LINEAR)

    fx = 1.5
    fy = 1.5

    resized1 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_NEAREST)
    
    resized2 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_LINEAR)
    print('Resized Dimensions : ',resized.shape)
    
    cv2.imshow("Resized image", resized)
    cv2.imshow("INTER_NEAREST image", resized1)
    cv2.imshow("INTER_LINEAR image", resized2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
Original Dimensions :  (1080, 1080, 3)
Resized Dimensions :  (324, 324, 3)
1080*0.3
324.0

0.3倍缩小,双线性插值

1.5倍放大,最近邻插值

1.5倍放大,双线性插值

  • 推荐书籍:学习OpenCV中文版
  • 推荐博客:https://blog.csdn.net/hongbin_xu/category_6936122.html

1.6 总结

  插值算法是很多几何变换的基础和前置条件,对插值算法细节的掌握有助于对其他算法的理解,为自己的学习打下坚实的基础。


Task01 OpenCV框架与图像插值算法 END.

By: Aaron

博客:https://sandy1230.github.io/

博客:https://blog.csdn.net/weixin_39940512

关于Datawhale

Datawhale是一个专注于数据科学与AI领域的开源组织,汇集了众多领域院校和知名企业的优秀学习者,聚合了一群有开源精神和探索精神的团队成员。Datawhale以“for the learner,和学习者一起成长”为愿景,鼓励真实地展现自我、开放包容、互信互助、敢于试错和勇于担当。同时Datawhale 用开源的理念去探索开源内容、开源学习和开源方案,赋能人才培养,助力人才成长,建立起人与人,人与知识,人与企业和人与未来的联结。

补充

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像超分辨率算法是一种通过方式将低分辨率图像增强到高分辨率图像的技术。常见的方法包括线性、双三次和基于梯度的等方法。其中,双三次是最流行的方法之一,它简单易行,计算速度快,在处理小尺寸图像时效果较好。然而,在处理高分辨率图像时,双三次的效果可能不够理想。\[2\] 除了方法,还有一种基于卷积神经网络的超分辨率算法,称为SRCNN算法。SRCNN算法通过三个卷积层和一个反卷积层来实现图像的超分辨率。该算法利用低分辨率图像作为输入,经过神经网络训练后输出高分辨率图像。SRCNN算法能够在速度和精度之间找到平衡点,可以快速且精确地实现图像的超分辨率。\[3\] 综上所述,图像超分辨率算法包括传统的方法和基于卷积神经网络的算法,它们都能够提升图像的清晰度和细节。具体选择哪种算法取决于应用场景和需求。 #### 引用[.reference_title] - *1* *2* *3* [人工智能之超分辨率算法详解](https://blog.csdn.net/q6115759/article/details/130758781)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值