OpenCV图像处理

OpenCV图像处理


几何变换

图像缩放:cv.resize(src,dsize,fx=0,fy=0,interpolation=cv.INTER_LINEAR)

src:输入图像。

dsize:绝对尺寸,直接指定调整后图像的大小。

fx,fy:相对尺寸,将dsize设置为None,然后将fx和fy设置为比例因子即可。

interpolation:插值方法。其中INTER_LINEAR:双线性插值法;INTER_NEAREST:最近邻插值;INTER_AREA:像素区域重采样(默认);INTER_CUBIC:双三次插值。

图像平移:

将图像按照指定方向和距离,移动到相应的位置。

cv.warpAffine(img,M,dsize)

img:要操作的图像

M:2*3移动举证,对于(x,y)处的像素点,要把它移动到(x+tx,y+ty)处时,M矩阵应如下设置:

image-20211130202933039

注意:将M设置为np.float32类型的Numpy数组。

dsize:输出图像的大小。

注意:输出图像的大小,他应该是(宽度,高度)的形式。请记住,width=列数,height=行数。

图像旋转:

指图像按照某个位置转动一定角度的过程。旋转中图片仍保持原始尺寸。

OpenCV中图像旋转首先根据旋转角度和旋转中心获取旋转矩阵,然后根据旋转矩阵进行变换,即可实现任意角度和任意中心的旋转效果。

API:cv.getRotationMatrix2D(center,angle,scale)

center:旋转中心。

angle:旋转角度。

scale:缩放比例。

返回:

M:旋转矩阵。

调用cv.warpAffine完成图像的旋转。

仿射变换

图像的仿射变换涉及到图像的形状位置角度的变化,主要是对图像进行缩放,旋转,翻转,平移等操作。

在仿射变换中,原图中所有的平行线在结果图像中同样平行。为了创建这个矩阵我们需要从原图像中找到三个点以及他们在输出图像中的位置。然后使用cv.getAffineTransform会创建一个2×3的矩阵,最后这个矩阵会被传给函数cv.warpAffine。

投射变换

利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光纤束,仍能保持承影面上投影的几何图形不变的变换。

在OpenCV中,我们要找到4个点,其中任意三个点不共线,然后获取变换矩阵T,再进行透射变换,通过函数cv.getPerspectiveTransform找到变换矩阵,将cv。warpPerspective应用于此3×3变换矩阵。

import cv2
import matplotlib.pyplot as plt
import numpy as np

lena1=cv2.imread("1.jpg")
cv2.imshow("image",lena1)
# cv2.waitKey(0)
#matplotlib中展示
plt.imshow(lena1[::-1,::-1,::-1])
plt.show()

px=lena1[100,100]
print(px)
lena2=cv2.imread("2.jpg")
lena2=cv2.resize(lena2,(800,1099))
img=cv2.add(lena1,lena2)
cv2.imshow("img",img)
img2=cv2.addWeighted(lena1,0.3,lena2,0.7,5)
cv2.imshow("img2",img2)
img3=cv2.resize(img2,(400,500),interpolation=cv2.INTER_CUBIC)
cv2.imshow("img3",img3)
rows,cols=img3.shape[:2]
M=np.float32([[1,0,100],[0,1,50]])
img4=cv2.warpAffine(img3,M,(rows,cols))
cv2.imshow("img4",img4)
M=cv2.getRotationMatrix2D((rows/2,cols/2),90,1)
img5=cv2.warpAffine(img3,M,(rows,cols))
cv2.imshow("img5",img5)
a1=np.float32([[50,50],[50,200],[200,50]])
a2=np.float32([[100,50],[50,200],[200,100]])
M1=cv2.getAffineTransform(a1,a2)
img6=cv2.warpAffine(img2,M1,(cols,rows))
cv2.imshow("img6",img6)
#透射变换
b1=np.float32([[32,12],[14,25],[23,32],[14,23]])
b2=np.float32([[44,23],[12,32],[22,32],[43,23]])
M2=cv2.getPerspectiveTransform(b1,b2)
img6=cv2.warpPerspective(img2,M2,(cols,rows))
cv2.imshow("img6",img6)
cv2.waitKey(0)

形态学操作

腐蚀

具体操作时用一个结构元素扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖,像素做“与”操作,如果都为1,则该像素为1,否则为0。

该方法的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点。

API:cv.erode(img,kernel,iterations)

img:要处理的图像

kernel:核结构

iterations:腐蚀的次数,默认是1

膨胀

用一个结构元素扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。

该方法的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的孔洞。

API:cv.dilate(img,kernel,iterations)

#腐蚀和膨胀
kernel=np.ones((5,5),np.uint8)
img7=cv2.erode(img,kernel)
img8=cv2.dilate(img,kernel)
cv2.imshow("img7",img7)
cv2.imshow("img8",img8)
开闭运算

开运算和闭运算是腐蚀和膨胀按照一定的次序进行处理。但是两者都是不可逆的,即先开后闭之后并不能得到原来的图像。

开运算:

先腐蚀后膨胀,作用是分离物体,消除小区域。特点是消除噪点,去除小的干扰块,而不影响原来的图像。

闭运算:

先膨胀后腐蚀,作用是消除“闭合”物体里面的孔洞,特点:可以填充闭合区域。

API:cv.morphologyEx(img,op,kernel)

img:要处理的图像

op:处理方式:若进行开运算,则设为cv.MORPH_OPEN,若进行闭运算,则设为cv.MORPH_CLOSE

kernel:核结构

礼帽和黑帽

礼帽运算:

原图像与”开运算“的结果图之差。

黑帽运算:

“闭运算”结果图与原图像之差。

API:cv.morphologyEx(img,op,kernel)

img:要处理的图像

op:处理方式。MORPH_CLOSE:闭运算;MORPH_OPEN:开运算;MORPH_TOPHAT:礼帽运算;MORPH_BLACKHAT:黑帽运算。

kernel:核结构。

图像平滑

图像噪声

椒盐噪声

是图像中常见的一种噪声,是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或者是暗的区域有白色像素。成因可能是因为影像讯号受到突如其来的强烈干扰而产生、类比数位转换器或位元传输错误等。例如失效的感应器导致像素值为最小值,饱和的感应器导致像素值为最大值。

高斯噪声

指噪声密度函数服从高斯分布的一类噪声。由于高斯噪声在空间和频域中数学上的易处理性,这种噪声模型经常被用于实践中。

高斯噪声产生的噪声是各个灰度值的都有,不仅仅是黑白两种颜色。

图像平滑

去除图像中的高频信息,保留低频信息。

因此,实行低通滤波可以去除图像中的噪声,对图像进行平滑处理。

滤波器可以分为:均值滤波,高斯滤波,中值滤波,双边滤波。

均值滤波

优点:算法简单,计算速度较快。

缺点是在去除噪声的同时也去除了很多的细节部分,将图像变得模糊。

API:cv.blur(src,ksize,anchor,borderType)

src:输入图像

ksize:卷积核的大小

anchor:默认值(-1,-1),表示核中心

borderType:边界类型

高斯平滑

正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。计算平滑结果时,只需要将“中心点”作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。

高斯平滑在处理图像中的高斯噪声方面非常有效。

如果原图是彩色图像,就对RGB三个通道分别都做一次高斯平滑就可以了。

API:cv.GaussianBlur(src,ksize,sigmax,sigmay,borderType)

src:输入图像。

ksize:高斯卷积核大小,注意:卷积核的宽度和高度都应为奇数,且可以不同。

sigmax:水平方向的标准差

sigmay:垂直方向的标准差,默认值为0,表示为sigmax相同。

borderType:填充边界类型

中值滤波

基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值。

中值滤波对椒盐噪声来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。

API:cv.medianBlur(src,ksize)

src:输入图像。

ksize:卷积核的大小。

直方图

图像直方图是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素个数。这种直方图中,横坐标的左侧为较暗的区域,右侧为较亮的区域。因此一张较暗图片的直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。

直方图的一些术语:

dims:需要统计的特征数目。

bins:每个特征空间子区段的数目。

range:要统计特征的取值范围。

直方图的意义:

直方图是图像中像素强度分布的图形表达方式。

它统计了每个强度值所具有的像素个数。

不同的图像的直方图可能是相同的。

API:cv.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])

images:原图像。当传入函数时应该用中括号[]括起来。例如[img]

channels:如果输入图像是灰度图,它的值就是[0];如果是彩色图像的话,传入的参数可以是[0],[1],[2]它们分别对应着通道B,G,R。

mask:掩模图像。要统计整幅图像的直方图就把它设为None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。

histSize:BIN的数目。也应该用中括号括起来。

ranges:像素值范围,[0,255]

掩模的应用

掩模的主要用途:

  • 提取感兴趣区域:用预先制作的感兴趣区掩模与待处理图像进行“与”操作,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0.

  • 屏蔽作用:用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区做处理或统计。

  • 结构特征提取:用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。

  • 特殊形状图像制作。

API:cv.bitwise_and(img,img,mask=mask)

直方图均衡化

把原始图像的灰度直方图从比较集中的某个灰度区间变成更广泛灰度范围内的分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。

这种方法能够提高图像整体的对比度,特别是有用数据的像素值分布比较接近时,在X光图像中使用广泛,可以提高骨架结构的显示,另外在曝光过度或不足的图像中可以更好的突出细节。

API:cv.equalizeHist(img)

img:灰度图像

返回值:均衡化后的结果。

自适应直方图均衡化

对整幅图像进行很多小块划分,然后对每一个小块分别进行直方图均衡化。如果有噪声的话,噪声会被方法,为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的bin超过对比度的上限的话,就把其中的像素点均匀分散到其他bins中,然后再进行直方图均衡化。

最后,为了去除每一个小块之间的边界,再使用双线性差值,对每一小块进行拼接。

API:cv.createCLAHE(clipLimit,titleGridSize)

clipLimit:对比度限制,默认是40

titleGridSize:分块的大小,默认为8×8

边缘检测

边缘检测的目的是标识数字图像中亮度变化明显的点,图像属性中的显著变化通常反映了属性的重要事件和变化。

图像边缘检测大幅度地减少了数据量,并剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,绝大部分可以划分为两类:基于搜索和基于零穿越。

基于搜索:通过寻找图像一阶导数中的最大值来检测边界,然后利用计算结果估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值,代表算法是Sobel算子和Scharr算子。

基于零穿越:通过寻找图像二阶导数零穿越来寻找边界,代表算法是Laplacian算子。

Sobel检测算子

Sobel边缘检测算法比较简单,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合中,Sobel边缘却是首选,Sobel算子是高斯平滑与微分操作的结合体,所以其抗噪声能力很强,用途较多。尤其是效率要求较高,而对纹理不太关心的时候。

对于要处理的图像需要从两个维度进行求导:水平变化和垂直变化。然后对两个方向的结果进行平方和再开方。

统计极大值所在的位置,就是图像的边缘。

注意:当内核大小为3时,以上Sobel内核可能产生比较明显的误差,为解决这一问题,我们使用Scharr函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确。

API:cv.Sobel(src,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

src:传入的图像

ddepth:图像的深度

dx和dy:指求导的阶数,0表示这个方向上没有求导,取值为0,1.

ksize:是Sobel算子的大小,即卷积核的大小,必须为奇数1、3、5、7,默认为3。如果ksize=-1,就演变成为3×3的Scharr算子。

scale:缩放导数的比例常数,默认情况为没有伸缩系数。

borderType:图像边界的模式,默认值为cv.BORDER_DEFAULT。

Sobel函数求导完后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv.CV_16S。处理完图像后,再使用cv.convertScaleAbs()函数将其转回原来的uint8格式,否则图像无法显示。

Sobel算子是在两个方向计算的,最后还需要用cv.addWeighted()函数将其组合起来。

拉普拉斯算子

拉普拉斯利用的是二阶导数来进行边缘检测。

API:cv.Laplacian(src,ddepth[,dst[,kszie[,scale[,delta[,borderType]]]]])

Src:需要处理的图像。

Ddepth:图像的深度,-1表示采用的是原图像相同的深度,目标图像的深度必须大于等于原图像的深度;

ksize:算子的大小,即卷积核的大小,必须为1,3,5,7.

Canny边缘检测

是一种非常流行的边缘检测算法。

原理

第一步:去除噪声

由于边缘检测很容易受到噪声的影响,所以首先使用5×5高斯滤波器去除噪声。

第二步:计算图像梯度

对于平滑后的图像使用Sobel算子计算水平方向和竖直方向的一阶导数(Gx和Gy)。根据得到的这两幅梯度图找到边界的梯度和方向。

如果某个像素点是边缘,则其梯度方向总是垂直与边缘。梯度方向被归为四类:垂直,水平,和两个对角线方向。

第三步:非极大值抑制

在获得梯度的方向和大小后,对整幅图像进行扫描,去除那些非边界上的点。对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。

第四步:滞后阈值

现在要确定真正的边界,设置两个阈值max和min。当图像的灰度梯度高于max时被认为是真的边界,低于min时会被抛弃。如果介于两者之间的话,要看这两个点是否与某个被确定为真正的边界相连。

API:cv.Canny(image,threshold1,threshold2)

image:灰度图

threshold1:min,较小的阈值将间断的边缘连接起来

threshold2:max,较大的阈值检测图像中明显的边缘

模板匹配和霍夫变换

模板匹配就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片。整个任务过程就是不断地滑动模板图片来寻找与模板相同的图片区域。最终将匹配度最高的区域选择为最终的结果。

API:cv.matchTemplate(img,template,method)

img:要进行模板匹配的图像

template:模板

method:实现模板匹配的算法,主要有:平方差匹配(CV_TM_SQDIFF)想、相关匹配(CV_TM_CCORR)、利用相关系数匹配(CV_TM_CCOEFF)

最后使用minMaxLoc定位最匹配的区域。

模板匹配不适用于尺度变换,视角变换后的图像。

霍夫变换

常用来提取图像中的直线和圆等几何形状。

笛卡尔坐标系中的一条直线,对应于霍夫空间中的一个点。

API:cv.HoughLines(img,rho,theta,threshold)

img:检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测。

tho、theta:ρ和角度的精确度。

threshold:阈值,只有累加器中的值高于该阈值时才被认为是直线。

霍夫圆检测

霍夫梯度法将霍夫圆检测分为两个阶段,第一阶段检测圆心,第二阶段利用圆心推导出圆半径。

  • 圆心检测的原理:圆心是圆周法线的交汇处,设置一个阈值,在某点的相交的直线条数大于这个阈值就认为该交汇点为圆心。

  • 圆半径确定原理:圆心到圆周上的距离是相同的,确定一个阈值,只要相同距离的数量大于该阈值,就认为该距离是该圆心的半径。

原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数更多,霍夫空间的维数就更多,因此程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图形的检测中。霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。

API:cv.HoughCircles(image,method,dp,minDist,param1=100,param2=100,minRadiius=0,maxRadius=0)

image:输入图像,应输入灰度图像。

method:使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT。

dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一般,以此类推。

minDist:表示圆心之间的最下距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心。

param1:边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。

param2:检测圆心和确定半径时所共有的阈值。

minRadius和maxRadius:所检测到的圆半径的最小值和最大值。

霍夫圆检测对噪声比较敏感,因此要对图像进行中值滤波。

 

posted @ 2021-12-07 16:04  用余生去爱  阅读(374)  评论(0)    收藏  举报