一、图像透视变化
1.1 实验原理
图像透视变换(Perspective Transformation)是一种通过数学方法将图像中的点集映射到一个新的点集上的技术。它能够对图像进行几何变换,常用于将不规则形状的区域转换为规则形状,或修正图像中的透视失真。
透视变换的核心在于透视矩阵的计算。通过一组源图像中的四个点(通常是矩形的四个角)和目标图像中的四个点,我们可以得到一个透视变换矩阵,然后应用该矩阵到原始图像中,从而得到变换后的图像。
- 四点透视变换:首先从原始图像中选取四个点,这些点应该位于待变换区域的四个角落。然后定义目标图像的四个角,通常目标图像是一个矩形。
- 透视变换矩阵计算:使用 OpenCV 的
cv2.getPerspectiveTransform()
函数来计算源点与目标点之间的映射关系,并生成一个透视变换矩阵。 - 应用透视变换:通过
cv2.warpPerspective()
函数将透视变换矩阵应用到原图像中,从而得到变换后的图像。
1.2 实验代码
# 导入OpenCV库和numpy库
import cv2
import numpy as np
# 从指定路径读取图像
img = cv2.imread('./youhua.png')
# 定义原始图像中的四个点(通常是矩形顶点),这些点用于定义要进行透视变换的区域
# 这些点的坐标需要根据你的图像中的实际位置进行调整
points1 = np.float32([[175,142],[621,35],[89,491],[652,546]])
# 定义变换后的目标图像中的四个点,这里创建了一个新的矩形,其顶点位于
# 原始图像的最左、最上、最右、最下边界上,从而进行透视变换
# 这一步的目的是将原始图像中的不规则四边形区域变换为一个规则的矩形
points2 = np.float32([[min(points1[:,0]),min(points1[:,1])], # 左上角
[max(points1[:,0]),min(points1[:,1])], # 右上角
[min(points1[:,0]),max(points1[:,1])], # 左下角
[max(points1[:,0]),max(points1[:,1])] # 右下角
])
# 使用cv2.getPerspectiveTransform函数计算透视变换矩阵M
# 这个矩阵用于将points1中的点映射到points2中的点
M = cv2.getPerspectiveTransform(points1,points2)
# 使用cv2.warpPerspective函数应用透视变换矩阵M到原始图像img上
# 第三个参数是输出图像的尺寸,这里设置为原始图像的尺寸
img_output = cv2.warpPerspective(img,M,(img.shape[1],img.shape[0]))
# 显示原始图像和变换后的图像
cv2.imshow('img',img)
cv2.imshow('img_output',img_output)
# 等待用户按键操作,按任意键后关闭所有窗口
cv2.waitKey(0)
1.3 实验现象
-
原始图像:在实验中,原始图像是一张有透视畸变的图片,通常是一个四边形或不规则形状的区域。通过选择图像中的四个控制点,我们将该区域转化为一个矩形区域。
-
变换后的图像:通过透视变换后,图像中的指定区域被调整为矩形,从而纠正了原图中的透视失真,使得该区域看起来更加符合我们期望的正视图效果。
-
效果展示:
- 原图中的区域看起来可能会有一定的倾斜或失真。
- 经过透视变换后,图像中的四边形区域将被转换为矩形,纠正了透视畸变。
二、 图片添加水印
2.1 实验原理
图像叠加和 logo 融合是图像处理中常见的操作。它通常用于将一个图像(如 logo)插入到另一张图像(如背景图)中的特定位置。此过程通常包括以下几个步骤:
-
灰度化与二值化: 对 logo 图像进行灰度化,转换为单通道灰度图,然后使用二值化技术生成二值掩膜。掩膜的作用是从 logo 图像中提取出有用的区域(即 logo 的形状),将这些区域与背景图像进行合成。
-
ROI(Region of Interest)区域选择: 在背景图像中选择一个区域作为插入 logo 的目标区域,通常这个区域的大小与 logo 图像一致。这个目标区域被称为“ROI”(感兴趣区域)。
-
位运算(bitwise): 使用
cv2.bitwise_and()
函数对背景图像中的目标区域和 logo 图像的掩膜进行位与操作,得到与 logo 匹配的区域。位运算的目的是确保 logo 图像的透明背景部分不会对目标区域产生影响。 -
图像融合: 将处理后的目标区域和 logo 图像合成,使用
cv2.add()
函数对这两个区域进行相加操作,完成 logo 的融合。 -
替换原图中的区域: 最后,将融合后的图像部分替换原始图像中的相应区域,从而完成 logo 的叠加过程。
2.2 实验代码
import cv2 # 导入OpenCV库
# 从指定路径读取背景图像和logo图像
img = cv2.imread("./flower.png") # 背景图像
logo = cv2.imread("./logo.png") # logo图像
# 对logo图像进行灰度化处理,然后应用二值化操作,得到一个白底的掩膜
# 灰度化是将彩色图像转换为灰度图像,二值化是将灰度图像转换为只有黑白两种颜色的图像
logo_gray = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY) # 将logo图像从BGR颜色空间转换为灰度颜色空间
_, logo_binary = cv2.threshold(logo_gray, 70, 255, cv2.THRESH_BINARY_INV) # 对灰度图像进行二值化操作,使用反阈值法
# 这里,70是阈值,255是最大值,cv2.THRESH_BINARY_INV表示将灰度值大于70的像素点设置为0(黑色),其余设置为255(白色)
# 在背景图像中选取一个和logo图像同等大小的区域,作为要插入logo的位置
# ROI是感兴趣区域(Region of Interest)的缩写
ROI = img[10:10+logo.shape[0], 100:100+logo.shape[1]] # 在背景图像中指定ROI的位置和大小
ROI_logo = cv2.bitwise_and(ROI, ROI, mask=logo_binary)
# 将处理后的ROI区域(实际上是经过掩膜处理的ROI,但这里由于逻辑问题,直接使用了ROI)与原始的logo图像进行融合
# 注意:这里的融合方式(使用cv2.add)可能会导致颜色值溢出(超过255),通常需要对结果进行截断或归一化处理。
img_logo = cv2.add(ROI_logo, logo)
# 将融合的图像(实际上是经过错误处理的图像)替换到背景图像中指定的位置
img[10:10+logo.shape[0], 100:100+logo.shape[1]] = img_logo # 替换ROI区域
# 显示处理后的图像
cv2.imshow('image', img)
cv2.waitKey(0) # 等待用户按键操作,按任意键后关闭窗口
2.3 实验现象
-
原始图像与 logo 图像:
- 原始图像为
flower.png
,其内容为花卉图像。 - logo 图像为
logo.png
,这是一个带有透明背景的 logo 图案。
- 原始图像为
-
掩膜处理:
- 对 logo 图像进行灰度化,并通过二值化生成掩膜。掩膜将 logo 图像中的非透明部分提取出来,作为 logo 插入原图时的有效区域。
-
ROI 区域选择与 logo 插入:
- 选择原始图像的某个区域作为目标区域(ROI),该区域与 logo 图像的大小相同。
- 通过位与操作和掩膜技术,确保只有 logo 图像中的有效部分(即非透明部分)被插入到目标区域中。
-
图像融合与替换:
- 经过处理后,logo 图像和目标区域在视觉上融合,效果自然且不突兀。
- 最终,logo 被成功插入到原始图像中的指定位置,形成一个新的图像。
-
结果展示:
- 实验完成后,通过
cv2.imshow()
显示最终结果。可以看到 logo 图像无缝地叠加到原始图像上,达到了预期的效果。
- 实验完成后,通过
三、识别图片颜色并绘制轮廓
3.1 实验原理
在图像处理中,轮廓检测是一项重要的技术,用于提取图像中的物体边界或形状。通过轮廓分析,我们可以对图像中的形状进行分类、提取或者进一步处理。该实验的核心操作是使用 OpenCV 提供的函数进行图像灰度化、二值化、轮廓提取以及轮廓排序。
-
图像灰度化:
- 将彩色图像转换为灰度图像,以减少处理的计算量。灰度图像中的每个像素点表示图像的亮度。
-
图像二值化:
- 使用阈值分割方法将图像转换为二值图像,即将像素分为两个类别(黑色和白色),使得轮廓更加清晰。
-
轮廓检测:
- 使用
cv2.findContours()
函数检测图像中的轮廓。轮廓是一条连续的边界,能够反映图像中的物体形状。
- 使用
-
轮廓排序:
- 根据轮廓的面积对所有检测到的轮廓进行排序,找出面积最大的轮廓或其他特定的轮廓。
-
绘制轮廓:
- 使用
cv2.drawContours()
函数在图像上绘制轮廓,以便观察结果。
- 使用
3.2 实验代码
import cv2 # 导入OpenCV库
# 读取图像文件
img = cv2.imread("./../12.11/card.png")
# 将图像从BGR颜色空间转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用Otsu's二值化方法对灰度图像进行二值化处理
# 这里的127是一个初始阈值,但实际上Otsu's方法会自动计算一个最佳阈值
# 255是当像素值超过(或等于)阈值时的赋值
# cv2.THRESH_BINARY + cv2.THRESH_OTSU表示使用Otsu's二值化
_, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 在二值化图像中查找轮廓
# cv2.RETR_LIST表示检索所有轮廓,但不创建任何父子关系
# cv2.CHAIN_APPROX_SIMPLE表示压缩水平、垂直和对角线段,只保留它们的端点
contours, hierarchy = cv2.findContours(img_binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 创建一个列表来存储轮廓及其面积
contour_areas = []
for i in range(len(contours)): # 注意:直接使用len(contours)即可,无需转换为列表
contour_areas.append((i, cv2.contourArea(contours[i]))) # 添加轮廓索引和面积到列表中
# 按面积降序对轮廓列表进行排序
contour_areas.sort(key=lambda x: x[1], reverse=True)
# 获取面积第二大的轮廓的索引(索引从0开始,所以[1]表示第二大的轮廓)
idx = contour_areas[1][0]
# 复制原始图像,以便在其上绘制轮廓
img_copy = img.copy()
# 在复制的图像上绘制指定索引的轮廓
# (0, 0, 255)表示轮廓的颜色为红色
# 3表示轮廓线的厚度
img_draw = cv2.drawContours(img_copy, contours, idx, (0, 0, 255), 3)
# 显示原始图像和绘制了轮廓的图像
cv2.imshow('image', img) # 这里应该显示原始图像,但可能您想显示灰度图像或二值图像以对比
cv2.imshow('image_draw', img_draw) # 显示绘制了轮廓的图像
# 等待按键按下,然后关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows() # 添加了这行代码来确保所有窗口都被关闭
3.3 实验现象
-
原始图像:
- 实验中使用的原始图像是
card.png
,其内容可能是卡片或其他对象。该图像包含需要提取轮廓的元素。
- 实验中使用的原始图像是
-
灰度化图像:
- 图像转换为灰度图像后,所有的颜色信息被丢弃,图像变为单通道。灰度图像通过亮度值(从黑到白)表示图像的内容。
-
二值化图像:
- 使用 Otsu 方法进行二值化后,图像的前景和背景被清晰分离,背景部分为黑色,前景部分为白色,使得轮廓的检测更加明显。
-
轮廓检测:
cv2.findContours()
函数成功地从二值化图像中提取出了多个轮廓。每个轮廓代表图像中一个独立的区域或物体的边界。
-
轮廓排序与选择:
- 所有轮廓的面积被计算并排序。实验中选择了面积第二大的轮廓,这意味着我们可以选择特定大小的物体进行处理或分析。
-
绘制轮廓:
- 通过
cv2.drawContours()
,将选定的轮廓(面积第二大的轮廓)绘制在原图上,轮廓的颜色为红色。结果图像展示了原图和绘制了选定轮廓的图像。
- 通过
-
显示结果:
cv2.imshow()
显示了原始图像和带有轮廓的图像。可以明显看到,第二大面积的轮廓被红色边框标记出来。