Python是一种高级、通用、解释型的编程语言,由Guido van Rossum于1991年创造。它被设计为易读易写的语言,具有简洁而清晰的语法,使得它成为许多领域的首选语言,如Web开发、科学计算、人工智能、数据分析等。结合本科阶段以及研究生阶段的进一步使用,预期使用Opencv结合Scikit-imag实现图像的简单处理,同时使用PyQt5实现界面的可视化和人机交互。
Python在图像处理领域有着丰富的库和工具,使得开发人员能够进行各种图像处理操作,包括图像加载、处理、分析和生成等。Python的图像处理库能够加载和保存各种图像格式,如JPEG、PNG、BMP等,使得开发人员能够处理不同来源和格式的图像数据。通过Matplotlib等库,可以将图像显示在屏幕上,进行可视化分析和结果展示。对图像进行缩放、旋转、裁剪、平移等变换操作,调整图像的大小、方向和位置。可以使用各种滤波器对图像进行模糊、锐化、边缘增强等处理,改善图像质量和提取图像特征。也可以将图像从一种颜色空间转换到另一种,如RGB、HSV、LAB等,以便于进行颜色分析和处理。可以对图像进行分割,将图像分成多个区域或对象,以及提取图像中的特征和描述符,用于后续的识别和分析。可以使用机器学习和深度学习技术进行对象检测和识别,如人脸检测、物体识别、文字识别等。
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法,涵盖了从基本的图像处理操作到高级的计算机视觉任务的各种功能。代码简单、应用广泛、具有很多丰富的功能。Scikit-image是一个基于SciPy的开源Python库,用于图像处理。它提供了一系列强大的工具和算法,用于各种图像处理和分析任务。操作简单、易于使用,同时兼容numpy。PyQt5是由Riverbank Computing开发的Qt应用程序框架的Python绑定的综合集合。它使开发人员能够使用Python创建强大的跨平台图形用户界面(GUI)。PyQt5 是一个强大的框架,用于在 Python 中开发 GUI 应用程序,提供了丰富的功能、优秀的性能和与 Qt 生态系统的无缝集成。无论是构建简单的实用工具还是复杂的桌面应用程序,PyQt5 都提供了创建精致和功能丰富的用户界面所需的工具和灵活性。
使用Python代码进行编程实现,并将各个功能集成在一个GUI界面中,建立代码的可视化界面。具体包括九大板块:(1)初始化 (2)图像基本运算(3)图像几何变换(4)添加噪声(5)图像平滑(6)边缘检测(7)形态学处理(8)采样和量化(9)其他。基本界面如下图:
2.1.1 读取图片imread
cv.imread()
括号里面写图片的路径,同在一个文件夹,可以写相对路径也可以绝对路径;不同文件夹,需要写绝对路径。需要注意在Opencv中读入的图片显示格式为BGR。
cv.imwrite(filename, img, params=None)
filename:需要保存图像的文件名,后缀为格式
img:要保存的图片
params:表示为特定格式保存的参数编码,一般进行操作,使用默认值
重新选择模块通过启动一个新的进程来重新启动 Python 脚本。然而,值得注意的是,这种方法可能不会在所有情况下按预期工作,特别是如果脚本依赖于全局状态或者在重新启动之前需要正确关闭一些打开的资源时。此外,在脚本在受限制或沙盒环境中运行的情况下,它可能无法正常工作。
通过定义关闭函数,使用sys模块中的exit函数,设置点击按钮回调关闭函数实现界面的退出。
图像像素相加时,需要保持图像的尺寸一致,当像素值相加大于255后会保持255。函数如下:
cv.add(src1, src2, dst, mask, dtype)
src1:输入的图像1
src2:输入的常数矩阵,和图像1相等大小的,固定常数的矩阵
dst:相加后的输出图像,一般不对其进行操作
mask:8位单通道图像,用于指定哪些像素需要相加,一般不对其进行操作
dtype:输出图像的深度(像素值位数),一般不对其进行操作
图像像素相减时,需要保持图像的尺寸一致。函数如下:
cv.subtract(src1, src2, dst, mask, dtype)
src1:输入图像1
src:输入的常数矩阵,和图像1相等大小的,固定常数的矩阵
dst:相减后的输出图像,一般不对其进行操作
mask:8位单通道图像,用于指定哪些像素需要相减,一般不对其进行操作
dtype:输出图像的深度(像素值位数),一般不对其进行操作
cv.bitwise_and(src1, src2, dst=None, mask=None)
src1:输入图像1
src2:输入图像2
dst:可选输出变量,一般不对其进行操作
mask:掩膜图像,可选参数,一般不对其进行操作
cv.bitwise_or(src1, src2, dst, mask)
src1:输入图像1
src2:输入图像2
dst:可选输出变量,一般不对其进行操作
mask:掩膜图像,可选参数,一般不对其进行操作
cv.bitwise_not(src, dst, mask)
src:输入图像
dst:可选输出变量,一般不对其进行操作
mask:掩膜图像,可选参数,一般不对其进行操作
cv.bitwise_xor(src1, src2, dst, mask)
src1:输入图像1
src2:输入图像2
dst:可选输出变量,一般不对其进行操作
mask:掩膜图像,可选参数,一般不对其进行操作
图像的灰度化主要是降低图像的维度,方便图像在灰度空间进行处理。
cv.cvtColor(src,cv.COLOR_BGR2GRAY)
src:输入的图片
cv.COLOR_BGR2GRAY:这个具体的有很多种,具体格式是cv.COLOR_固定不变,然后是哪个色彩空间到哪个色彩控机,比如BGR到灰度空间,就是BGR2GRAY
cv.threshold(src,thresh,maxval,type,dst)
src:输入图像
thresh:阈值
maxval:当type指定为THRESH_BINARY或THRESH_BINARY_INV时,需要设置该值
type:指定阈值类型
dst:目标图像
2.3.1 平移图像warpAffine
cv.warpAffine(img,mat,size)
img:移动的图像
mat:平移矩阵,决定平移的方向和距离 mat = np.float([[1,0,0],[0,1,20]]) 平移矩阵 对y进行平移20个单位
size:平移后显示的图像大小
cv.getRotationMatrix2D(center, angle, scale)
center:旋转中心
angle:旋转角度
scale:缩放比例
cv.flip(src,flipCode,dst=None)
src:原始图像
dst:代表与原始图像具有同样大小,同样通道数的目标图像
flipCode:旋转类型具体有三个:
0:绕X轴翻转 正数:绕Y轴翻转 负数:绕Y轴翻转
通过for循环对左右像素点进行交换
通过for循环对上下像素点进行交换
水平镜像和垂直镜像同时发生,即对角对称
仿射变换保持了二维图形的“平直性”(直线经仿射变换后依然为直线)和“平行性”(直线之间的相对位置关系保持不变,平行线经仿射变换后依然为平行线,且直线上点的位置顺序不会发生变化)。非共线的三对对应点确定一个唯一的仿射变换。图像的旋转加上拉升就是图像仿射变换,仿射变化也是需要一个M矩阵就可以,但是由于仿射变换比较复杂,一般直接找很难找到这个矩阵,opencv提供了根据变换前后三个点的对应关系来自动求解M。这个函数是M=cv2.getAffineTransform(pos1,pos2),其中两个位置就是变换前后的对应位置关系。输出的就是仿射矩阵M。然后在使用函数cv2.warpAffine()
M = cv2.getAffineTransform(post1, post2)
post1 = 表示变换前的位置
post2 = 表示变换后的位置
cv2.warpAffine(src, M, (cols, rows))
src表示原始图像
M表示仿射变换矩阵
(rows, cols)表示变换后的图像大小,rows表示行数,cols表示列数
透视变换是把一个图像投影到一个新的视平面的过程,该过程包括:把一个二维坐标系转换为三维坐标系,然后把三维坐标系投影到新的二维坐标系。该过程是一个非线性变换过程,因此,一个平行四边形经过透视变换后只得到四边形,但不平行。主要使用cv.getPerspectiveTransform()构建透视矩阵,然后用cv.warpPerspective()进行透视位置的变换。
主要添加四种噪声:
(1)高斯噪声:高斯噪声是一种常见的随机噪声形式,它在许多自然和工程系统中都会出现。这种噪声的产生源于各种随机过程,例如电子器件的热运动、传感器的不确定性、光的散射等。高斯噪声的特点是其在时间或空间域内的数值服从高斯分布(也称为正态分布)。这意味着大多数样本都集中在均值附近,而较少的样本分布在离均值较远的位置。处理高斯噪声的一个常见方法是使用滤波器,如高斯滤波器或均值滤波器,来尝试减少噪声的影响。
(2)泊松噪声:泊松噪声是一种常见的随机噪声形式,通常出现在计数型数据中,例如图像中的像素值、声音中的声波振幅等。泊松噪声的产生源于随机事件的统计性质,例如光子在图像传感器上的随机分布、声音波在传感器上的随机到达等。泊松分布是描述独立随机事件发生次数的概率分布,它是二项分布的一种极限情况。处理泊松噪声的一个常见方法是使用滤波器进行平滑处理,例如中值滤波器或高斯滤波器。此外,可以利用泊松噪声的统计特性进行后处理,例如使用泊松分布的最大似然估计来恢复原始信号。
(3)椒盐噪声:椒盐噪声是一种常见的图像噪声,通常在图像采集、传输或存储过程中产生。这种噪声的特点是图像中随机出现的黑白像素点,看起来就像是图像中撒了椒和盐一样,因此得名椒盐噪声。椒盐噪声通常由于传感器故障、信号传输中的干扰、存储介质损坏等因素引入。它可以出现在任何类型的图像中,但在低质量或老化的图像采集设备中更为常见。椒盐噪声的影响通常是使图像中的细节变得模糊或混淆,降低图像质量。处理椒盐噪声的一个常见方法是使用滤波器进行去噪。中值滤波器是处理椒盐噪声的一种有效方法,它将每个像素的值替换为它周围像素的中值,从而消除异常值的影响,但保留了图像的边缘特征。除了中值滤波器外,还有其他去噪方法,如均值滤波器、高斯滤波器等。选择哪种方法取决于图像的特点以及对图像细节的要求。
(4)乘性噪声:乘性噪声是一种在信号处理领域中常见的噪声类型,它与原始信号的幅度成比例地影响信号的每个样本。乘性噪声通常是由于信号采集或传输过程中的不确定性、噪声源的非线性特性等因素引入的。与加性噪声不同,乘性噪声不是简单地加在原始信号上,而是通过将原始信号的每个样本乘以一个随机变量来引入噪声。这意味着乘性噪声的影响与信号的强度有关,因此在信号的低幅度部分,噪声的影响可能会更为显著。乘性噪声在图像处理领域中也很常见。例如,在数字摄影中,光照不均匀或传感器特性可能会引入乘性噪声,导致图像的局部对比度降低。在图像传输中,乘性噪声可以由于信号传输的非线性特性、传输介质的失真等因素引入。处理乘性噪声的方法通常需要考虑信号的幅度特性。一种常见的方法是使用局部对比度增强技术,例如直方图均衡化或自适应对比度增强,以提高图像的可视化质量。另一种方法是使用适应性滤波器,这些滤波器可以根据信号的局部特性来调整滤波参数,以有效地减少乘性噪声的影响。
具体函数如下:
使用Scikit-image中的函数添加噪声,设置参数改变噪声模型
skimage.util.random_noise(image, mode=‘gaussian’, seed=None, clip=True, **kwargs)
image: 添加噪声的图像
mode: 添加的噪声类型:
‘gaussian’ 高斯加性噪声
‘localvar’ 高斯加性噪声,每点具有特定的局部方差
‘poisson’ 泊松分布的噪声
'salt’盐噪声,随机用1替换像素。属于高灰度噪声
‘pepper’ 胡椒噪声,随机用0或-1替换像素,属于低灰度噪声
‘s&p’椒盐噪声,两种噪声同时出现,呈现出黑白杂点)
后面的参数在运用时一般不对其操作,直接使用默认值
cv.blur(src,ksize)
src:需要处理的图像
ksize:选取的核大小
example cv.blur(img,(6,5))
cv.boxFilter(src,ddepth,ksize,normalize)
src:输入图片
ddepth:目标图像的深度
ksize:核大小
normalize:是否归一化,使用布尔值进行选择
example cv.boxFilter(img, ddepth = -1, ksize(2,2),normalize = False)
cv.GaussianBlur(src,kszie,sigmax)
src:输入图片
ksize:滤波器大小
sigmax:标准差,一般设置为0
example cv.GaussianBlur(img,(5,5),0)
cv.medianBlur(src,ksize)
src:输入图片
ksize:滤波器尺寸大小,必须为奇数
example cv.medianBlur(img,9)
Sobel算子是一种经典的图像边缘检测算子,常用于计算图像中的梯度。它能够识别图像中的边缘(即图像中像素值变化剧烈的地方),从而对图像进行边缘检测和特征提取。Sobel算子是基于离散卷积运算的一种算子,它通过在图像上应用卷积核来计算图像中每个像素的梯度值。
函数如下:
cv.Sobel(src,ddepth,dx,dy,ksize)
src :输入图像
ddepth:输出图像深度,输入8U有正负一起可能值很大,最好是CV_16S/CV_32F
dx:X方向,几阶导数
dy: Y方向,几阶导数.
ksize:Sobel算子ksize大小,必须是1、3、5、7
example: cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
Laplacian算子是一种用于图像处理和计算机视觉中的边缘检测算子,它能够识别图像中的二阶边缘(即图像中的像素值变化的二阶导数)。与Sobel算子等一阶边缘检测算子不同,Laplacian算子能够更好地突出图像中的边缘特征,因为它考虑了像素值的变化率和变化方向。
函数如下:
cv.Laplacian(src,ddepth,ksize)
src:输入图像
ddepth:输出图像深度
ksize:核大小
example: cv.Laplacian(img,cv.CV_64F)
Scharr算子是一种用于图像处理和边缘检测的算子,类似于Sobel算子。它是一种对Sobel算子的改进,能够更加灵敏地检测图像中的边缘。Scharr算子在计算图像的梯度时,与Sobel算子相比,采用了更精确的卷积核。Scharr算子具有两个3x3的卷积核,分别用于水平方向(Gx)和垂直方向(Gy)的梯度计算。
函数如下:
cv.Scharr(src,ddepth,dx,dy,ksize)
src :输入图像
ddepth:输出图像深度,输入8U有正负一起可能值很大,最好是CV_16S/CV_32F
dx:X方向,几阶导数
dy: Y方向,几阶导数.
ksize:核大小
example: cv.Scharr(img,cv.CV_64F,0,1)
Canny算法的输出是一个二值图像,其中边缘被表示为白色像素,而其他区域为黑色像素。由于Canny算法能够准确地识别图像中的边缘,并且对于噪声具有较强的抵抗能力,因此它被广泛应用于许多图像处理任务,例如目标检测、图像分割、物体识别等。
函数如下:
cv.Canny(src,threshold1,threshold2)
src:输入图片
threshold1:阈值1
threshold2:阈值2
example cv.Canny(img,100,200)
图像腐蚀是图像处理中的一种基本操作,通常用于去除图像中的小区域或细节,或者缩小图像中的物体。腐蚀操作通过滑动一个结构元素(也称为核)在图像上,将核与图像重叠的区域内的像素值取最小值,从而使图像中的边缘变细或消失。
函数如下:
cv.erode(src,kernel,iterations)
src:输入图像
kernel:核的大小
iterations:迭代次数,默认为1
example cv.erode(img,kernel=(3,3),iterations=1)
图像膨胀是图像处理中的一种基本操作,通常用于增强图像中的物体或区域,或者连接图像中的物体。膨胀操作通过滑动一个结构元素(也称为核)在图像上,将核与图像重叠的区域内的像素值取最大值,从而扩展或增强图像中的物体。
函数如下:
cv.dilate(src,kernel,iterations)
src:输入图像
kernel:核的大小
iterations:迭代次数,默认为1
example cv.dilate(img,kernel=(3,3),iterations=1)
图像开、闭、梯度、顶帽、底帽是图像处理中常用的形态学运算,它们基于图像的形态学特征进行操作,通常用于图像的增强、分割、去噪等应用。
(1)开运算(Opening): 开运算是先进行腐蚀操作,再进行膨胀操作。它的作用是去除图像中的小物体或者细小的结构,以及消除图像中的小孔洞。
(2)闭运算(Closing): 闭运算是先进行膨胀操作,再进行腐蚀操作。它的作用是填充图像中的小孔洞,平滑物体的边界,并连接相邻的物体。
(3)梯度运算(Gradient): 梯度运算是用膨胀操作的结果减去腐蚀操作的结果。它的作用是突出图像中的边缘或物体轮廓。
(4)顶帽运算(Top Hat): 顶帽运算是原始图像减去开运算的结果。它的作用是突出图像中的明亮区域,并且可以检测到图像中的小亮点或小区域。
(5)底帽运算(Black Hat): 底帽运算是闭运算的结果减去原始图像。它的作用是突出图像中的暗区域,并且可以检测到图像中的小暗点或小区域。
函数如下:
cv.morphologyEx(src,op,kernel)
src:输入图像
op:操作的类型
kernel:核的大小
开运算把类型设为cv.MORPH_OPEN
闭运算把类型设为cv.MORPH_CLOSE
梯度运算把类型设为cv.MORPH_GRADIENT
顶帽运算把类型设为cv.MORPH_TOPHAT
底帽运算把类型设为cv.MORPH_BLACKHAT
cv.adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C,dst=None)
src:输入的图像
maxValue:最大值
adaptiveMethod:自适应的方法有两种,一种是cv.ADAPTIVE_THRESH_MEAN_C,领域内的像素值的权值一样;另一种是cv.ADAPTIVE_THRESH_GAUSSIAN_C,领域内的像素值的权值不同,与到中心的距离有关系,呈现高斯分布,通过高斯方程得到各个点的权重。
thresholdType:代表阈值处理的方法,该值必须是cv.THRESH_BINARY或者cv.THRESH_BINARY_INV中的一个
blockSize:块的大小,计算阈值使用的尺寸,3,5,7等
C:常量对每个blockSize所指定的领域的加权平均值减去常量C
图片采样是把图片以一定的间隔进行像素采样,采样就是对图像的像素值等间隔取值,代码段如下:
img8 = img1[0:-1:2, 0:-1:2] # 间隔为2采样
img9 = img1[0:-1:4, 0:-1:4]
img10 = img1[0:-1:8, 0:-1:8]
img11 = img1[0:-1:16, 0:-1:16]
量化即对图像进去取模,然后以一些像素值代替所有像素值,其原理与二值法相似,没有具体的函数,参考代码段如下:
img3 = np.uint8(img1/16)*16
img4 = np.uint8(img/32)*32
img5 = np.uint8(img/64)*64
img6 = np.uint8(img >= 128)*128
高斯金字塔是一种用于图像分析和处理的多尺度表示方法,它能够在不同尺度下提取图像的特征信息。在高斯金字塔中,每一层图像都是通过对上一层图像进行高斯模糊(低通滤波)和下采样(降低分辨率)得到的。在高斯金字塔中,向下采样(下采样)是指将原始图像缩小到更小的尺寸。这通常通过对原始图像进行滤波然后进行取样来实现。
函数如下:
cv.pyrDown(src)
src:输入要下采样的图片
cv.pyrUp(src)
src:输入要上采样的图片
上采样下采样不可逆,因为丢失的图像序列信息是未知的,需要通过拉普拉斯金字塔来还原原图
马赛克的原理就是一片区域的像素点以区域里的一个点代替,产生相同像素点,在人眼形成“马赛克视觉”
图像油画是通过量化和滤波实现的一种视觉上的效果,具体步骤如下:
(1)将图像转化为灰度图像
(2)将图像划分为一个个小方框(4*4,6*6...),并统计其中的每一个像素点像素值
(3)对方框中的像素点的的灰度值进行量化(可以参考我之前的关于量化的文章),并对不同的等级的像素点数目进行计数
(4)找到方框中灰度等级最多的像素点,并对这些像素点的灰度值求平均
(5)用平均值代替原像素像素值
直方图均衡化是一种用于增强图像对比度的常用技术,它能够使图像中的像素分布更加均匀,从而提高图像的视觉效果和细节可见性。直方图均衡化的基本思想是通过调整图像的像素值分布,使其在整个灰度范围内更加均匀分布,从而增强图像的对比度。
函数如下:
全局直方图均衡化 equalizeHist
cv.equalizeHist(src)
src:需要直方图均衡化的图片
局部直方图均衡化 createCLAHE
cv.createCLAHE(clipLimit, tileGridSize)
clipLimit:一般设置为2.0
tileGridSize:对图像进行小区域分割
example cv.createCLAHE(clipLimit=2.0, tileGridSize=(10, 10))
超像素由一系列位置相邻且颜色、亮度、纹理等特征相似的像素点组成的小区域。这些小区域大多保留了进一步进行图像分割的有效信息,且一般不会破坏图像中物体的边界信息,用少量的超像素代替大量像素表达图像特征,降低了图像处理的复杂度,一般作为分割算法的预处理步骤。SLIC算法生成的像素块相对紧凑,领域特征容易表达;同时需要设置调整的参数少,操作简单,速度快,对于图像的紧凑度、轮廓保持拥有很好的效果;兼容灰度图和彩色图的分割。
Otsu算法是一种用于图像分割的经典方法,通常用于将图像分成两个部分:背景和前景。该算法由日本学者大津展之于1979年提出,它利用图像的灰度直方图来自动确定一个阈值,将图像分成两个类别。
算法步骤:
问题一:PyQt5的版本适配问题
PyQt5的版本与qt5-tools版本不适配,导致GUI界面运行不出来。
问题二:PyUIC和PyRCC的配置
使用Qt.Designer设计GUI界面的布局时,需要使用PyUIC将ui文件转换成 python代码 ,然而在配置PyUIC时候找不到pyuic.exe文件的路径,最后发现是qt5和qt5-tools版本不适配,版本过低,没有pyuic.exe和pyrcc.exe,将qt5库卸载后安装高级版本解决。
问题三:Opencv读取图片格式问题
Opencv读取图片的格式为BGR格式,直接使用pyqt5显示的图片格式为RGB与预期的图片处理结果不符合。最后查阅大量的资料,使用rgbSwapped函数将图片RGB转回到BGR格式问题解决。
问题四:采样后输出的图片尺寸问题
图片在采样后,图片的尺寸发生变化,导致在窗口显示异常。使用resize函数,在图像每次进行采样后,对图像的尺寸进行改变显示正常。
问题五:文本框输入内容通过超参数传递时类型不匹配
在LineEdit控件中输入旋转角度的时候,LineEdit返回的输入内容为字符串形式,不能直接填入getRotationMatrix2D函数当作参数使用。首先将字符串进行分割,形成一个列表,采用索引的方式充当函数的参数,实现图像的正常旋转。
此次设计的大多使用按键控制,下一步的改进希望使用TreeWidget实现折叠侧边栏来解放界面,消除界面设计的冗余。同时对界面进行色彩上的美化,设计多窗口折叠显示。