opencv基础
一 参考教程:
- 菜鸟教程:
优:
较为全面,代码有现成的
缺点
:图画较少,要自己本地找些例子跑一跑 - b站快速入门opencv
二 图像基本操作
这个模块你将学习到::imshow(图片展示),imwrite(图片写入),imread(读取图片)
import cv2
_photo=cv2.imread("./saved_image.jpg")
if _photo is None:
print("图片没有找到")
# cv2.imshow("display",_photo)
(h,w)=_photo.shape[:2]
# print((h,w))
# cv2.waitKey(0)#如果没有这一行,直接跑的话,你会发现窗口一闪而过
cv2.imwrite("saved_30.jpg",_photo,[cv2.IMWRITE_JPEG_QUALITY,30])
#笔者突然好奇jpeg压缩质量差别真的很大吗?如下实验:
#实验1:
_photo1=cv2.imread("saved_30.jpg")
#_rephoto=cv2.resize(_photo1,(w,h))#注意这个resize的(w,h)顺序时候shape返回顺序相反
result=cv2.subtract(_photo,_photo1)#发现相减之后全是黑色,但其实并不能说明两者就是相同(虽然哪怕视觉效果也不大明显)
#实验二:
diff=cv2.absdiff(_photo,_photo1)
# result=cv2.bitwise_or(_photo,_rephoto)
#result=cv2.addWeighted(_photo,0.7,_rephoto,0.3,0)
cv2.imshow("display",result)
cv2.imshow("diff",diff*10)
cv2.waitKey(0)
cv2.destroyAllWindows()
原图:
diff跑出来的结果
:
二.图像阈值处理
import cv2
_photo=cv2.imread("image.png")
#简单阀值处理
_hphoto=cv2.cvtColor(_photo,cv2.COLOR_BGR2GRAY)#变为灰度,因为黑白之间更容易分辨
ret,thresh2=cv2.threshold(_hphoto,100,255,cv2.THRESH_BINARY)
#自适应阀值处理
thresh1=cv2.adaptiveThreshold(_hphoto,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)#如果用photo会发现发现报错,因为photo是彩色
#二值化
ret1,thresh3=cv2.threshold(_hphoto,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imshow("Binary Threshold",thresh3)
cv2.waitKey(0)
cv2.destroyAllWindows()
声明:图片来自上述B站视频截图
1原始图片:
2简单阈值
3自适应阈值
二值化(适合双峰处理,黑白分明)
关于代码中各个函数参数的解释:
以下是转换为 Markdown 格式的内容:
图像二值化相关参数说明
一、自适应阈值处理(cv2.adaptiveThreshold
)
输入要求:
_hphoto
:输入图像,必须为单通道灰度图像(uint8
类型)。若输入彩色图像,需先用cv2.cvtColor
转换为灰度图,否则会报错。
参数说明:
-
255
- 阈值最大值。超过阈值的像素值将设置为该值(即白色)。
-
cv2.ADAPTIVE_THRESH_GAUSSIAN_C
- 自适应阈值计算方法:
cv2.ADAPTIVE_THRESH_MEAN_C
:使用邻域内像素的均值减去常量C
作为阈值。cv2.ADAPTIVE_THRESH_GAUSSIAN_C
:使用邻域内像素的加权均值(权重为高斯分布减去常量C
作为阈值。
- 自适应阈值计算方法:
-
cv2.THRESH_BINARY
- 阈值类型:
cv2.THRESH_BINARY
:像素值 > 阈值时,设置为最大值(255
);否则设置为0
。cv2.THRESH_BINARY_INV
:与cv2.THRESH_BINARY
逻辑相反(像素值 > 阈值时设为0
,否则设为255
)。
- 阈值类型:
-
11
- 邻域大小(
blockSize
):计算阈值的像素邻域大小,必须为奇数(如3
、5
、7
等)。- 例:
11
表示以每个像素为中心,取 11×11 的邻域计算阈值。
- 例:
- 邻域大小(
-
2
- 常量
C
:从计算出的阈值中减去的值,用于微调结果。C > 0
:阈值降低;C < 0
:阈值升高。
- 常量
简单的说就是把一个图片分成若干个区域,将每个区域取平均来计算
二、大津算法自动阈值处理(cv2.threshold
+ cv2.THRESH_OTSU
)
输入要求:
_hphoto
:输入图像,必须为单通道灰度图像(uint8
类型)。
参数说明:
0
- 固定阈值。当使用
cv2.THRESH_OTSU
时,此值会被忽略,OpenCV 自动计算最佳阈值。
- 固定阈值。当使用
255
- 阈值最大值。超过阈值的像素值将设置为该值(即白色)。
cv2.THRESH_BINARY + cv2.THRESH_OTSU
- 阈值类型组合:
cv2.THRESH_BINARY
:像素值 > 阈值时设为255
,否则设为0
。cv2.THRESH_OTSU
:使用大津算法自动计算最佳阈值,适用于双峰图像(前景和背景像素值分布明显)。
- 阈值类型组合:
- 返回值:
ret1
:自动计算出的最佳阈值(仅在使用cv2.THRESH_OTSU
时返回)。thresh3
:二值化后的图像。
总结:
- 自适应阈值处理适用于局部光照不均匀的图像,通过邻域计算动态调整阈值。
- 大津算法适用于全局光照均匀且前景/背景分布明显的图像,自动获取最优全局阈值。(
前景后景的解释我也暂时还不理解,欢迎指教)
四 平滑处理
import cv2
_photo=cv2.imread("./image.png")
blurred_img=cv2.blur(_photo,(5,5))#均值模糊
Gau_img=cv2.GaussianBlur(_photo,(5,5),0)#高斯模糊
comined_img=cv2.hconcat([_photo,blurred_img])#双边模糊
cv2.imshow("display",comined_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
首先算法作用是类似的,刚入门的时候还暂时做不到依照特定场景使用特定的方法(起码我是这样的)
形象化理解(ai的解释,非常好,供参考):
1. 高斯模糊降噪(Gaussian Blur) 🌀
📌 费曼解释
高斯模糊就像戴上一副轻度磨砂的眼镜看图像——它通过加权平均周围像素来平滑图像,减少噪点(比如照片上的小颗粒)。
🔧 参数含义
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
- (5, 5):高斯核的大小(宽度和高度),必须是正奇数(如3×3、5×5)。
- 值越大,图像越模糊(比如(11,11)会更模糊)。
- 0:标准差(SigmaX)。
- 如果设为0,OpenCV会根据核大小自动计算。
- 手动设置时,值越大,模糊效果越明显。
🌰 生活类比
想象用喷雾瓶在玻璃上喷水雾:
- 核大小 = 喷雾的范围(喷得越广,玻璃越模糊)。
- 标准差 = 喷雾的密度(喷得越密,模糊效果越均匀)。
2. 定义核(Kernel) ⬛
📌 费曼解释
核是一个小矩阵,像一把小刷子,在图像上滑动做数学运算。它决定了形态学操作(如腐蚀、膨胀)的效果范围。
🔧 代码示例
kernel = np.ones((3, 3), np.uint8) # 3×3的全1矩阵
- (3, 3):核的尺寸。3×3表示每次处理3×3像素的区域。
- np.uint8:数据类型(无符号8位整数)。
🌰 生活类比
核就像不同形状的印章:
np.ones((3,3))
是一块方形印章,覆盖3×3区域。- 如果用
cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
,会得到一个圆形印章。
五 形态学操作
形态学常用的操作:腐蚀(相当于用硫酸倒在纸上,主要视觉效果是让边缘部分变细);膨胀(顾名思义,边缘变粗);开运算和闭运算(我实验的图效果不太明显);梯度操作(可以看到明显的轮廓边缘)
import cv2
import numpy as np
# 读取图像
image = cv2.imread('image.png', 1)
# 定义结构元素
kernel = np.ones((10,10), np.uint8)
# 腐蚀操作
eroded_image = cv2.erode(image, kernel, iterations=1)#腐蚀
_oopen_morphology_imge=cv2.morphologyEx(image,cv2.MORPH_OPEN,kernel)#开运算
_close_morphlogy_image=cv2.morphologyEx(image,cv2.MORPH_CLOSE,kernel)#闭运算
dilate_image = cv2.dilate(image, kernel, iterations=1)#膨胀
_grand_morphlogy_image=cv2.morphologyEx(image,cv2.MORPH_GRADIENT,kernel)#形态学梯度
# 显示结果
cv2.imshow('Eroded Image', eroded_image)
cv2.imshow('open_',_oopen_morphology_imge)
cv2.imshow('_close',_close_morphlogy_image)
cv2.imshow('dilate',dilate_image)
cv2.imshow('_grand',_grand_morphlogy_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
关于梯度运算在边缘运算中的使用
import cv2
import numpy as np
# 读取图像
image = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
# 计算 x 方向的梯度
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
# 计算 y 方向的梯度
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
#CV_64F什么意思
# 计算梯度幅值
sobel_combined = np.sqrt(sobel_x**2 + sobel_y**2)
#combine起来为什么这么奇怪
# 显示结果
cv2.imshow('Sobel X', sobel_x)
cv2.imshow('Sobel Y', sobel_y)
cv2.imshow('Sobel Combined', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()
沿着Y轴:
combine后: