>>> from env_helper import info; info()
页面更新时间: 2024-04-06 23:05:44
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

3.10. 使用OpenCV对图像进行处理

pillow相对于OpenCV 来讲,它还是弱小很多。跟很多开源软件一样 OpenCV 也提供了完善的 Python 接口,非常便于调用。OpenCV 的稳定版是 2.4.8,最新版是 4.2.0,包含了超过 2500 个算法和函数,几乎任何一个能想到的成熟算法都可以通过调用 OpenCV 的函数来实现,超级方便。

OpenCV的优点:

  • OpenCV 是跨平台的,可以在 Windows、Linux、Mac OS、Android、iOS 等操作系统上运行。

  • OpenCV 的应用领域非常广泛,包括图像拼接、图像降噪、产品质检、人机交互、人脸识别、动作识别、动作跟踪、无人驾驶等。

  • OpenCV 还提供了机器学习模块,你可以使用正态贝叶斯、K最近邻、支持向量机、决策树、随机森林、人工神经网络等机器学习算法。

使用pip安装OpenCV

pip install opencv-python

也可以使用anaconda安装,同样方便快捷。

3.10.1. 读取图像

使用函数 cv2.imread() 读入图像。

  • cv2.IMREAD_COLOR :读入一副彩色图像。图像的透明度会被忽略,这是默认参数。

  • cv2.IMREAD_GRAYSCALE :以灰度模式读入图像

  • cv2.IMREAD_UNCHANGED :读入一幅图像,并且包括图像的 alpha 通道(RGBA)

>>> import cv2
>>> from matplotlib import pyplot as plt
>>> img = cv2.imread( 'L1020120.JPG')

同样使用matplotlit库进行查看

>>> from matplotlib import pyplot as plt
>>> plt.imshow(img)
>>> plt.show()
_images/sec50_opencv_5_0.png

可以看出,图像的颜色显示不正常。

这是因为matplotlib使用的颜色模式是我们现在流行的RGB模式,而opencv使用的是BGR模式,即RGB的倒序模式,与我们通常的RGB是反向的。因此在使用matplotlib显示之前需要做一下图像颜色的转换。

>>> img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

3.10.2. 保存图像

使用函数cv2.imwrite(file,img,num)保存一个图像。第一个参数是要保存的文件名,第二个参数是要保存的图像。可选的第三个参数,它针对特定的格式:对于JPEG,其表示的是图像的质量,用0 - 100的整数表示,默认95;对于png ,第三个参数表示的是压缩级别,默认为3。

  • cv2.IMWRITE_JPEG_QUALITY类型为 long ,必须转换成 int

  • cv2.IMWRITE_PNG_COMPRESSION, 从0到9 压缩级别越高图像越小

>>> cv2.imwrite('./xx_opencv_out.jpg',img,
>>>             [int( cv2.IMWRITE_JPEG_QUALITY), 95])
True

3.10.3. 变换操作

翻转图片

使用函数cv2.flip(img,flipcode)翻转图像,flipcode控制翻转效果。

  • flipcode = 0 : 沿 x 轴翻转

  • flipcode > 0 :沿 y 轴翻转

  • flipcode < 0x,y 轴同时翻转

>>> imgflip = cv2.flip(img,0)

3.10.4. 绘图函数

画线

要画一条线,你只需要告诉函数这条线的起点和终点。 我们下面会画一条从左上方到右下角的绿色线段。如果是展示其他颜色还需要再次转换。

>>> import numpy as np
>>>
>>> img = np.zeros((512,512,3), np.uint8)
>>> cv2.line(img,(0,0),(511,511),(0,255,0),5); pass

画矩形

要画一个矩形,你需要告诉函数的左上角顶点和右下角顶点的坐标。这次我们会在图像的右上角话一个绿色的矩形。

>>> cv2.rectangle(img,(390,0),(510,120),(0,255,0),3); pass

3.画圆

要画圆的话,只需要指定圆形的中心点坐标和半径大小。我们在上面的矩形中画一个圆。

>>> cv2.circle(img,(450,60), 60, (0,0,255), -1); pass
  1. 画椭圆

画椭圆比较复杂,我们要多输入几个参数。一个参数是中心点的位置坐标。

下一个参数是长轴和短轴的长度。椭圆沿逆时针方向旋转的角度。椭圆弧演顺时针方向起始的角度和结束角度,如果是 0 和 360,就是整个椭圆。

>>> cv2.ellipse(img,(256,256),(100,50),0,0,360,255,-1); pass

5.画多边形

画多边形,需要指点每个顶点的坐标。用这些点的坐标构建一个大小等于行数的数组,行数就是点的数目。这个数组的数据类型必须为 int32。

>>> pts = np.array([[10,450],[100,300],[200,420],[10,450]], np.int32)
>>> pts = pts.reshape((-1,1,2))
>>> cv2.polylines(img,[pts],True,(0,255,255)); pass

最后查看一下结果 :

>>> plt.imshow(img)
>>> plt.show()
_images/sec50_opencv_23_0.png

这里 reshape 的第一个参数为 -1, 表明这一维的长度是根据后面的维度的计算出来的。 如果第三个参数是 False,我们得到的多边形是不闭合的(首尾不相连)。

注意:cv2.polylines() 可以被用来画很多条线。只需要把想要画的线放在一个列表中,将这个列表传给函数就可以了。每条线都会被独立绘制。这会比用 cv2.line() 一条一条的绘制要快一些。

3.10.5. 添加水印

要在图片上绘制文字,你需要设置下列参数:

  • 你要绘制的文字

  • 你要绘制的位置

  • 字体类型(通过查看 cv2.putText() 的文档找到支持的字体)

  • 字体的大小

  • 文字的一般属性如颜色,粗细,线条的类型等。为了更好看一点推荐使用 linetype=cv2.LINE_AA

>>> img=cv2.imread('L1020120.JPG')
>>> img.shape
(734, 1000, 3)
>>> font = cv2.FONT_HERSHEY_SIMPLEX
>>> cv2.putText(img,'OpenCV',(500,600), font, 4,(25,205,255),7,cv2.LINE_AA)
>>> img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
>>> plt.imshow(img)
>>> plt.show()
_images/sec50_opencv_26_0.png
  • (2000,1900) 设置字体位置

  • (font, 7) 调整字体大小

  • (25,205,255) 调整字体颜色

    1. 调整字体粗细

3.10.6. 形态学处理

形态学一词通常指生物学的一个分支,它用于处理动物和植物的形状和结构。在数学形态学的语境中也使用该词来作为提取图像分量的一种工具,这些分量在表示和描述区域形状(如边界,骨骼和凸壳)时是很有用的。此外,我们还很关注用于预处理和后处理的形态学技术,如形态学滤波、细化和裁剪。 数学形态学的基本运算 数学形态学的基本运算有4个:腐蚀、膨胀、开启和闭合。数学形态学方法利用一个称作结构元素的”探针”收集图像的信息,当探针在图像中不断移动时,便可考察图像各个部分之间的相互关系,从而了解图像的结构特征。在连续空间中,灰度图像的腐蚀、膨胀、开启和闭合运算分别表述如下。

腐蚀

腐蚀“收缩”或“细化”二值图像中的对象。收缩的方式和程度由一个结构元素控制。数学上,A被B腐蚀,记为AΘB,

换言之,A被B腐蚀是所有结构元素的原点位置的集合,其中平移的B与A的背景并不叠加。可以理解为腐蚀是将黑色区域放大。

>>> image = cv2.imread("i.png")
>>> plt.imshow(image)
>>> plt.show()
_images/sec50_opencv_29_0.png
>>> kernel = np.ones((5,5),np.uint8)
>>> erosion = cv2.erode(image,kernel,iterations = 1)
>>> plt.imshow(erosion)
>>> plt.xticks([]), plt.yticks([])
>>> plt.show()
_images/sec50_opencv_30_0.png

卷积值越大,处理的图像越明显。

>>> kernel = np.ones((10,10),np.uint8)
>>> erosion = cv2.erode(image,kernel,iterations = 1)
>>> plt.imshow(erosion)
>>> plt.xticks([]), plt.yticks([])
>>> plt.show()
_images/sec50_opencv_32_0.png

膨胀

膨胀是在二值图像中“加长”或“变粗”的操作。这种特殊的方式和变粗的程度由一个称为结构元素的集合控制。结构元素通常用0和1的矩阵表示。数学上,膨胀定义为集合运算。A被B膨胀,记为A⊕B,与腐蚀相反膨胀是将白色的区域方大。

其中,Φ为空集,B为结构元素。总之,A被B膨胀是所有结构元素原点位置组成的集合,其中映射并平移后的B至少与A的某些部分重叠。这种在膨胀过程中对结构元素的平移类似于空间卷积。

膨胀满足交换律,即A⊕B=B⊕A。在图像处理中,我们习惯令A⊕B的第一个操作数为图像,而第二个操作数为结构元素,结构元素往往比图像小得多。 膨胀满足结合律,即A⊕(B⊕C)=(A⊕B)⊕C。假设一个结构元素B可以表示为两个结构元素B1和B2的膨胀,即B=B1⊕B2,则A⊕B=A⊕(B1⊕B2)=(A⊕B1)⊕B2,换言之,用B膨胀A等同于用B1先膨胀A,再用B2膨胀前面的结果。我们称B能够分解成B1和B2两个结构元素。结合律很重要,因为计算膨胀所需要的时间正比于结构元素中的非零像素的个数。通过结合律,分解结构元素,然后再分别用子结构元素进行膨胀操作往往会实现很客观的速度的增长。

>>> image = cv2.imread("i.png")
>>> plt.imshow(image)
>>> plt.show()
_images/sec50_opencv_34_0.png
>>> kernel = np.ones((5,5),np.uint8)
>>> dilation = cv2.dilate(image,kernel,iterations = 1)
>>> plt.imshow(dilation)
>>> plt.xticks([]), plt.yticks([])
>>> plt.show()
_images/sec50_opencv_35_0.png

开运算与闭运算

开运算

先进性腐蚀再进行膨胀就叫做开运算。就像我们上面介绍的那样,它被用来去除噪声。这里我们用到的函数是 cv2.morphologyEx()。

>>> img=cv2.imread("./img7.png")
>>> opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
>>> plt.subplot(121),plt.imshow(img),plt.title('Original')
>>> plt.xticks([]), plt.yticks([])
>>> plt.subplot(122),plt.imshow(opening),plt.title('Opening')
>>> plt.xticks([]), plt.yticks([])
>>> plt.show()
_images/sec50_opencv_37_0.png

闭运算

先膨胀再腐蚀。它经常被用来填充前景物体中的小洞,或者前景物体上的小黑点。

>>> img=cv2.imread("./img5.png")
>>> closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
>>> plt.subplot(121),plt.imshow(img),plt.title("Original")
>>> plt.xticks([]),plt.yticks([])
>>> plt.subplot(122),plt.imshow(closing),plt.title("Closing")
>>> plt.xticks([]),plt.yticks([])
>>> plt.show()
_images/sec50_opencv_39_0.png