使用OpenCV对图像进行处理:图像处理中的几何变换、形态学操作、图像平滑、直方图分析和边缘检测等关键技术
本文介绍了图像处理中的几何变换、形态学操作、图像平滑、直方图处理、边缘检测、模板匹配和霍夫变换等核心技术。主要内容包括: 几何变换:缩放(不同插值方法)、平移、旋转、仿射变换和透视变换的实现与应用; 形态学操作:腐蚀/膨胀、开闭运算、礼帽/黑帽运算的原理和使用场景; 图像平滑:均值滤波、高斯滤波和中值滤波处理图像噪声的方法; 直方图处理:灰度直方图计算、均衡化及自适应均衡化技术; 边缘检测:Sob
一.几何变换
1.图像缩放
(1)对图像进行放大缩小
cv2.resize(src,dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)
在其中,各个参数的含义如下
src:选择要处理的图像
dsize:直接指定调整后图像的大小
fx,fy:将dsize设置为none,随后更改这个数值
interpolation:插值方法
cv2.INTER_LINEAR:双线性插值法
cv2:.INTER_NEAREST:最近邻插值法
cv2.INTER_AREA:像素区域重采样(默认)
cv2.INTER_CUBIC:双三次插值
-
最近邻插值(cv2.INTER_NEAREST)
- 原理:选取距离目标像素最近的原图像像素值作为输出。
- 特点:计算过程简单,速度快,但在图像放大时容易产生锯齿状或块状的失真现象。
- 适用情况:适用于对处理速度要求高,且对图像质量要求不高的场景,像游戏画面的简单缩放。
-
双线性插值(cv2.INTER_LINEAR)
- 原理:基于目标像素周围 4 个点的像素值,通过加权平均的方式来计算输出值。
- 特点:计算量不大,图像质量较好,缩放后的图像比较平滑。
- 适用情况:是图像缩放时的常用方法,尤其适用于放大操作,在速度和质量之间能取得较好的平衡。
-
双三次插值(cv2.INTER_CUBIC)
- 原理:依据目标像素周围 16 个点的像素值,进行三次多项式插值计算。
- 特点:计算量相对较大,但图像质量更高,能够保留更多的细节信息。
- 适用情况:适用于对图像质量要求较高的场景,如医学图像处理、图像编辑等。
-
像素区域重采样(cv2.INTER_AREA)
- 原理:此方法基于局部像素区域关系进行重采样,类似于积分图算法。
- 特点:在图像缩小时可以有效避免波纹效应,在放大时效果与最近邻插值相近。
- 适用情况:是图像缩小操作时的默认方法,适合需要保持图像细节的降采样处理。
若要进行图像缩小,优先考虑使用 cv2.INTER_AREA。
若要进行图像放大,推荐使用 cv2.INTER_CUBIC(注重质量)或 cv2.INTER_LINEAR(注重速度)。
在实时处理等对速度要求极高的场景下,可以考虑使用 cv2.INTER_NEAREST。
(2)举例
a.使用OpenCV展示缩放图片
import cv2
#读取图片
img1 = cv2.imread("./image/1.jpg")
#图像缩放
#1.绝对尺寸
rows,cols = img1.shape[:2]#获取当前图片的行数,列数
res = cv2.resize(img1,(2*cols,2*rows),interpolation=cv2.INTER_CUBIC)
#相对尺寸
res1 = cv2.resize(img1,None,fx=0.5,fy=0.5)
#图像显示
cv2.imshow("yuantu",img1)
cv2.imshow("juedui",res)
cv2.imshow("xiangdui",res1)
cv2.waitKey(0)

b.使用matplotlib展示图片
import cv2
#读取图片
import matplotlib.pyplot as plt
img1 = cv2.imread("./image/1.jpg")
#图像缩放
#1.绝对尺寸
rows,cols = img1.shape[:2]#获取当前图片的行数,列数
res = cv2.resize(img1,(2*cols,2*rows),interpolation=cv2.INTER_CUBIC)
#相对尺寸
res1 = cv2.resize(img1,None,fx=0.5,fy=0.5)
#使用matplotlib对图像进行展示
fig,axes = plt.subplots(nrows=1,ncols=3,figsize=(20,10),dpi=100)
axes[0].imshow(res[:,:,::-1])
axes[0].set_title("juedui")
axes[1].imshow(img1[:,:,::-1])
axes[1].set_title("yuan")
axes[2].imshow(res1[:,:,::-1])
axes[2].set_title("suoxiao")
plt.show()

2,图像平移
(1)将图像按照指定方向和距离,移动到相应的位置
cv2.warpAffine(img,M,dsize)
参数的含义:
img:选择要平移的图像
M:2*3移动矩阵
对于(x,y)里的像素点,要把他移动到(x+t,y+t)处时,应该设置成
M = [[1, 0, tx], [0, 1, ty]] 注意:将M设置成np.float32类型的Numpy数组
dzise:输出图像的大小 注意:这里的大小是(宽度,高度)的形式,width=列数,height=行数
(2)举例演示
将图像像素点移动(50,100)的距离
import numpy as np
import cv2
import matplotlib.pyplot as plt
#读取图像
img1 = cv2.imread("./image/1.jpg")
#图像平移
rows,cols = img1.shape[:2]#获取当前图片的行数,列数
M = np.float32([[1,0,100],[0,1,50]])#平移矩阵
dst = cv2.warpAffine(img1,M,(cols,rows))
#图像显示
fig,axes = plt.subplots(nrows=1,ncols=3,figsize=(20,10),dpi=100)
axes[0].imshow(img1[:,:,::-1])
axes[0].set_title("yuantu")
axes[1].imshow(dst[:,:,::-1])
axes[1].set_title("xiugai")
plt.show()

3.图像旋转
图像旋转是一种基本的几何变换,它将图像绕某个点(通常是图像中心)旋转指定角度。旋转操作会改变图像中像素的位置,同时保持图像的基本结构特征。
cv2.getRotationMatrix2D
(center, angle, scale)
其中,参数:
center:旋转的中心
angle:旋转的角度
scale:缩放的比例
举例
import numpy as np
import cv2
import matplotlib.pyplot as plt
#读取图像
img = cv2.imread("./image/1.jpg")
#图像旋转
rows,cols = img.shape[:2]#获取当前图片的行数,列数
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
#进行旋转变化
dst = cv2.warpAffine(img,M,(cols,rows))
#图像显示
fig,axes = plt.subplots(nrows=1,ncols=3,figsize=(20,10),dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("yuantu")
axes[1].imshow(dst[:,:,::-1])
axes[1].set_title("xiugai")
plt.show()

4.图像的仿射变换
图像的仿射变换是一种二维坐标到二维坐标之间的线性变换,它保持了图像的 “平直性”(直线变换后仍为直线)和 “平行性”(平行线变换后仍为平行线)。仿射变换可以通过一个 2×3 的变换矩阵实现,该矩阵包含了旋转、平移、缩放、剪切等基本变换的组合
import numpy as np
import cv2
import matplotlib.pyplot as plt
#读取图像
img = cv2.imread("./image/1.jpg")
#仿射变换
rows,cols = img.shape[:2]#获取当前图片的行数,列数
#创建变换矩阵
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[100,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(cols,rows))
ig,axes = plt.subplots(nrows=1,ncols=3,figsize=(20,10),dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("yuantu")
axes[1].imshow(dst[:,:,::-1])
axes[1].set_title("xiugai")
plt.show()

5.图像的投射变换
透视变换是将三维空间中的物体通过透视投影映射到二维平面时,因观察角度不同而产生的形状变化的逆过程 —— 简单说,它能将 “倾斜视角下的图像” 校正为 “正视角下的图像”,本质是对透视投影的 “反向修正”。
cv2.getPerspectiveTransform(src, dst):计算从源点到目标点的 3x3 透视变换矩阵
cv2.warpPerspective(img, M, dsize):应用透视变换,dsize 为输出图像的尺寸
import numpy as np
import cv2
import matplotlib.pyplot as plt
#读取图像
img = cv2.imread("./image/1.jpg")
#仿射变换
rows,cols = img.shape[:2]#获取当前图片的行数,列数
#创建变换矩阵
pts1 = np.float32([[56,65],[368,52],[20,307],[389,390]])
pts2 = np.float32([[100,145],[300,100],[80,290],[310,300]])
T = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,T,(cols,rows))
ig,axes = plt.subplots(nrows=1,ncols=3,figsize=(20,10),dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("yuantu")
axes[1].imshow(dst[:,:,::-1])
axes[1].set_title("xiugai")
plt.show()

6.图像金字塔
cv2.pyrUp(img)
cv2.pyrDown(img)
图像金字塔(Image Pyramid)是图像处理和计算机视觉中一种多尺度表示图像的技术,通过对原始图像进行逐级降采样(缩小)或升采样(放大),生成一组不同分辨率的图像,形似 “金字塔” 结构。这些不同分辨率的图像可用于多种场景,如目标检测、图像融合、特征提取等。
import numpy as np
import cv2
import matplotlib.pyplot as plt
#读取图像
img = cv2.imread("./image/1.jpg")
up_img = cv2.pyrUp(img)
img_1 = cv2.pyrDown(img)
cv2.imshow("up",up_img)
cv2.imshow("yuantu",img)
cv2.imshow("down",img_1)
cv2.waitKey(0)
cv2.destroyWindow()

二.关于形态学操作
1.连通性
邻域模型
4邻接:旁边四个
D邻接:对角线四个
8邻接:周围所有的
根据连通性的定义
4联通:如果处于4邻接其中之一,就是4联通
8联通:如果处于旁边邻接的任何一个
2.形态学操作
(1)腐蚀和膨胀
a.腐蚀
图像的腐蚀(Erosion)是数字图像处理中形态学操作的基础技术之一,主要用于收缩或细化图像中的前景区域(通常假设前景为白色,背景为黑色)。它的核心思想类似于 “侵蚀”—— 用一个结构化元素(称为 “核”)扫描图像,通过判断核覆盖区域内的像素是否完全满足条件(如均为前景),来决定输出像素的值。
cv2.erode(img,kernel,iterations)
img:要处理的照片
kernel:核结构
iterations:腐蚀的次数,默认是1
b.膨胀
图像的膨胀(Dilation)是数字图像处理中形态学操作的另一种基础技术,与腐蚀(Erosion)互为补充,主要用于扩张或加粗图像中的前景区域(通常假设前景为白色,背景为黑色)。它的核心思想类似于 “扩张”—— 用一个结构化元素(核)扫描图像,通过判断核覆盖区域内的像素是否存在前景像素,来决定输出像素的值。
cv2.dilate(img,kernel,iterations)
img:要处理的照片
kernel:核结构
iterations:腐蚀的次数,默认是1
举例
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt #1读取图像
img =cv.imread("./image/1.jpg")
#2创建核结构
kernel = np.ones((5,5),np.uint8)
#3图像腐蚀和膨胀
erosion = cv.erode(img,kernel) #腐蚀
dilate = cv.dilate(img,kernel) #膨胀
#4图像展示
fig,axes=plt.subplots(nrows=1,ncols=3,figsize=(10,8),dpi=100)
axes[0].imshow(img)
axes [0].set_title("yuan")
axes[1].imshow(erosion)
axes[1].set_title("fushi")
axes[2].imshow(dilate)
axes[2].set_title("pengzhang")
plt.show()

(2)开闭运算
a.开运算
图像的开运算(Opening Operation)是数字图像处理中形态学操作的一种,由腐蚀(Erosion)和膨胀(Dilation)两个基本操作组合而成。其核心思想是先对图像进行腐蚀,再对结果进行膨胀,常用于去除小噪声、分离物体、平滑轮廓等场景。
b.闭运算
图像的闭运算(Closing Operation)是数字图像处理中形态学操作的一种,由膨胀(Dilation)和腐蚀(Erosion)两个基本操作组合而成。其核心思想是先对图像进行膨胀,再对结果进行腐蚀,常用于填补内部空洞、连接断裂部分、平滑轮廓等场景。
cv2.morphologyEx(img,op,kernel)
img:要处理的照片
op:处理的方式
若进行开运算则选择cv2.MORPH_OPEN
若进行闭运算则选择cv2.MORPH_CLOSE\
kernel:核结构
举例
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt#1读取图像
img1 = cv.imread("./image/1.jpg")
img2 = cv.imread("./image/1.jpg")#2创建核结构
kernel = np.ones((10, 10),np.uint8)#3图像的开闭运算
cvOpen = cv.morphologyEx(img1,cv.MORPH_OPEN,kernel) #开运算
cvClose = cv.morphologyEx(img2,cv.MORPH_CLOSE,kernel)#闭运算#4图像展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img1)
axes[0,0].set_title("yuan")
axes[0,1].imshow(cvOpen)
axes[0,1].set_title("kai")
axes[1,0].imshow(img2)
axes[1,0].set_title("yuan")
axes[1,1].imshow(cvClose)
axes[1,1].set_title("bi")
plt.show()

(3)礼帽和黑帽
a.礼帽运算
图像的礼帽运算(Top-Hat Transformation),也称为顶帽变换,是数字图像处理中形态学操作的一种,常用于突出图像中的细节部分(如小目标、纹理、噪声)或增强局部对比度。它基于开运算(Opening),通过计算原始图像与开运算结果的差值来实现。
礼帽运算的核心作用
-
提取小目标或细节:
开运算会去除图像中的小前景区域(如噪声点、细纹理),因此原始图像与开运算结果的差值即为被去除的小目标,常用于检测比结构化元素小的前景物体。 -
增强局部对比度:
在灰度图像中,礼帽运算可以突出比周围区域更亮的小区域,例如医学图像中的微钙化点、文本中的笔画细节等。 -
去除背景噪声:
若图像背景存在不均匀光照或大面积渐变,礼帽运算可分离出前景中的小目标,减少背景干扰。
礼帽运算的应用场景
-
文本检测:
- 从扫描文档中提取文字笔画(特别是细字体或低对比度文本);
- 去除背景中的网格线或水印,保留文字内容。
-
医学图像处理:
- 检测 X 光片或 CT 图像中的微小病变(如肺部小结节、乳腺钙化点);
- 增强细胞图像中的细节特征(如细胞核边缘)。
-
工业检测:
- 检测零件表面的划痕、凹陷等微小缺陷;
- 识别电路板上的焊点或线路细节。
-
遥感图像处理:
- 提取卫星图像中的小型建筑物、车辆或植被斑块。
b.黑帽运算
图像的黑帽运算(Black-Hat Transformation)是数字图像处理中形态学操作的一种,与礼帽运算相对应,主要用于提取图像中比周围背景更暗的小区域、细节或纹理。它基于闭运算(Closing),通过计算闭运算结果与原始图像的差值实现。
cv2.morphologyEx(img,op,kernel)
img:要处理的照片
op:处理的方式
若进行开运算则选择cv2.MORPH_OPEN
若进行闭运算则选择cv2.MORPH_CLOSE
若进行礼帽运算则选择cv2.MORPH_TOPHAT
若进行黑帽运算则选择cv2.MORPH_BLACKHAT
kernel:核结构
举例
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt#1读取图像
img1 = cv.imread("./image/1.jpg")
img2=cv.imread("./image/1.jpg" )#2 创建核结构
kernel = np.ones((10,10),np.uint8)#3图像的礼帽和黑帽运算
cv0pen = cv.morphologyEx(img1,cv.MORPH_TOPHAT,kernel)#礼帽运算
cvClose = cv.morphologyEx(img2,cv.MORPH_BLACKHAT,kernel)#黑帽运算#4图像显示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img1)
axes[0,0].set_title("yuan")
axes[0,1].imshow(cv0pen)
axes[0,1].set_title("limao")
axes[1,0].imshow(img2)
axes[1,0].set_title("yuan")
axes[1,1].imshow(cvClose)
axes[1,1].set_title("black")
plt.show()

三.图像平滑操作
1.图像噪声
(1)椒盐噪声
椒盐噪声(Salt-and-Pepper Noise)是数字图像中常见的一种脉冲噪声,因噪声在图像中呈现为随机分布的白色亮点(盐噪声)和黑色暗点(椒噪声)而得名,形似 “盐粒” 和 “胡椒粒” 散落在图像上。
(2)高斯噪声
高斯噪声(Gaussian Noise)是数字图像处理中最常见的加性噪声之一,其像素值的概率分布符合高斯分布(正态分布),广泛存在于各类图像中,对图像质量和后续处理有显著影响。
2.图像平滑简介
(1)均值滤波
均值滤波(Mean Filtering)是数字图像处理中最基础的线性平滑滤波方法,通过计算像素邻域内的平均值来替代当前像素值,主要用于降低图像噪声和模糊图像。它的核心思想是 “平均化”,即通过邻域像素的集体信息来抑制个体噪声点的影响。(计算速度快但比较模糊)
均值滤波的原理
均值滤波基于一个固定大小的滑动窗口(如 3×3、5×5 的矩阵),其操作步骤为:
- 将窗口中心对准当前像素;
- 计算窗口内所有像素的灰度平均值(或彩色图像中每个通道的平均值);
- 用该平均值替换当前像素值。
cv2.blur(src,ksize,anchor,borderType)
src:输入的图像
ksize:卷积核的大小
anchor:默认是(-1,-1)表示核中心
borderType:边界类型
举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt# 1图像读取
img = cv.imread('./image/1.jpg')#.2 均值滤波
blur = cv.blur(img,(5,5))#3图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('yuan')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('hou')
plt.xticks([]),plt.yticks([])
plt.show()
(2)高斯滤波
高斯滤波(Gaussian Filtering)是数字图像处理中常用的线性平滑滤波方法,通过对图像邻域像素进行加权平均(权重服从高斯分布)来实现降噪和平滑,是均值滤波的 “升级版”。它在抑制噪声的同时,能更好地保留图像边缘和细节,因此广泛应用于图像预处理、特征提取等领域。
cv2.GaussianBlur(src,ksize,sigmaX,sigmay,borderType)
src:要输入的图片
ksize:高斯卷积核的大小(卷积核的高度和宽度都应该为奇数,且可以不同)
sigmaX:水平方向的标准差
sigmay:垂直方向的标准差默认为0
borderType:边界类型
举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt#1图像读取
img = cv.imread('./image/1.jpg')#2高斯滤波
blur =cv.GaussianBlur(img,(3,3),1)#3图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('yuan')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img[:,:,::-1]),plt.title("hou")
plt.xticks([]),plt.yticks([])
plt.show()
(3)中值滤波
中值滤波(Median Filtering)是一种基于排序统计的非线性滤波方法,核心原理是用像素邻域内所有像素值的中值替换该像素的值,从而有效抑制脉冲噪声(如椒盐噪声),同时较好地保留图像边缘细节。与均值滤波、高斯滤波等线性滤波相比,中值滤波对异常值(噪声)更不敏感,在特定场景下降噪效果更优。
cv2.medianBlur(src,ksize)
src:要输入的图片
ksize:卷积核的大小
举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt#1图像读取
img = cv.imread('./image/1.jpg')#2滤波
blur =cv.medianBlur(img,5)#3图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('yuan')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img[:,:,::-1]),plt.title("hou")
plt.xticks([]),plt.yticks([])
plt.show()
四.直方图
1.灰度直方图
(1)原理
直方图(Histogram)是一种用于展示数据分布特征的统计图表,其核心原理是通过将数据分组并统计每组的频数(或频率),直观呈现数据在不同区间的分布规律。无论是连续数据还是离散数据,直方图都能清晰反映数据的集中趋势、离散程度、峰值数量等关键特征,广泛应用于统计分析、图像处理、数据挖掘等领域。
直方图的核心原理
-
数据分组( bins 划分)
直方图的第一步是对原始数据进行 “分组”:- 将数据的取值范围划分为若干个连续且不重叠的区间(称为 “bins”,即 “箱” 或 “组”),每个区间的宽度可以相等(最常见),也可根据数据特征设置不等宽区间。
- 例如,分析学生成绩(0-100 分)时,可按 10 分为一组,划分为 [0,10)、[10,20)、…、[90,100] 共 10 个区间。
-
频数统计
对每个区间,统计落入该区间内的数据个数(即 “频数”),或计算频数占总数据量的比例(即 “频率”)。- 频数:某区间内数据的数量(如 [80,90) 区间有 25 人,频数为 25;
- 频率:频数 / 总数据量(如总人数 100,[80,90) 区间频率为 25%)。
-
可视化呈现
以区间为横轴(表示数据的取值范围),频数 / 频率为纵轴,每个区间对应一个矩形(“柱子”),矩形的高度代表该区间的频数 / 频率,宽度代表区间范围。通过柱子的高低和分布,可直观判断数据的集中位置、分散程度、是否对称等特征。
直方图的构建步骤(以连续数据为例)
-
确定数据范围
找出数据中的最小值(min)和最大值(max),明确数据的整体分布区间[min,max]。
例如:一组学生成绩数据为[65,72,88,95,50,60,78,82,90,75],最小值 50,最大值 95,范围为 [50,95]。 -
划分数据区间( bins )
- 区间数量(或宽度)需根据数据量和分布特征确定:太少会掩盖细节,太多则导致分布杂乱。
- 常用方法:
- 等宽划分:区间宽度 =(最大值 - 最小值)/ 区间数量(如将 [50,95] 分为 5 个区间,宽度为 9,区间为 [50,59)、[59,68)…);
- 自适应划分:根据数据密度调整区间(如使用 Sturges 公式:区间数 ≈ 1 + log₂N,N 为数据量)。
-
统计每个区间的频数
遍历所有数据,统计每个数据落入哪个区间,并记录该区间的频数。
例如:上述成绩数据中,[70,80) 区间包含 72、78、75,频数为 3。 -
绘制直方图
横轴标注区间,纵轴标注频数(或频率),每个区间对应一个矩形,矩形的底边覆盖整个区间,高度与频数成正比。
直方图的核心作用
-
揭示数据分布特征
- 集中趋势:数据主要集中在哪个区间(如成绩集中在 [70,90),说明整体成绩较好);
- 离散程度:数据是否分散(如区间跨度大、频数分布均匀,说明数据离散程度高);
- 分布形态:
- 对称分布(如正态分布,左右两侧大致对称);
- 偏态分布(左偏 / 右偏,如收入数据多为右偏,少数人收入极高);
- 峰值数量(单峰、双峰等,如学生成绩可能呈现 “两极分化” 的双峰分布)。
-
数据异常检测
直方图中若某区间频数极低(甚至为 0),或出现远离主要分布的 “孤立区间”,可能提示存在异常值(如数据录入错误)。 -
辅助决策
- 例如:通过商品销量直方图判断热销价格区间,指导定价策略;
- 通过图像灰度直方图分析亮度分布,辅助图像增强(如直方图均衡化)。
直方图的应用场景
- 统计分析:展示身高、体重、成绩等数据的分布(如 “成年人身高多集中在 160-180cm”);
- 图像处理:灰度直方图用于描述图像中像素亮度的分布(亮部 / 暗部占比),是图像增强、阈值分割的基础;
- 质量控制:生产数据的直方图可判断产品指标是否符合正态分布(如零件尺寸误差);
- 机器学习:特征直方图用于分析特征分布,指导特征工程(如判断是否需要归一化、处理异常值)。
与条形图的区别(避免混淆)
| 特征 | 直方图 | 条形图 |
|---|---|---|
| 数据类型 | 连续数据(区间分组) | 离散数据(类别) |
| 横轴含义 | 数据区间(连续,无间隔) | 类别(离散,可间隔) |
| 矩形关系 | 相邻矩形无缝连接(区间连续) | 矩形独立分隔(类别互斥) |
| 核心作用 | 展示数据分布规律 | 比较不同类别的数值大小 |
(2)直方图的计算和绘制
cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]]
images:原图像 【img】
channels:如果输入图像是灰度图就是【0】,如果是彩色可以【0】,【1】,【2】分别对应B,G,R
mask:掩膜图像
histSize:bin的数目
ranges:像素值范围
举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#直接以灰度图的方式读入
img = cv.imread('./image/1.jpg',0)
histr = cv.calcHist([img],[0],None,[256],[0,256])
plt.figure(figsize=(10,6),dpi=100)
plt.plot(histr)
plt.grid()
plt.show()

(3)掩膜的应用
掩膜(Mask)是一种通过遮挡或标记特定区域来实现 “选择性处理” 的技术,广泛应用于计算机视觉、图像处理、遥感、医学影像、工业检测等领域。其核心思想是定义一个与目标数据(如图像、矩阵)尺寸相同的 “模板”,通过模板中的 “有效区域”(如像素值为 1)和 “无效区域”(如像素值为 0),控制对原始数据的处理范围 —— 仅对有效区域执行操作,无效区域则被忽略或保留原始状态。
掩膜的核心作用
- 区域选择:精准圈定需要处理的目标区域(如图像中的人脸、遥感图像中的建筑),排除无关背景干扰;
- 特征提取:通过特定形状的掩膜(如边缘检测算子)突出数据中的关键特征(如纹理、边缘);
- 数据过滤:屏蔽无效或噪声区域,仅保留有效信息(如医学影像中去除骨骼区域,专注于软组织)。
示例
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1. 直接以灰度图的方式读入
img = cv.imread('./image/1.jpg',0)
#2.创建蒙版
mask = np.zeros(img.shape[:2],np.uint8)
mask[400:650,200:500]=255
# 3.掩模
masked_img = cv.bitwise_and(img,img,mask= mask)
# 4.统计掩膜后图像的灰度图
mask_histr =cv.calcHist([img],[0],mask,[256],[1,256])
# 5.图像展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img,cmap=plt.cm.gray)
axes[0,0].set_title("yuan")
axes[0,1].imshow(mask,cmap=plt.cm.gray)
axes[0,1].set_title("mengban")
axes[1,0].imshow(masked_img,cmap=plt.cm.gray)
axes[1,0].set_title("yanmo")
axes[1,1].plot(mask_histr)
axes[1,1].grid()
axes[1,1].set_title("huidu")
plt.show()

2.直方图的均衡化
(1)应用
dst = cv2.equalizeHist(img)
img:灰度图像
dst:均衡化后的结果
举例
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1.直接以灰度图的方式读入
img = cv.imread('./image/1.jpg',0)
# 2.均衡化处理
dst = cv.equalizeHist(img)
# 3.结果展示
plt.imshow(img,cmap=plt.cm.gray)
plt.imshow(dst,cmap=plt.cm.gray)
plt.show()

(2)自适应的直方图均衡化
自适应直方图均衡化(Adaptive Histogram Equalization,AHE)是一种改进的直方图均衡化技术,旨在解决传统直方图均衡化(Global Histogram Equalization)在增强图像对比度时容易过度放大噪声、导致局部细节失真的问题。其核心思想是将图像分割为多个子区域(称为 “块” 或 “tiles”),对每个子区域单独进行直方图均衡化,并通过插值处理消除子区域边界的突变,从而更精细地增强图像局部对比度。
cv2.createCLAHE(cliplimit,tileGridSize)
cliplimit:对比度限制,默认40
tileGridSize:分块的大小,默认8*8
举例
from matplotlib import pyplot as plt
import numpy as np
import cv2 as cv
#.1.以灰度图形式读取图像
img = cv.imread('./image/1.jpg',0)
# 2. 创建一个自适应均衡化的对象,并应用于图像
cl =cv.createCLAHE(2.0,(8,8))
clahe = cl.apply(img)
# 3.图像展示
plt.imshow(clahe,cmap=plt.cm.gray)
plt.show()
五.边缘检测
1.原理
边缘检测是计算机视觉和图像处理中的核心技术,用于识别图像中灰度值发生剧烈变化的区域(即 “边缘”),这些区域通常对应物体的轮廓、不同区域的边界或场景中的结构变化。其核心原理是通过数学方法捕捉图像中灰度的突变,将连续的图像信息转化为离散的边缘特征。
| 算子类型 | 原理 | 特点 |
|---|---|---|
| Sobel 算子 | 用 3×3 卷积核分别计算 x 和 y 方向的梯度(加权平均 + 差分),再合成梯度大小。 | 对噪声有一定抑制能力,计算简单,边缘较粗,适合快速检测。 |
| Prewitt 算子 | 用 3×3 卷积核计算 x 和 y 方向的梯度(均匀加权差分)。 | 比 Sobel 更简单,但对噪声更敏感。 |
| Canny 算子 | 多步骤优化:高斯滤波降噪 → 计算梯度 → 非极大值抑制(细化边缘) → 双阈值筛选(保留强边缘,连接弱边缘)。 | 检测精度高,边缘连续且单像素宽,抗噪声能力强,是目前最常用的算子之一。 |
| Laplacian 算子 | 基于二阶导数(灰度变化率的变化),对阶跃边缘的响应为零交叉点(正负变化处)。 | 对噪声非常敏感,需先强滤波,适合检测细线边缘。 |
| Roberts 算子 | 用 2×2 卷积核计算对角线方向的梯度(差分)。 | 计算速度快,但抗噪声能力差,边缘粗糙。 |
2.sobel检测算子
Sobel_x_or_y = cv2.Sobel(src,ddepth,dx,dy,dst,ksize,scale,delta,borderType)
src:传入的图像
ddepth:图像的深度
dx:求导的阶数,0表示这个方向上没有求导
dy:求导的阶数,0表示这个方向上没有求导
ksize:sobel算子的大小,卷积核的大小,必须奇数13579,默认为3
scale:缩放导数的比例常数,默认情况为没有伸缩系数
borderType:图像边界的模式,默认为cv2.BORDER_DEFAULT
举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#1该取图像
img = cv.imread("./image/1.jpg",0)
# 2计算Sobel卷积结果
x = cv.Sobel(img,cv.CV_16S,1,0)
y = cv.Sobel(img,cv.CV_16S,0,1)
#3杯数进转换
Scale_absX = cv.convertScaleAbs(x)# convert 转换 scale 细放
Scale_absY = cv.convertScaleAbs(y)
#4结果合成
result = cv.addWeighted(Scale_absX,0.5,Scale_absY,0.5,0)
#5图像显示
plt.imshow(result,cmap=plt.cm.gray),plt.title("yuan")
plt.show()

3.laplacian算子
利用二阶导数来检测边缘
laplacian = cv2.laplacian(src,ddepth[,dst[,ksize[,scale[,delta[,borderType]]]]])
src:传入的图像
ddepth:图像的深度
ksize:算子的大小,卷积核的大小
举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 读取图像
img =cv.imread('./image/1.jpg',0)
# 2 laplacian转换
result = cv.Laplacian(img,cv.CV_16S)
Scale_abs = cv.convertScaleAbs(result)#3图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('YUAN')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(Scale_abs,cmap = plt.cm.gray),plt.title('Laplacian')
plt.xticks([]),plt.yticks([])
plt.show()

4.Canny边缘检测(最优)
Canny 边缘检测是一种经典的多阶段图像处理算法,旨在高效、准确地检测图像中的真实边缘,同时抑制噪声和虚假边缘。由 John F. Canny 在 1986 年提出,该算法基于严格的数学优化理论,通过多阶段处理平衡了边缘检测的三大目标:低错误率(不漏检真实边缘,不误检非边缘)、边缘定位精确(检测到的边缘与真实边缘位置偏差小)、单像素响应(每个边缘仅由一个像素表示)。
Canny 边缘检测的核心流程
Canny 算法通过以下五个步骤实现高精度边缘检测:
1. 高斯平滑(Gaussian Smoothing)
- 目的:减少图像噪声对边缘检测的干扰(噪声会导致虚假边缘)。
- 操作:用高斯核(如 3×3、5×5)对图像进行卷积,平滑图像的同时保留主要边缘信息。
- 参数影响:高斯核的标准差 σ 越大,平滑效果越强,但可能模糊真实边缘;通常 σ=1.0~1.5。
2. 计算梯度(Gradient Calculation)
- 目的:通过梯度计算定位图像中灰度值变化剧烈的区域(即边缘)。
- 操作:
- 计算梯度幅值:用 Sobel 算子(或其他算子)分别计算水平(Gₓ)和垂直(Gᵧ)方向的梯度,合成梯度幅值
G = √(Gₓ² + Gᵧ²); - 计算梯度方向:
θ = arctan(Gᵧ/Gₓ),四舍五入到四个方向之一(0°, 45°, 90°, 135°),对应水平、对角线、垂直、反对角线方向。
- 计算梯度幅值:用 Sobel 算子(或其他算子)分别计算水平(Gₓ)和垂直(Gᵧ)方向的梯度,合成梯度幅值
3. 非极大值抑制(Non-Maximum Suppression)
- 目的:将模糊的 “宽边缘” 细化为单像素宽的边缘(保留局部梯度最大值点,抑制其他点)。
- 操作:
- 遍历每个像素,根据其梯度方向(θ),检查该像素在梯度方向上的相邻两个像素;
- 若当前像素的梯度幅值不大于相邻像素,则将其值设为 0(抑制非极大值),否则保留原值。
- 效果:仅保留梯度方向上的局部最大值点,形成单像素宽的边缘。
4. 双阈值筛选(Double Thresholding)
- 目的:区分 “强边缘”(确定为真实边缘)和 “弱边缘”(可能是真实边缘或噪声),并通过连接规则保留真实边缘。
- 操作:
- 设置两个阈值:高阈值(
TH)和低阈值(TL),通常TH = 2×TL(如TL=50,TH=100); - 梯度幅值 >
TH的像素被标记为强边缘(确定的真实边缘); - 梯度幅值在
TL和TH之间的像素被标记为弱边缘(需进一步验证); - 梯度幅值 <
TL的像素被抑制(视为噪声)。
- 设置两个阈值:高阈值(
5. 边缘连接(Edge Tracking by Hysteresis)
- 目的:将弱边缘连接到强边缘,形成完整的边缘轮廓(弱边缘可能是强边缘的延续,也可能是噪声)。
- 操作:
- 遍历所有弱边缘像素,检查其 8 邻域内是否存在强边缘像素;
- 若存在,则将该弱边缘像素标记为真实边缘(连接到强边缘);否则抑制该弱边缘(视为噪声)。
参数选择与优化
Canny 算法的效果高度依赖以下参数:
- 高斯核大小:通常为 3×3 或 5×5,σ=1.0~1.5,需平衡降噪与边缘保留。
- 双阈值(
TL和TH):- 高阈值(
TH)控制边缘检测的严格程度:过高会漏检边缘,过低会引入噪声; - 低阈值(
TL)影响边缘连接的完整性:过低会导致噪声被连接,过高会使边缘断裂。 - 经验值:对于 8 位图像(0~255 灰度),
TL=50,TH=100是常用初始值,需根据图像特性调整。
- 高阈值(
Canny 算法的优缺点
优点
- 高精度:通过多阶段处理,有效平衡了边缘检测的三大目标(低错误率、精确定位、单像素响应)。
- 抗噪声能力强:高斯平滑和双阈值机制能有效抑制噪声,保留真实边缘。
- 参数可调整:通过调整高斯核和阈值,可适应不同类型的图像(如医学影像、遥感图像)。
缺点
- 计算复杂度高:相比简单算子(如 Sobel),Canny 算法需多次遍历图像,计算开销较大。
- 参数敏感:双阈值的选择需人工经验,对不同图像可能需反复调参才能获得最佳效果。
应用场景
Canny 边缘检测广泛应用于需要高精度边缘的场景:
- 计算机视觉:目标识别(如人脸轮廓提取)、图像分割的预处理。
- 医学影像:X 光、CT 图像中的器官边界检测(如肺部轮廓、骨骼边缘)。
- 工业检测:产品表面缺陷检测(如裂纹、划痕的边缘识别)。
- 遥感图像:土地边界、建筑物轮廓的提取。
实现示例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#1图像读取
img = cv.imread('./image/1.jpg',0)
# 2 Canny边缘检测
lowThreshold = 0
max_lowThreshold = 100
canny = cv.Canny(img,lowThreshold,max_lowThreshold)
#图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('yuan')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow( canny,cmap = plt.cm.gray),plt.title('Canny')
plt.xticks([]),plt.yticks([])
plt.show()

六.模版匹配和霍夫变换
1.模版匹配
(1)原理
模版匹配是计算机视觉和图像处理中一种用于在目标图像中寻找与给定模版(参考图像)相似区域的技术,其核心原理是通过比较模版与目标图像中不同位置的相似度,来确定模版在目标图像中的位置。
实现流程:
准备俩付图像:原图像,在这附图中,找到与模版相匹配的区域
模版:与原图像进行对比的图像块
res = cv2.matchTemlate(img,template,method)
img:要进行模版匹配的图像
template:模版
method:实现模版匹配的算法
-
平方差匹配(SSD)
计算模版与子区域对应像素值差的平方和,公式为:SSD(x,y)=∑i,j[I(x+i,y+j)−T(i,j)]2- 数值越小,匹配度越高(完全匹配时为 0)。
- 缺点:对光照变化敏感。
2.相关匹配(CC)
计算模版与子区域的像素值乘积和,类似向量点积,公式为:CC(x,y)=∑i,j[I(x+i,y+j)⋅T(i,j)]
- 数值越大,匹配度越高(适用于亮度一致的场景)。
3.利用相关系数匹配(CV_TM_CCOEFF):利用模版与图像间的乘法进行匹配:1表示完美的匹配,-1表示最差的匹配
(2)举例
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#1图像和模板读取
img =cv.imread('./image/1.jpg')
template = cv.imread('./image/2.png')
h,w,l = template.shape
#2模板匹配
# 2.1 模板匹配
res =cv.matchTemplate(img, template, cv.TM_CCORR)
#2.2返回图像中最匹配的位置,确定左上角的坐标,并将匹配位置绘制在图像上
min_val, max_val, min_loc,max_loc = cv.minMaxLoc(res)#使用平方差时最小值为最佳匹配位置#
top_left = min_loc
top_left = max_loc
bottom_right = (top_left[0] +w,top_left[1] + h)
cv.rectangle(img, top_left, bottom_right,(0,255,0),2)#3图像显示
plt.imshow(img[:,:,::-1])
plt.title('jieguo'),plt.xticks([]),plt.yticks([])
plt.show()

2.霍夫变换
霍夫变换(Hough Transform)是计算机视觉中一种强大的特征检测技术,主要用于从图像中提取具有特定形状的目标,尤其擅长检测直线、圆、椭圆等几何形状。其核心原理是通过将图像空间中的特征点映射到参数空间,将 “检测图像中的形状” 转化为 “在参数空间中寻找峰值”,从而克服图像噪声、目标不完整等问题。
核心思想
在图像空间中,同一几何形状(如直线)上的点满足特定的数学方程。霍夫变换的关键是:
- 将图像空间中每个点的可能参数(如直线的斜率和截距)映射到参数空间,形成一条 “参数曲线”;
- 同一形状上的点在参数空间的曲线会相交于同一点(该点对应形状的真实参数);
- 通过统计参数空间中曲线的交点密度(峰值),即可确定图像中是否存在该形状及其实参数。
直线检测(最经典应用)
1. 直线的参数表示
在图像空间中,直线的常见表示方式有两种:
-
笛卡尔坐标系:y=kx+b(k为斜率,b为截距),但斜率k在直线垂直时为无穷大,不便于计算。
-
极坐标系(霍夫变换常用):xcosθ+ysinθ=ρ,其中:
- ρ:原点到直线的垂直距离(单位:像素);
- θ:垂线与x轴的夹角(范围:−90∘∼90∘ 或 0∼180∘)。
每个(ρ,θ)唯一确定一条直线,避免了斜率无穷大的问题。
2. 直线检测的步骤
- 预处理:对图像进行边缘检测(如 Canny 算子),得到边缘点集(仅保留可能在直线上的点)。
- 参数空间映射:
对每个边缘点(x0,y0),在参数空间(ρ,θ)中,所有满足ρ=x0cosθ+y0sinθ的(ρ,θ)构成一条正弦曲线(每个点对应一条曲线)。 - 投票统计:
用一个二维累加器(类似直方图)记录参数空间中曲线的交点次数:每有一条曲线经过(ρ,θ),累加器对应位置加 1。 - 提取峰值:累加器中数值超过阈值的点(ρ,θ),对应图像中存在的直线(数值越高,直线上的点越多,可信度越高)。
3.举例
import cv2
import numpy as np
# 读取图像
image = cv2.imread('road.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 边缘检测
edges = cv2.Canny(gray, 50, 150)
# 霍夫变换检测直线
lines = cv2.HoughLinesP(
edges, 1, np.pi/180,
threshold=100,
minLineLength=50,
maxLineGap=10
)
# 在原图上绘制直线
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
# 显示结果
cv2.imshow('Edges', edges)
cv2.imshow('Lines', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
圆检测
圆的数学方程为(x−a)2+(y−b)2=r2,其中(a,b)是圆心,r是半径。
- 参数空间:由(a,b,r)构成三维空间,每个边缘点(x,y)在参数空间中对应一个圆锥面(满足方程的(a,b,r)集合)。
- 检测步骤:
- 对每个边缘点,在可能的半径范围内,计算所有可能的(a,b)并在三维累加器中 “投票”;
- 累加器中峰值对应的(a,b,r)即为检测到的圆。
- 缺点:三维参数空间计算量大,实际中常通过限制半径范围或使用随机霍夫变换(RHT)优化效率。
举例
import cv2
import numpy as np
# 读取图像并转换为灰度图
img = cv2.imread('circles.jpg', 0)
img = cv2.medianBlur(img, 5) # 中值滤波减少噪点
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 转回BGR用于画圆
# 霍夫圆检测
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1,
20, # 圆心之间的最小距离
param1=50, # Canny边缘检测的高阈值
param2=30, # 累加器阈值,越小检测到的圆越多
minRadius=0, # 最小圆半径
maxRadius=0) # 最大圆半径(0表示无限制)
# 绘制检测到的圆
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# 绘制外圆
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
# 绘制圆心
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)
# 显示结果
cv2.imshow('Detected Circles', cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
优缺点
优点
- 对图像噪声、目标部分遮挡、边缘断裂不敏感,鲁棒性强;
- 能检测出完整或不完整的几何形状。
缺点
- 计算量大(尤其是高维参数空间,如圆、椭圆);
- 对参数范围敏感(需预先设定可能的参数范围,如直线的角度、圆的半径);
- 容易受非目标边缘点干扰,需结合阈值筛选。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)