OpenCV从零开始:30天掌握图像处理基础
OpenCV从零开始:30天掌握图像处理基础
,计算机视觉是人工智能领域的核心方向之一,旨在让计算机具备理解和解释视觉信息的能力。本文以 30 天学习计划为主线,结合 Python 代码与实战案例,系统讲解 OpenCV 图像处理核心技术。从环境搭建到高级应用,涵盖图像读取、几何变换、特征提取、视频处理等模块,助您快速上手计算机视觉开发。
前言
计算机视觉是一门研究如何使机器“看”的科学,更进一步的说,就是是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。作为一个科学学科,计算机视觉研究相关的理论和技术,试图建立能够从图像或者多维数据中获取‘信息’的人工智能系统。这里所指的信息指Shannon定义的,可以用来帮助做一个“决定”的信息。因为感知可以看作是从感官信号中提取信息,所以计算机视觉也可以看作是研究如何使人工系统从图像或多维数据中“感知”的科学。
👉👉👉 🥇 点击进入计算机视觉专栏,计算机视觉(CV)是人工智能的重要分支,致力于让机器通过数字图像或视频获取、处理和分析视觉信息,并模拟人类视觉的认知能力。本专栏涵盖基础概念、技术应用、前沿研究和实战案例等方向。
👉👉👉 🥇 点击进入计算机网络技术专栏,本专栏旨在深入探讨计算机网络的核心概念、关键技术、协议标准以及最新发展趋势,帮助读者全面理解网络通信的原理与实践。
👉👉👉 🥇 点击进入网络安全知识专栏,本专栏详细介绍了网络安全入门:理解基本概念和术语,网络安全的五大核心领域:防护、检测、响应、恢复与治理,常见的网络攻击类型及防范技巧,网络安全防护层次:从物理到应用的多重保障,企业网络安全的十大挑战及解决方案等。
一、基础环境搭建(第 1 天)
1.1 安装 OpenCV-Python
在开始学习 OpenCV 之前,首先需要搭建好开发环境。这里我们选择使用 Python 语言,并安装 OpenCV-Python 库。Python 因其简洁的语法和丰富的库资源,成为了 OpenCV 开发的首选语言。安装 OpenCV-Python 非常简单,只需要使用 pip 命令即可。为了避免依赖冲突,强烈建议在虚拟环境中进行安装。虚拟环境可以帮助我们隔离不同项目的依赖,确保每个项目都能在独立的环境中运行。常见的虚拟环境工具包括 venv 和 conda,下面以 venv 为例进行介绍:
1.创建虚拟环境: 在命令行中执行以下命令,创建一个名为opencv_env的虚拟环境:
python -m venv opencv_env
2.激活虚拟环境:在 Windows 系统的命令提示符中,执行:
opencv_env\Scripts\activate
在 Linux 或 macOS 的终端中,执行:
source opencv_env/bin/activate
安装 OpenCV-Python:激活虚拟环境后,使用 pip 安装 OpenCV-Python 库。可以安装最新版本,也可以指定版本号。例如,安装最新版本的命令如下:
pip install opencv-python
如果需要安装指定版本,比如 4.5.5 版本,可以使用:
pip install opencv-python==4.5.5
在安装过程中,如果遇到网络问题导致下载速度过慢,可以使用国内的镜像源,如清华大学的镜像源:
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
1.2 验证安装
安装完成后,需要验证 OpenCV-Python 是否安装成功。在命令行中进入 Python 交互模式,执行以下命令:
import cv2
print(cv2.__version__)
如果没有报错,并且成功输出 OpenCV 的版本号,说明安装成功。接下来,我们就可以开始使用 OpenCV 进行图像处理了。
二、图像基础操作(第 2-5 天)
2.1 图像读取与显示
在 OpenCV 中,读取和显示图像是最基础的操作。使用cv2.imread()函数读取图像,该函数的第一个参数是图像的路径,第二个参数是读取图像的方式。常见的读取方式有cv2.IMREAD_COLOR(彩色图像,默认值)、cv2.IMREAD_GRAYSCALE(灰度图像)和cv2.IMREAD_UNCHANGED(包含 alpha 通道的图像)。例如,读取一张彩色图像:
import cv2
# 读取彩色图像
img = cv2.imread('test.jpg', cv2.IMREAD_COLOR)
if img is not None:
cv2.imshow('Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print('无法读取图像')
上述代码中,cv2.imshow()
函数用于显示图像,第一个参数是窗口名称,第二个参数是要显示的图像。cv2.waitKey(0)
表示无限期等待键盘输入,当用户按下任意键时,程序继续执行。cv2.destroyAllWindows()
用于关闭所有打开的窗口。
如果要读取灰度图像,只需将cv2.imread()
的第二个参数改为cv2.IMREAD_GRAYSCALE
:
# 读取灰度图像
gray_img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
if gray_img is not None:
cv2.imshow('Gray Image', gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print('无法读取图像')
2.2 几何变换
几何变换是图像处理中常用的操作,包括缩放、旋转、平移和翻转等。
缩放:使用cv2.resize()
函数进行图像缩放,可以指定缩放后的尺寸,也可以指定缩放比例。例如,将图像缩小为原来的一半:
import cv2
img = cv2.imread('test.jpg')
# 按比例缩放,0.5表示缩小为原来的一半
resized_img = cv2.resize(img, None, fx=0.5, fy=0.5)
cv2.imshow('Resized Image', resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
或者指定缩放后的尺寸:
# 指定尺寸缩放
resized_img = cv2.resize(img, (300, 200))
cv2.imshow('Resized Image', resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
旋转:使用cv2.getRotationMatrix2D()
和cv2.warpAffine()
函数实现图像旋转。cv2.getRotationMatrix2D()
用于生成旋转矩阵,cv2.warpAffine()
用于应用旋转矩阵进行图像变换。例如,将图像逆时针旋转 45 度:
import cv2
import numpy as np
img = cv2.imread('test.jpg')
rows, cols = img.shape[:2]
# 生成旋转矩阵,参数为旋转中心、旋转角度、缩放比例
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 1)
# 应用旋转矩阵进行图像变换
rotated_img = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('Rotated Image', rotated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
平移:通过cv2.warpAffine()
函数实现图像平移。需要创建一个平移矩阵,然后应用该矩阵进行图像变换。例如,将图像向右平移 100 个像素,向下平移 50 个像素:
import cv2
import numpy as np
img = cv2.imread('test.jpg')
rows, cols = img.shape[:2]
# 创建平移矩阵,[1, 0, tx; 0, 1, ty],tx为x方向平移量,ty为y方向平移量
M = np.float32([[1, 0, 100], [0, 1, 50]])
# 应用平移矩阵进行图像变换
translated_img = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('Translated Image', translated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
翻转:使用cv2.flip()
函数实现图像翻转,可以指定翻转方向(水平、垂直或两者)。例如,水平翻转图像:
import cv2
img = cv2.imread('test.jpg')
# 水平翻转,参数1表示水平翻转
flipped_img = cv2.flip(img, 1)
cv2.imshow('Flipped Image', flipped_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过这些几何变换操作,可以对图像进行各种变形处理,满足不同的应用需求。
三、像素级处理技术(第 6-10 天)
3.1 通道操作
在 OpenCV 中,彩色图像通常由多个通道组成,常见的 RGB 图像就包含红(R)、绿(G)、蓝(B)三个通道。通道操作可以帮助我们对图像的不同颜色通道进行独立处理,从而实现一些特殊的效果。
通道拆分:使用cv2.split()函数可以将彩色图像拆分成单独的通道。例如,对于一张 RGB 图像,将其拆分为 B、G、R 通道:
import cv2
import numpy as np
img = cv2.imread('test.jpg')
# 拆分通道
b, g, r = cv2.split(img)
# 显示各个通道图像
cv2.imshow('Blue Channel', b)
cv2.imshow('Green Channel', g)
cv2.imshow('Red Channel', r)
cv2.waitKey(0)
cv2.destroyAllWindows()
上述代码中,cv2.split()
函数返回一个包含三个通道图像的元组,分别对应蓝色、绿色和红色通道。
通道合并:cv2.merge()
函数用于将多个单通道图像合并成一个多通道图像。例如,将之前拆分的 B、G、R 通道图像合并回彩色图像:
# 合并通道
merged_img = cv2.merge((b, g, r))
cv2.imshow('Merged Image', merged_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
通道操作在很多场景中都有应用,比如调整图像的颜色平衡、提取特定颜色通道的信息等。
3.2 二值化处理
二值化处理是将图像转换为只有两种颜色(通常是黑色和白色)的过程,通过设定一个阈值,将图像中的像素值分为两类。二值化在图像分割、目标检测、字符识别等领域有着广泛的应用。
全局阈值二值化:使用cv2.threshold()
函数进行全局阈值二值化。该函数的原型为cv2.threshold(src, thresh, maxval, type)
,其中src是输入图像,thresh
是阈值,maxval
是最大值(通常为 255),type
是二值化操作的类型。常见的类型有cv2.THRESH_BINARY
(大于阈值的像素值设置为最大值,小于阈值的像素值设置为 0)和cv2.THRESH_BINARY_INV
(与cv2.THRESH_BINARY
相反)。例如:
import cv2
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
# 全局阈值二值化,阈值为127
ret, binary_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
cv2.imshow('Binary Image', binary_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在实际应用中,选择合适的阈值非常关键。如果阈值过高,可能会丢失目标信息;如果阈值过低,可能会引入过多的噪声。
自适应阈值二值化:当图像的光照不均匀时,全局阈值二值化可能效果不佳。这时可以使用自适应阈值二值化,通过cv2.adaptiveThreshold()
函数实现。该函数根据图像的局部特征自动确定阈值,适用于光照不均匀或有噪声的图像。函数原型为cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
,其中adaptiveMethod
是自适应二值化的方法,常用的有cv2.ADAPTIVE_THRESH_MEAN_C
(使用邻域的平均值作为阈值)和cv2.ADAPTIVE_THRESH_GAUSSIAN_C
(使用邻域的高斯加权平均值作为阈值);blockSize
是邻域的大小,通常为奇数;C是常数,用于调整阈值。例如:
# 自适应阈值二值化
adaptive_binary_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('Adaptive Binary Image', adaptive_binary_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过对比全局阈值二值化和自适应阈值二值化的结果,可以发现自适应阈值二值化在处理光照不均匀的图像时具有更好的效果。
四、图像增强与滤波(第 11-15 天)
4.1 高斯滤波
高斯滤波是一种线性平滑滤波,常用于图像去噪。它的原理是对图像中的每个像素点,根据其邻域像素的高斯分布进行加权平均。高斯分布的特点是离中心越近的像素权重越大,离中心越远的像素权重越小,这样可以在平滑图像的同时,较好地保留图像的边缘信息。
在 OpenCV 中,使用cv2.GaussianBlur()函数进行高斯滤波。函数原型如下:
cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst
- src:输入图像。
- ksize:高斯核的大小,必须是奇数,如 (3, 3)、(5, 5) 等。
- sigmaX:X 方向的标准差。
- sigmaY:Y 方向的标准差,默认为 0,表示与sigmaX相同。
- borderType:边界处理方式,默认为cv2.BORDER_DEFAULT。
- 示例代码:
import cv2
img = cv2.imread('test.jpg')
# 使用(5, 5)的高斯核,标准差为0
blurred_img = cv2.GaussianBlur(img, (5, 5), 0)
cv2.imshow('Original Image', img)
cv2.imshow('Blurred Image', blurred_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过调整ksize和sigmaX、sigmaY的值,可以控制滤波的强度和效果。较小的ksize和sigma值会使图像的模糊程度较轻,较大的值会使图像更加模糊。
4.2 自适应阈值
自适应阈值是一种根据图像局部特征自动调整阈值的方法,适用于图像中光照不均匀或物体与背景对比度不一致的情况。与全局阈值二值化不同,自适应阈值会为图像的每个局部区域计算一个阈值,从而更好地分割图像。
在 OpenCV 中,使用cv2.adaptiveThreshold()函数实现自适应阈值。函数原型如下:
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) -> dst
- src:输入图像,必须是单通道灰度图像。
- maxValue:当像素值超过阈值时设定的值,通常为 255。
- adaptiveMethod:自适应阈值的计算方法,常用的有-
cv2.ADAPTIVE_THRESH_MEAN_C
(均值法)和cv2.ADAPTIVE_THRESH_GAUSSIAN_C
(高斯加权法)。 - thresholdType:阈值类型,必须是
cv2.THRESH_BINARY
或cv2.THRESH_BINARY_INV
。 - blockSize:计算阈值时的邻域大小,必须是奇数,如 3、5、7 等。
- C:常数,用于调整阈值,通常为正数。
- 示例代码:
import cv2
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
# 使用高斯加权法,邻域大小为11,常数为2
adaptive_binary_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('Original Image', img)
cv2.imshow('Adaptive Binary Image', adaptive_binary_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过选择合适的自适应方法和参数,可以使图像在不同光照条件下都能得到较好的二值化效果,为后续的图像分析和处理奠定基础。
五、特征提取与检测(第 16-20 天)
5.1 Canny 边缘检测
Canny 边缘检测是一种非常流行的边缘检测算法,它通过多阶段处理来准确地识别图像中的边缘。该算法在计算机视觉和图像处理领域有着广泛的应用,例如目标识别、图像分割等。
- Canny 边缘检测算法主要包含以下几个步骤:
高斯滤波:由于边缘检测对噪声非常敏感,所以首先使用高斯滤波器去除图像中的噪声。高斯滤波可以平滑图像,减少高频噪声的影响,为后续的边缘检测提供更稳定的基础。在 OpenCV 中,可以使用cv2.GaussianBlur()函数进行高斯滤波。例如:
import cv2
import numpy as np
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
# 使用(5, 5)的高斯核,标准差为0进行高斯滤波
blurred_img = cv2.GaussianBlur(img, (5, 5), 0)
计算图像梯度: 对平滑后的图像使用 Sobel 算子计算水平方向和竖直方向的一阶导数(图像梯度),得到梯度幅值和梯度方向。梯度幅值表示像素点处的边缘强度,梯度方向表示边缘的方向。计算公式如下:
# 计算水平方向梯度
grad_x = cv2.Sobel(blurred_img, cv2.CV_64F, 1, 0, ksize=3)
# 计算竖直方向梯度
grad_y = cv2.Sobel(blurred_img, cv2.CV_64F, 0, 1, ksize=3)
# 计算梯度幅值
grad_magnitude = np.sqrt(grad_x**2 + grad_y**2)
# 计算梯度方向
grad_direction = np.arctan2(grad_y, grad_x)
非极大值抑制:在获得梯度的方向和大小之后,对整幅图像进行扫描,去除那些非边界上的点。具体做法是对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。如果不是,则将该点的梯度值设为 0,这样就可以得到一个只包含 “窄边界” 的二值图像。这个过程可以有效地细化边缘,使检测到的边缘更加准确。
滞后阈值:设置两个阈值:minVal
和 maxVal
。当图像的灰度梯度高于 maxVal
时被认为是真的边界,那些低于 minVal
的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正边界点相连,如果是,就认为它也是边界点,如果不是就抛弃。这种双阈值策略可以在保留真实边缘的同时,减少噪声和虚假边缘的干扰。
在 OpenCV 中,使用cv2.Canny()
函数可以直接实现 Canny
边缘检测。函数原型如下:
cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) -> edges
- image:输入图像,必须是单通道灰度图像。
- threshold1:低阈值。
- threshold2:高阈值。
- edges:输出的边缘图像。
- apertureSize:Sobel 算子的孔径大小,默认为 3。
- L2gradient:一个布尔值,用于指定是否使用更精确的 L2 范数计算梯度幅值,默认为 False。
- 示例代码:
# 直接使用cv2.Canny()函数进行Canny边缘检测
edges = cv2.Canny(img, 50, 150)
cv2.imshow('Original Image', img)
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过调整threshold1和threshold2的值,可以控制边缘检测的灵敏度和准确性。较低的阈值会检测到更多的边缘,包括一些噪声和弱边缘;较高的阈值会只检测到较强的边缘,边缘更加简洁,但可能会丢失一些重要的边缘信息。
5.2 轮廓检测
轮廓检测是在图像中查找物体边界的过程,它在计算机视觉应用中非常重要,如目标识别、形状分析等。轮廓可以被看作是一系列连接的点,这些点定义了物体的边界。
在 OpenCV 中,使用cv2.findContours()
函数进行轮廓检测。该函数的原型如下:
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
- image:输入图像,必须是二值图像(通常是边缘检测的结果)。
- mode:轮廓检索模式,常见的有以下几种:
- cv2.RETR_EXTERNAL:只检测外轮廓。
- cv2.RETR_TREE:检测所有轮廓,并构建轮廓的树形层次结构,这种模式可以表示轮廓之间的嵌套关系,比如一个物体内部有孔洞,就可以通过层次结构来体现。
- cv2.RETR_LIST:检测所有轮廓,但不建立轮廓之间的层次关系,所有轮廓都是独立的。
- method:轮廓逼近方法,常见的有:
- cv2.CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角方向的线段,只保留线段的端点。例如,一个矩形轮廓只需 4 个点来表示,这样可以大大减少存储轮廓所需的内存,同时也能保留轮廓的基本形状特征。
- cv2.CHAIN_APPROX_NONE:存储轮廓上的所有点,这样可以保留轮廓的所有细节,但会占用更多的内存。
- contours:检测到的轮廓列表,每个轮廓是一个点的向量(即numpy.ndarray- 类型)。
- hierarchy:可选的层次结构输出向量,用于表示轮廓之间的关系。如果使用cv2.RETR_TREE模式,hierarchy会包含每个轮廓的父轮廓、子轮廓、前一个轮廓和后一个轮廓的索引信息。
- 下面是一个完整的轮廓检测示例代码:
import cv2
import numpy as np
# 读取图像
img = cv2.imread('test.jpg')
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用高斯滤波平滑图像
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 使用Canny边缘检测获取二值边缘图像
edges = cv2.Canny(blurred, 50, 150)
# 进行轮廓检测
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上绘制轮廓
img_with_contours = img.copy()
cv2.drawContours(img_with_contours, contours, -1, (0, 0, 255), 2)
# 显示结果
cv2.imshow('Original Image', img)
cv2.imshow('Edges', edges)
cv2.imshow('Image with Contours', img_with_contours)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述代码中,首先读取图像并将其转换为灰度图像,然后进行高斯滤波和平滑处理,接着使用 Canny
边缘检测获取二值边缘图像,最后使用cv2.findContours()
函数检测轮廓,并使用cv2.drawContours()
函数在原图上绘制检测到的轮廓。cv2.drawContours()
函数的参数如下:
- image:要绘制轮廓的图像。
- contours:轮廓列表。
- contourIdx:要绘制的轮廓索引,如果为 - 1,则绘制所有轮廓。
- color:轮廓的颜色。
- thickness:轮廓线条的粗细,如果为 - 1,则填充轮廓。
通过轮廓检测,我们可以提取图像中物体的形状信息,进一步进行形状分析、目标识别等操作。例如,可以计算轮廓的面积、周长、重心等特征,用于区分不同的物体或对物体进行分类。
六、视频处理实战(第 21-25 天)
6.1 实时人脸检测
实时人脸检测是计算机视觉中的一个重要应用,OpenCV 提供了强大的工具来实现这一功能。这里我们使用 Haar 级联分类器,它是一种基于机器学习的目标检测方法,通过训练大量的正样本(人脸图像)和负样本(非人脸图像)来构建分类器模型。
在 OpenCV 中,已经预训练好了一些 Haar 级联分类器模型,如haarcascade_frontalface_default.xml
用于检测正面人脸。下面是实现实时人脸检测的 Python 代码示例:
import cv2
# 加载人脸检测模型
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 将图像转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 在检测到的人脸周围绘制矩形框
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 显示结果
cv2.imshow('Face Detection', frame)
# 按下 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头资源并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
在上述代码中:
cv2.CascadeClassifier
用于加载 Haar 级联分类器模型。cv2.VideoCapture(0)
用于打开默认摄像头,参数0表示使用第一个摄像头,如果有多个摄像头,可以通过修改参数来选择。cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
将彩色图像转换为灰度图像,因为 Haar 级联分类器在灰度图像上的检测效果更好,而且灰度图像的计算量相对较小,可以提高检测速度。face_cascade.detectMultiScale
是关键的人脸检测函数,它会返回检测到的人脸的矩形框坐标。scaleFactor
表示每次图像尺寸减小的比例,minNeighbors
表示构成检测目标的相邻矩形的最小个数,minSize
表示检测目标的最小尺寸。这些参数可以根据实际情况进行调整,以获得更好的检测效果。cv2.rectangle
用于在原始图像上绘制矩形框,标记出检测到的人脸。cv2.waitKey(1)
用于等待按键事件,每 1 毫秒检查一次是否有按键按下。如果按下q键(ASCII 码值为ord('q')
),则退出循环。
通过这段代码,我们可以实现一个简单的实时人脸检测应用,在视频流中实时检测并标记出人脸。在实际应用中,还可以进一步优化代码,如调整检测参数、增加图像预处理步骤(如降噪、直方图均衡化等),以提高检测的准确性和稳定性。
七、综合项目实践(第 26-30 天)
7.1 文档扫描器
在这一部分,我们将综合运用之前所学的知识,实现一个简单的文档扫描器。文档扫描器的主要功能是将拍摄的文档图像进行矫正和预处理,使其更易于阅读和后续的 OCR(光学字符识别)处理。
7.1.1 透视变换矫正文档
透视变换是一种将成像投影到一个新的平面上的变换,也称作投影映射。在文档扫描中,我们使用透视变换来将倾斜的文档图像矫正为矩形。
在 OpenCV 中,通过cv2.getPerspectiveTransform()
函数构造变换矩阵M,该函数需要传入变换前后 4 个点的对应位置。然后,使用cv2.warpPerspective()
函数进行透视变换。示例代码如下:
import cv2
import numpy as np
def order_points(pts):
# 初始化4个坐标点的矩阵
rect = np.zeros((4, 2), dtype="float32")
# 按顺序找到对应坐标0123分别是 左上,右上,右下,左下
# 计算左上,右下
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# 计算右上和左下
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
def four_point_transform(image, pts):
# 获取输入坐标点
rect = order_points(pts)
(tl, tr, br, bl) = rect
# 计算输入的w和h值
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
# 变换后对应坐标位置
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype="float32")
# 计算变换矩阵
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
return warped
# 读取图像
image = cv2.imread('document.jpg')
# 转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 进行边缘检测
edges = cv2.Canny(gray, 75, 200)
# 轮廓检测
contours, _ = cv2.findContours(edges.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 取前5个最大面积的轮廓
cnts = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
for c in cnts:
# 计算轮廓近似
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 4个点的时候就拿出来,意味着可能得到的是矩形
if len(approx) == 4:
screenCnt = approx
break
# 进行透视变换
warped = four_point_transform(image, screenCnt.reshape(4, 2))
# 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Scanned Document', warped)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述代码中,order_points函数用于对输入的 4 个点进行排序,使其按照左上、右上、右下、左下的顺序排列。four_point_transform
函数计算透视变换矩阵并应用变换,将文档图像矫正为矩形。
7.1.2 自适应阈值提取文字区域
为了更好地提取文档中的文字区域,我们使用自适应阈值二值化方法。自适应阈值会根据图像的局部特征自动调整阈值,从而在不同光照条件下都能取得较好的二值化效果。示例代码如下:
# 转换为灰度图像
gray = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
# 自适应阈值二值化
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
# 显示结果
cv2.imshow('Adaptive Threshold', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这段代码中,使用cv2.adaptiveThreshold()
函数对矫正后的文档图像进行自适应阈值二值化处理。其中,cv2.ADAPTIVE_THRESH_GAUSSIAN_C
表示使用高斯加权法计算阈值,11是邻域大小,2是常数。
7.1.3 边缘检测与轮廓筛选
在进行文档扫描时,边缘检测和轮廓筛选是关键步骤,用于确定文档的边界。我们使用 Canny 边缘检测算法来检测图像中的边缘,然后通过轮廓检测找到文档的轮廓。
# 进行边缘检测
edges = cv2.Canny(gray, 30, 100)
# 轮廓检测
contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 找到最大面积的轮廓,即文档轮廓
doc_contour = max(contours, key=cv2.contourArea)
在上述代码中,cv2.Canny()
函数用于进行 Canny 边缘检测,cv2.findContours()
函数用于查找图像中的轮廓。cv2.RETR_EXTERNAL
表示只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE
表示压缩水平、垂直和对角方向的线段,只保留线段的端点。通过max(contours, key=cv2.contourArea)
找到最大面积的轮廓,即为文档轮廓。
通过以上步骤,我们实现了一个简单的文档扫描器,能够对拍摄的文档图像进行矫正、文字区域提取和轮廓检测,为后续的 OCR 识别等应用奠定了基础。在实际应用中,还可以进一步优化代码,如调整参数以适应不同场景的文档图像,增加图像预处理步骤以提高处理效果等。
八、总结与资源推荐
8.1 30 天学习路线图
阶段 | 内容重点 | 推荐项目 |
---|---|---|
基础阶段 | 环境搭建、图像读取、几何变换 | 图片旋转器 |
核心阶段 | 像素操作、滤波、阈值处理 | 图像去噪器 |
进阶阶段 | 特征检测、轮廓分析 | 形状分类器 |
实战阶段 | 视频处理、综合项目 | 实时人脸检测系统 |
8.2 学习资源
OpenCV 官方文档:https://docs.opencv.org,这是最权威的学习资料,包含了详细的函数说明、算法原理和示例代码。
数据集:MNIST、COCO ,MNIST 是一个手写数字图像数据集,常用于图像识别和分类任务的入门练习;COCO 是一个大型的目标检测、分割和字幕数据集,涵盖了丰富的图像内容和标注信息,对于实战项目的训练和评估非常有帮助。
工具:LabelMe(数据标注)、VS Code(代码调试),LabelMe 是一款简单易用的数据标注工具,可用于标注图像中的目标物体,为机器学习模型的训练准备数据;VS Code 是一款功能强大的代码编辑器,支持 Python 等多种编程语言,具备智能代码补全、调试、版本控制等功能,能够大大提高开发效率 。
8.3 学习资料视频文档下载
关于 计算机视觉相关资料 放网盘了,需要的自取,建议先保存到自己的网盘,网盘数据如果找不见了,联系博主免费获取!
- 资料教程1:计算机视觉-Opencv项目实战(Python版) - 带源码课件
- 资料教程2:CV计算机视觉集训营(视频)
- 资料教程3:计算机视觉应用基础 - 带源码课件
致读者一封信
亲爱的朋友,无论前路如何漫长与崎岖,都请怀揣梦想的火种,因为在生活的广袤星空中,总有一颗属于你的璀璨星辰在熠熠生辉,静候你抵达。
愿你在这纷繁世间,能时常收获微小而确定的幸福,如春日微风轻拂面庞,所有的疲惫与烦恼都能被温柔以待,内心永远充盈着安宁与慰藉。
至此,文章已至尾声,而您的故事仍在续写,不知您对文中所叙有何独特见解?期待您在心中与我对话,开启思想的新交流。
💞 关注博主 带你实现畅游前后端
🏰 大屏可视化 带你体验酷炫大屏
💯 神秘个人简介 带你体验不一样得介绍
🎀 酷炫邀请函 带你体验高大上得邀请
① 🉑提供云服务部署;
② 🉑提供前端、后端、应用程序、H5、小程序、公众号等相关业务;
③ 🉑提供产品测评,产品推广业务;
如🈶合作请联系我,期待您的联系。
注:本文撰写于CSDN平台,作者:xcLeigh(所有权归作者所有) ,https://xcleigh.blog.csdn.net/,如果相关下载没有跳转,请查看这个地址,相关链接没有跳转,皆是抄袭本文,转载请备注本文原地址。
亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请留言(评论),博主看见后一定及时给您答复,💌💌💌
原文地址:https://xcleigh.blog.csdn.net/article/details/146854132(防止抄袭,原文地址不可删除)