欢迎大家来到“Python从零到壹”,在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲解,真心想把自己近十年的编程经验分享给大家,希望对您有所帮助,文章中不足之处也请海涵。Python系列整体框架包括基础语法10篇、网络爬虫30篇、可视化分析10篇、机器学习20篇、大数据分析20篇、图像识别30篇、人工智能40篇、Python安全20篇、其他技巧10篇。您的关注、点赞和转发就是对秀璋最大的支持,知识无价人有情,希望我们都能在人生路上开心快乐、共同成长。
该系列文章主要讲解Python OpenCV图像处理和图像识别知识,前期主要讲解图像处理基础知识、OpenCV基础用法、常用图像绘制方法、图像几何变换等,中期讲解图像处理的各种运算,包括图像点运算、形态学处理、图像锐化、图像增强、图像平滑等,后期研究图像识别、图像分割、图像分类、图像特效处理以及图像处理相关应用。
上一篇文章介绍了图像处理基础知识,这篇文章将详细讲解OpenCV入门知识,包括OpenCV常见数据类型、显示图像、读取像素、修改像素、创建图像、复制图像、保存图像等内容。希望文章对您有所帮助,如果有不足之处,还请海涵。接下来,让我们开启整个系列的学习吧!
下载地址:
前文赏析:
第一部分 基础语法
第二部分 网络爬虫
第三部分 数据分析和机器学习
第四部分 Python图像处理基础
第五部分 Python图像运算和图像增强
第六部分 Python图像识别和图像处理经典案例
第七部分 NLP与文本挖掘
第八部分 人工智能入门知识
第九部分 网络攻防与AI安全
第十部分 知识图谱构建实战
扩展部分 人工智能高级案例
作者新开的“娜璋AI安全之家”将专注于Python和安全技术,主要分享Web渗透、系统安全、人工智能、大数据分析、图像识别、恶意代码检测、CVE复现、威胁情报分析等文章。虽然作者是一名技术小白,但会保证每一篇文章都会很用心地撰写,希望这些基础性文章对你有所帮助,在Python和安全路上与大家一起进步。
OpenCV是一个轻量级高效的跨平台计算机视觉库,实现了图像处理和计算机视觉方面的多种通用算法。所谓的图像可以理解为一个数组,图像处理就是对数组的处理。首先,本文将介绍OpenCV中常见的数据类型,包括点Point类、颜色Scalar类、尺寸Size类、矩形Rect类、矩阵Mat类[1-2]。
表示二维坐标系中的点,含x和y。其示例如下:
#OpenCV示例
Point p; p.x=1, p.y=2;
Point p=Point(1, 2);
#Python示例
points_list = [(160, 160), (136, 160)]
包含四个元素的数组,设置像素值RGB三通道,第四个参数可忽略。其示例如下:
#OpenCV示例 BGR三分量
Scalar(b, g, r);
#Python示例
(0, 0, 255)
它和Point相似,主要成员包括height和width。其示例如下:
#OpenCV示例
Size(5, 5);
Size_(_Tp _width, _Tp _height);
#Python示例
width, height = img.shape
Rect类称为矩形类,包含Point类的成员x和y(代表矩形左上角的坐标)和Size类的成员width和height(代表矩形的大小)。其示例如下:
#OpenCV示例
Rect rect = rect1 & rect2; #求两矩形交集
Rect rect = rect1 | rect2; #求两矩形并集
Rect rectShift = rect + point; #矩形平移
Rect rect = rect1 + size; #矩形缩放
#Python示例
cv2.rectangle(img, (20,20), (150,250), (255,0,0), 2)
通用的矩阵类,用来创建和操作多维矩阵。其示例如下:
#OpenCV示例
Mat M(3,2, CV_8UC3, Scalar(0,0,255));
#Python示例
np.zeros((256,256,3), np.uint8)
在OpenCV2中,图像的读取和显示是最简单的两句代码,它们通过imread()和imshow()函数实现[3]。OpenCV读取图像的imread()函数原型如下,它将从指定的文件加载图像并返回矩阵,如果无法读取图像(因为缺少文件、权限不正确、格式不支持或图像无效等),则返回空矩阵(Mat::data==NULL)。
OpenCV中显示图像调用imshow()函数,它将在指定窗口中显示一幅图像,窗口会自动调整为图像大小,其原型如下所示:
下面是第一个示例程序,主要用于读取和加载经典的“Lena”图像。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
#读取图片
img = cv2.imread("Lena.png")
#显示图像
cv2.imshow("Demo", img)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果如图2-1所示:
需要注意,在图像显示过程中,如果代码中没有waitKey(0)函数,其运行结果可能会出现错误,加载一幅灰色的图像,如图2-2所示。
因此,在显示图像过程中,通常还会调用两个操作窗口的函数,它们分别是waitKey()和destroyAllWindows()。
retval = waitKey([, delay])
– 键盘绑定函数,共一个参数delay,表示等待的毫秒数,看键盘是否有输入,返回值为ASCII值。如果其参数为0,则表示无限期的等待键盘输入;参数大于0表示等待delay毫秒;参数小于0表示等待键盘单击。
destroyAllWindows()
– 该函数可以轻易删除所有建立的窗口。如果你想删除特定的窗口可以使用 cv2.destroyWindow(),并在括号内输入要删除的窗口名。
同时,可以设置加载图像后无限期等待,直到输入指定的按键才退出窗口,如下面的代码需要输入ESC才退出。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
#读取图片
img = cv2.imread("Lena.png")
#显示图像
cv2.imshow("Demo", img)
#无限期等待输入
k=cv2.waitKey(0)
#如果输入ESC按键退出
if k==27:
cv2.destroyAllWindows()
此外,在对比实验中,我们通常需要显示多张图片,此时可以调用NumPy和Matplotlib库辅助完成[4],具体实现过程如下所示。
该程序是调用cv2.imread()函数分别读取四张图片,并转换为RGB颜色空间,接着通过for循环分别设置各子图对应的图像、标题及坐标轴名称,其中plt.subplot(2,2)表示生成2×2张子图。
# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图像
img1 = cv2.imread('lena.png')
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
img2 = cv2.imread('xluo.png')
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)
img3 = cv2.imread('flower.png')
img3 = cv2.cvtColor(img3, cv2.COLOR_BGR2RGB)
img4 = cv2.imread('huawei.png')
img4 = cv2.cvtColor(img4, cv2.COLOR_BGR2RGB)
#显示四张图像
titles = ['lena', 'people', 'flower', 'huawei']
images = [img1, img2, img3, img4]
for i in range(4):
plt.subplot(2, 2, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
输出如图2-3所示,它显示了四幅图像。在图像处理对比中,同时对比多种算法的处理效果是非常重要的手段之一。
OpenCV中读取图像的像素值可以直接通过遍历图像的位置实现,如果是灰度图像则返回其灰度值,如果是彩色图像则返回蓝色(B)、绿色(G)、红色(G)三个分量值。其示例如下:
灰度图像:返回值 = 图像[位置参数]
示例:test=img[88,42]
彩色图像:返回值 = 图像[位置元素, 0 | 1 | 2 ]获取BGR三个通道像素
示例:blue=img[88,142,0] green=img[88,142,1] red=img[88,142,2]
当需要修改图像中的像素时,则定位指定像素并直接赋新像素值即可,彩色图像需要依次给三个分量赋值。如下列代码所示。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
#读取图片
img = cv2.imread("Lena.png")
#读取像素
test = img[88,142]
print("读取的像素值:", test)
#修改像素
img[88,142] = [255, 255, 255]
print("修改后的像素值:", test)
#分别获取BGR通道像素
blue = img[88,142,0]
print("蓝色分量", blue)
green = img[88,142,1]
print("绿色分量", green)
red = img[88,142,2]
print("红色分量", red)
#显示图像
cv2.imshow("Demo", img)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
读取的像素值及修改后的像素值结果如图2-4所示。
下面代码是将100到200行、150到250列的像素区域设置为白色的效果。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
#读取图片
img = cv2.imread("Lena.png")
#该区域设置为白色
img[100:200, 150:250] = [255,255,255]
#显示图像
cv2.imshow("Demo", img)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
图2-5是最终显示的效果图,它将img[100:200, 150:250] 区域显示为白色。
前面是直接读取和修改图像像素的方法,下面讲解通过NumPy库读取像素和修改像素的方法。NumPy是Python提供的数值计算扩展包,拥有高效的处理函数和数值编程工具,Array是NumPy库中最基础的数据结构,表示数组。NumPy可以很方便地创建各种不同类型的多维数组,并且执行一些基础操作。
在图像处理中,NumPy读取像素调用item()函数实现,修改像素调用itemset()实现,其原型如下所示[5]。使用Numpy进行像素读取,调用方式如下:
使用Numpy的itemset函数修改像素,调用方式如下:
最终实现代码如下所示。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
import numpy
#读取图片
img = cv2.imread("Lena.png")
print(type(img))
#Numpy读取像素
print(img.item(78, 100, 0))
print(img.item(78, 100, 1))
print(img.item(78, 100, 2))
#Numpy修改像素
img.itemset((78, 100, 0), 100)
img.itemset((78, 100, 1), 100)
img.itemset((78, 100, 2), 100)
print(img.item(78, 100, 0))
print(img.item(78, 100, 1))
print(img.item(78, 100, 2))
输出结果如下所示,原始图像BGR像素值为88、84、196,修改后的像素值为100、100、100。
<class 'numpy.ndarray'>
88
84
196
100
100
100
由于在OpenCV2中没有CreateImage函数,如果需要创建图像,则需要使用Numpy库函数实现。如下述代码,调用np.zeros()函数创建空图像,创建的新图像使用Numpy数组的属性来表示图像的尺寸和通道信息,其中参数img.shape表示原始图像的形状,np.uint8表示类型。
例如img.shape为(500, 300, 3),它表示500×300像素的图像,3表示这是一个RGB图像。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
#读取图片
img = cv2.imread("Lena.png")
#创建空图像
emptyImage = np.zeros(img.shape, np.uint8)
#显示图像
cv2.imshow("Demo", emptyImage)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
显示结果如图2-6所示,这是一幅新创建的“空白”图像。
复制原有图像来获取一幅新图像,可以调用copy()函数实现。
下述代码实现了图像的创建和复制功能。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
#读取图片
img = cv2.imread("Lena.png")
#创建空图像
emptyImage = np.zeros(img.shape, np.uint8)
#复制图像
emptyImage2 = img.copy()
#显示图像
cv2.imshow("Demo1", img)
cv2.imshow("Demo2", emptyImage)
cv2.imshow("Demo3", emptyImage2)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
最终输出结果如图2-7所示,Demo1表示原始图像,Demo2表示创建的空白图像,Demo3表示复制的图像。
在OpenCV中,输出图像到文件使用的函数为imwrite(),其函数原型如下:
下面是一个调用imwrite()函数输出图像到指定的文件的代码。
# -*- coding:utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
#读取图像
img = cv2.imread("Lena.png")
#显示图像
cv2.imshow("Demo", img)
#保存图像
cv2.imwrite("dst1.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 5])
cv2.imwrite("dst2.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
cv2.imwrite("dst3.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
cv2.imwrite("dst4.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
原始图像“Lena.jpg”为222KB,调用imwrite()函数输出保存的图像共四张,如图2-8所示,其中“dst1.jpg”被压缩,大小为4.90KB,“dst2.jpg”图像大小为99.1KB,“dst3.png”大小为499KB,“dst4.png”大小为193KB。
写到这里,这篇文章就介绍结束。本文详细介绍了OpenCV图像处理的基础用法,包括图像读取、显示、像素处理、创建、复制、写入和保存。通过这篇文章,初学者将学会基本的图像处理操作,代码比较简单,但希望大家一定要自己动手实现所有代码和案例,只有不断实践才能提升。
感谢在求学路上的同行者,不负遇见,勿忘初心。图像处理系列主要包括三部分,分别是:
这周的留言感慨~
十二年CSDN的博客分享,如果要说分享最让我开心的是什么?不是传道,不是授业,也不是解惑,而是接下来这类事。这些年已经陆续鼓励了一些朋友当老师,而昨天得知这一位博友真的去到新疆南疆成为了一名小学老师,我很是感动,是真的感动,六年前我曾鼓励他如果想,就放弃高额工资的互联网大厂,去做自己想做的,没想到已经当了四年老师。又当爹又当妈,国语普及,文化教育,这里面的艰辛不是一两句道得清,除了佩服就是鼓励。
正如你说的一样,“一辈子总得做点有意义的事情,生命实在太短暂,一定要活得积极、正面”。或许,这也是我在CSDN分享博客的最大意义,再比如云南那位老友的留言,“农村的孩子下雨没有伞,只能拼命奔跑”,希望你以后也能成为一名教师,感恩有你们,感谢有你们。我也希望自己早日毕业回到家乡,花上三四十年做好两件事,一是认真教书,二是将少数民族文物抢救和文字语音保护做好,也鼓励更多人一起加入进来。自己虽然很菜吧,但还是有一些喜欢的事,尤其陪伴爱的人,挺好,爱你们喔。2022年继续加油,在CSDN分享更高质量的博客和专栏。
(By:娜璋之家 Eastmount 2022-01-23 夜于贵阳 https://blog.csdn.net/Eastmount )
参考文献: