Image processing
大约 18 分钟
基于opencv课程设计,分两个部分,一个是根据要求将图像素材进行基础的函数处理,第二部分开发综合图像处理软件
第一部分 图像基础操作
1.1 返回图中的饮料瓶个数,选出容量少的那一瓶饮料,用绿色填充液体部分
(1)思路
操作一:返回饮料瓶个数
- 加载灰度图像,并图像二值化处理,将非黑色像素设置成白色,能够很好的排除瓶子液体部分的干扰
- 使用cv2.filter2D 和一个锐化核对图像进行锐化处理
- 提取边缘:使用 cv2.Canny 提取图像的边缘
- 寻找轮廓:使用 cv2.findContours 寻找边缘图像中的轮廓
- 轮廓数组的长度就是拼字的个数
提取的边缘图像:
操作二:选出容量少的那一瓶饮料,用绿色填充液体部分
- 图像预处理:将灰色的点变成白色,其余的点变成黑色 -> gray_image
- 平滑图像:对gray先进行开运算再形态学闭运算
- 寻找轮廓
- 遍历轮廓,找到所有轮廓中最小矩形的最小h值以及对应的轮廓
- 绘制绿色液体:利用cv2.cvtColor创建一个bgr图像,遍历最小h的轮廓内的所有像素值,除了黑色和白色部分,根据像素值调整设置不同的绿色
(2)实现
1.2 感兴趣区域提取与图像集校正 * 2
(1)思路:
- 提取ROI:从提取从 (x, y) 开始,宽 w 高 h 的子图像
- 定义透视变换的四个点
- 对 ROI 进行透视变换并应用图像增强(锐化和高斯模糊)。
- 返回增强后的图像和原始 ROI。
(2)实现
1.3 计算火柴数目1
(1)思路:
- 复制原图img_caculator,遍历img_caculator像素进行自定义二值化处理,遍历每一个像素灰度值小于160的像素值设置为0
- 边缘检测:使用Canny边缘检测算法提取边缘
- 寻找轮廓,轮廓数组长度 = 火柴根的数量
(2) 实现
1.4 将花瓣作为前景提取出来
(1)思路:
- 将图像从 BGR 颜色空间转换为 HSV 颜色空间
- 定义花瓣颜色的 HSV 范围
- 根据定义的花瓣 HSV 范围,生成掩码图像 mask。
- 创建一个 5x5 的矩形结构元素 kernel,用于形态学操作。
- 对掩码图像进行闭运算,填充小孔
- 对掩码图像进行开运算,去除噪点。
- 使用按位与操作从原始图像中提取花瓣区域。
(2) 实现
1.5 匹配模板
(1)思路:
- 读取模板图和待匹配图像,获取模板图宽高
- 创建模板的二值化掩膜,对模板图像 temp 进行二值化处理,生成掩膜 mask
- 图像 img 中使用模板 temp 进行模板匹配,并使用掩膜 mask
- 找到模板匹配结果中最小值和最大值及其对应的位置
- 计算模板匹配区域的右下角坐标
- 绘制匹配区域:在图像 img 上绘制一个矩形框,以标记匹配区域
1.6 提取出橙色的区域
(1)思路:
- 将图像从 BGR 颜色空间转换为 HSV 颜色空间
- 定义橙色的 HSV 颜色范围
- 根据定义的橙色 HSV 范围,生成掩码图像 mask
- 创建一个 10x10 的矩形结构元素 kernel,用于形态学操作。
- 对掩码图像进行闭运算,填充小孔。
- 对掩码图像进行开运算,去除噪点。
- 在掩码图像中查找轮廓
- 计算每个轮廓的面积,并找到面积最小的轮廓
- 在新的黑色图像 img_new 上绘制面积最小的轮廓。
- 使用按位与操作从原始图像中提取橙色区域
1.7 提取圆形区域
(1)思路:
- 将图像 img2 转换为灰度图,并进行高斯模糊和二值化处理
- 使用形态学操作去除噪点,创建一个椭圆形的结构元素,进行开运算,去除小的噪点
- 通过膨胀操作确定背景区域,并进行边缘检测,膨胀操作扩大背景区域,使用 Canny 算法检测开运算后的图像边缘
- 查找图像中的轮廓并绘制符合条件的轮廓,计算每个轮廓的最小包围圆和圆心:如果轮廓面积大于 4000/ 如果圆半径大于 5 且中心不在特定位置
(2)实现
1.8 图像分割2
(1)思路:
- 复制一个图像
- 应用卷积锐化滤波器[[-1,-1,-1], [-1,9,-1], [-1,-1,-1]]增强图像边缘
- 使用 Canny 算法检测图像边缘,找到图像中的外部轮廓
- 在图像上绘制检测到的轮廓
1.9 为花着色 + 为图上色
(1) 思路:
- 将 BGR 颜色空间的图像转换为 HSV 颜色空间
- 定义蓝色的 HSV 范围
- 生成一个掩码,掩码中蓝色范围内的像素值为 255,其余为 0
- (图)调整掩码中蓝色区域的 HSV 值,设置色调为 120(蓝色),饱和度为 150,并增加明度 50。保证像素值不超过 255。
- (花)调整掩码中蓝色和绿色区域的 HSV 值
- 设置蓝色区域的色调为 120(蓝色),饱和度为 150,并增加明度 50。
- 设置绿色区域的色调为 60(绿色),饱和度为 150,并增加明度 50。
- 保证像素值不超过 255。
- 将 HSV 颜色空间的图像转换回 BGR 颜色空间
1.10 阈值分隔,并统计图中有多少颗药片
(1)思路:
- 创建一个与输入图像大小相同的高斯低通滤波器,用于在频域内平滑图像
- 将图像从空间域转换到频域,以便进行频域滤波
- 中心化频谱,使得低频分量集中在频谱中心,这有助于后续滤波操作
- 在频域中进行滤波,保留低频成分,抑制高频成分,从而平滑图像
- 将频谱中心化的低频成分移回原位,以便进行逆傅里叶变换
- 将图像从频域转换回空间域
- 得到滤波后的图像,并转换为适合显示和处理的图像格式
- 将图像中灰度值大于160的像素设置为255(白色),小于130的像素设置为0(黑色),其余像素也设置为255(白色),以提取出药片
- 使用中值滤波去除图像中的噪点,平滑图像
- 使用 Canny 边缘检测算法提取图像中的边缘
- 找到图像中的药片轮廓
- 遍历轮廓,计算每个轮廓的面积,并在原图上绘制轮廓,以蓝色显示
1.11 找出火柴中黑色的头
(1)思路:
- 创建一个与输入图像大小相同的高斯低通滤波器,用于在频域内平滑图像
- 计算图像的二维快速傅里叶变换(FFT),将图像从空间域转换到频域,以便进行频域滤波
- 将频谱的低频成分移动到中心,中心化频谱,使得低频分量集中在频谱中心,这有助于后续滤波操作
- 应用高斯低通滤波器,在频域中进行滤波,保留低频成分,抑制高频成分,从而平滑图像
- 将频谱的低频成分移回原位,以便进行逆傅里叶变换
- 计算图像的二维逆快速傅里叶变换(IFFT),将图像从频域转换回空间域
- 取傅里叶变换结果的绝对值并转换为无符号8位整数类型,得到滤波后的图像,并转换为适合显示和处理的图像格式
- 对滤波后的图像进行二值化处理,将图像中灰度值大于160的像素设置为255(白色),小于50的像素保留原图值,其余像素也设置为255(白色),以提取出火柴根
- 对图像进行中值滤波,去除图像中的噪点,平滑图像
- 使用 Canny 边缘检测算法提取图像中的边缘,检测图像中的边缘,以便在后续步骤中查找轮廓
- 查找图像中的轮廓:找到图像中的火柴根轮廓,并输出检测到的火柴根数量
- 遍历并绘制检测到的轮廓:遍历轮廓,计算每个轮廓的面积。面积小于30的轮廓忽略。绘制轮廓在原图上,以蓝色显示
(2)实现
1.12 指纹增强,闭合断开地方
(1)思路:
- 对灰度图像进行直方图均衡化,增强图像对比度,使得图像的灰度级分布更加均匀,从而提高细节的可见性
- 对图像进行高斯模糊,减少图像中的噪声,平滑图像
- 对图像进行自适应阈值二值化,使得对象与背景区分开来
- 对二值图像进行形态学闭运算,闭合图像中的小孔或细缝,填补对象内部的空洞
- 使用 Canny 边缘检测算法提取图像中的边缘,检测图像中的边缘,使得对象的轮廓更加明显
- 对边缘图像进行膨胀操作,使边缘变粗,进一步闭合对象边缘的细缝
- 合并边缘图像和闭合图像,将边缘信息添加到闭合图像中,增强对象的轮廓
1.13 手写体识别0-9
(1)思路:
- 使用嵌套循环读取文件夹中的图像文件,将每个图像的像素值存储在数组 a 中。
- 初始化特征数组 feature,大小为 (100, 48, 48),其中每个特征值大小为原图像的 1/5。
- 遍历每个图像,计算每个特征块(5x5)中白色像素(值为255)的数量,并存储在 feature 数组中
- 将 feature 转换为二维数组 train,每行表示一个样本的特征向量。
- 为每个样本设置标签,每个数字 0-9 各有 10 个样本。
- 读取待识别图像,并计算其特征值。
- 创建 KNN 模型并训练。
- 预测待识别图像的类别。
!
第二部分 图像综合实践
2.1 应用简介
已实现功能:
- 功能1:加载图片 —— 文件
- 功能2:将图片向右边旋转 —— 文件
- 功能3:将图片向左边旋转 —— 文件
- 功能4:将图片灰度化 —— 灰度变换
- 功能5: tool bar:文件,灰度变换,噪声与滤波,二维码
- 功能6:裁剪功能(tool bar) 动态调整并生成新图显示在window框 —— 几何变换(文件)
- 功能7:查看灰度直方图/彩色直方图/直方图均衡 —— 灰度变换
- 功能8:增强对比度(tool bar)动态显示在图像框(只有线性) —— 灰度变换
- 功能9:保存当前图像 —— 文件
- 功能10:高斯噪声(tool bar)动态生成新图并显示在图像框 —— 噪声
- 功能11:椒盐噪声(tool bar)动态生成新图并显示在图像框 —— 噪声
- 功能12:高斯滤波(tool bar) 滑动条动态显示图像狂 —— 滤波
功能——二维码:
- 二维码识别(并能够框出已识别的)
- 二维码生成
2.2 核心方法及其参数说明
(1) 上传图片功能
- 使用filedialog.askopenfilename()打开一个文件对话框,让用户选择要上传的图像文件,并返回所选文件的路径。
(2)按照合适比例显示在显示框中:
- 将图像从BGR颜色空间转换为RGB颜色空间,OpenCV默认读取的图像是BGR格式,而PIL使用的是RGB格式。
- 将NumPy数组转换为PIL图像对象,这样可以在Tkinter中使用。
- 清除Canvas中的所有内容,为显示新图像腾出空间
- 获取Canvas和图像的宽高比例因子,选择最小的比例因子以保持图像的纵横比进行缩放。
- 根据计算的比例因子调整图像的大小,使用Lanczos重采样算法进行高质量的缩放。
- 将调整大小后的PIL图像对象转换为Tkinter可用的图像对象。
- 在Canvas中显示图像,使图像居中显示。
- 保存图像对象到showpicture.image属性,以防止图像被垃圾回收机制回收。
- 更新显示文件名的标签,使用os.path.basename(filename)获取文件的基本名称(不包括路径)。
(3) 向左向右旋转
- 使用NumPy的np.rot90()函数将图像数组顺时针旋转90度。np.rot90()函数默认情况下是逆时针旋转90度,需要调用三次或指定参数k=-1来实现顺时针旋转。
(4) 灰度化图片
- 使用OpenCV的cvtColor函数将彩色图像转换为灰度图像
- 将转换后的灰度图像(NumPy数组)转换为PIL图像对象,以便在Tkinter中使用。
(5) 动态裁剪图片
更新裁剪预览功能:
- 从滑动条获取 x1、y1、x2 和 y2 的值,并进行合法性检查(例如:确保 x1 小于 x2,y1 小于 y2,且坐标在图像范围内)。
- 根据指定的坐标裁剪图像。
- 显示图像 引用裁剪功能:
- 从滑动条获取 x1、y1、x2 和 y2 的值,并进行合法性检查。
- 如果坐标合法,则裁剪图像,并将裁剪后的图像赋值给全局变量 img。
- 销毁裁剪窗口。
- 调用 update_main_window 函数更新主窗口中的图像显示。 更新主窗口功能(最终确定按钮时):
- 保存图像对象到 showpicture.image 属性,以防止图像被垃圾回收机制回收。 裁剪窗口的创建于设置:
- 创建一个新的 Toplevel 窗口,用于裁剪操作。
- 设置裁剪窗口的标题和最小尺寸。
- 创建四个滑动条,用于输入裁剪的坐标 x1、y1、x2 和 y2。
- 每个滑动条都有一个对应的标签,并设置 command 参数为 update_crop,以便在滑动条值变化时实时更新裁剪预览。
- x2 和 y2 滑动条的初始值设置为图像的宽度和高度。
- 创建一个确认按钮,点击后调用 apply_crop 函数应用裁剪并更新主窗口中的图像显示。
- 设置裁剪窗口的关闭事件处理,确保关闭窗口时正确销毁窗口对象。
(6) 查看直方图
彩色:
- 使用 cv2.split 函数将彩色图像分为蓝色、绿色和红色三个通道。
- 使用 cv2.calcHist 函数分别计算每个通道的直方图。 • [b]、[g]、[r]:输入的单通道图像。 • [0]:计算第0个通道的直方图。 • None:不使用掩码。 • [256]:直方图的bin数。 • [0, 256]:像素值的范围。
- 使用 plt.subplots 创建一个包含三个子图的图形,并设置大小。
- 分别绘制红色、绿色和蓝色通道的直方图。每个子图设置标题、X轴标签和Y轴标签。
- 使用 plt.tight_layout 自动调整子图布局,使其不重叠。
- 使用 plt.show 显示图形。
灰度图像直方图
- 使用 cv2.calcHist 函数计算灰度图像的直方图。
- 使用 plt.plot 绘制灰度图像的直方图。设置颜色为灰色。
- 设置图形的标题、X轴标签和Y轴标签。
- 使用 plt.show 显示图形。
(7) 保存图像
- filename = filedialog.asksaveasfilename():弹出一个“保存文件”对话框,让用户选择保存文件的位置和文件名。filename 会保存用户选择的文件路径。如果用户取消对话框,filename 将为空。
(8) 直方图均质化
- img_grey = cv2.equalizeHist(img):对灰度图像进行直方图均衡化处理。
(9) 动态调节对比度,亮度
- a = alpha_slider.get() 和 b = beta_slider.get():获取滑动条的当前值。
- contrast_img = cv2.convertScaleAbs(img, alpha=a, beta=b):使用 OpenCV 的 convertScaleAbs 函数调整图像的对比度和亮度。
- 显示图像
创建对比度,亮度窗口:
- contrast_window = Toplevel(window):创建一个新的顶级窗口,用于对比度和亮度调整。
- contrast_window.title('Contrast'):设置窗口标题为“Contrast”。
- contrast_window.minsize(300, 150):设置窗口的最小尺寸为 300x150 像素。
- 创建和配置 alpha 滑动条:
- alpha_label = Label(contrast_window, text="Alpha:"):创建一个标签,用于显示 "Alpha:"。
- alpha_label.grid(row=0, column=0):将标签放置在窗口的第 0 行第 0 列。
- alpha_slider = Scale(contrast_window, from_=0.1, to=3.0, resolution=0.1, orient=HORIZONTAL, command=update_contrast):创建一个水平滑动条,用于调整对比度,范围从 0.1 到 3.0,步长为 0.1,滑动条的值变化时调用 update_contrast 函数。
- alpha_slider.set(1.0):设置滑动条的默认值为 1.0。
- alpha_slider.grid(row=0, column=1):将滑动条放置在窗口的第 0 行第 1 列。
- beta同alpha
- update_contrast():在窗口初始化时调用 update_contrast 函数,显示初始图像。
(10) 动态添加高斯噪声 / 调节高斯滤波
高斯噪声:
- mean = mean_slider.get() 和 sigma = sigma_slider.get():获取滑动条的当前值,分别用于设置高斯噪声的均值和标准差。
- gauss = np.random.normal(mean, sigma, img.shape[:2]):生成与图像大小相同的高斯噪声矩阵。
- noisy_img = np.clip(img + gauss, a_min=0, a_max=255).astype(np.uint8):将生成的高斯噪声添加到图像中,并将结果限制在 0 到 255 范围内,然后转换为 8 位无符号整数类型。
- 显示图像
高斯滤波:
- 从滑块获取均值(sigma)和核大小(ksize)的值。
- 核大小必须为奇数,如果滑块返回的值为偶数,则将其加1。
- 使用OpenCV的GaussianBlur函数对图像应用高斯模糊。
- 显示图像
(11) 动态添加椒盐噪声
- salt = salt_slider.get() / 100.0 和 pepper = pepper_slider.get() / 100.0:从滑动条中获取盐和胡椒噪声的比例,并将其从百分比转换为小数形式。
- h, w = img.shape[:2]:获取图像的高度和宽度。
- img_sp = np.copy(img):创建图像的副本,以便在其上添加噪声。
添加盐噪声:
- num_salt = np.ceil(salt * h * w):计算需要添加的盐噪声像素数量。
- coords = [np.random.randint(0, i - 1, int(num_salt)) for i in img.shape]:生成随机坐标,用于确定噪声位置。
- img_sp[coords[0], coords[1], :] = 255:将指定位置的像素值设置为 255(白色),即盐噪声。
添加胡椒噪声:
- num_pepper = np.ceil(pepper * h * w):计算需要添加的胡椒噪声像素数量。
- coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in img.shape]:生成随机坐标,用于确定噪声位置。
- img_sp[coords[0], coords[1], :] = 0:将指定位置的像素值设置为 0(黑色),即胡椒噪声。
- 显示图像
(12) 二维码——二维码生成与解码
生成二维码:
- data = qr_entry.get():从输入框 qr_entry 获取用户输入的内容。
- qr = qrcode.QRCode(...):创建一个二维码对象,配置参数如下: • version=1:设置二维码版本为1,版本从1到40,数字越大,二维码尺寸越大,能存储的数据越多。 • error_correction=qrcode.constants.ERROR_CORRECT_L:设置错误纠正等级为L(最低级别),能纠正约7%的错误。 • box_size=10:设置二维码每个模块的大小为10像素。 • border=4:设置二维码边框的宽度为4个模块。
- qr.add_data(data):向二维码对象添加用户输入的数据。
- qr.make(fit=True):生成二维码图案,fit=True表示根据数据量调整二维码大小。
- qr_img = qr.make_image(fill='black', back_color='white'):生成二维码图像,黑色填充模块,白色背景。
- qr_img.show():在默认图像查看器中显示生成的二维码。
- qr_window.destroy():关闭输入窗口。
二维码解码:
- 创建一个OpenCV的二维码检测器对象detector。
- 使用detectAndDecode方法检测图像中的二维码,返回解码数据data、顶点坐标数组vertices_array以及二值化的二维码图像binary_qrcode。
- 使用PyZbar库的decode方法检测图像中的二维码,返回所有检测到的二维码列表QRCodes。
- 遍历每个检测到的二维码,并打印其信息。
- 将二维码的数据解码为字符串形式并打印。
- 获取二维码的顶点坐标数组并转换为NumPy数组,用于绘制边框。
- 使用OpenCV的polylines方法在图像上绘制二维码的边框,颜色为绿色,线宽为5。
- 获取二维码的矩形坐标并在图像上绘制解码后的字符串数据。
- 显示图像