图片降噪
- 均值滤波
blur
中心点的像素值等于核值区域的平均值
python">
import cv2
img_gs = cv2.imread('./media/lvbo2.png') # 高斯噪声
img_jy = cv2.imread('./media/lvbo3.png') # 椒盐噪声def buler():img_jz1= cv2.blur(img_gs,(3,3))img_jz2= cv2.blur(img_jy,(3,3))cv2.imshow('img_jz1',img_jz1)cv2.imshow('img_jz2',img_jz2)buler()cv2.imshow('img_gs',img_gs)
cv2.imshow('img_jy',img_jy)cv2.waitKey(0)
- 方框滤波
boxFilter
- normalize=False 中心点的像素值等于核区域像素的总和
- normalize=True 默认为True 就是均值滤波
python"> img_jz1 = cv2.boxFilter(img_gs,-1,(3,3),normalize=False ) # [图像] [输出图像的深度,-1是原图像的深度] [核的大小]img_jz2 = cv2.boxFilter(img_jy,-1,(3,3))cv2.imshow('img_jz1',img_jz1)cv2.imshow('img_jz2',img_jz2)
- 高斯滤波
GaussianBlur
核的权重取决于高斯函数并取近似值,对应的像素乘以权重相加得到中心点的像素值
sigma的值 模糊效果越明显 (中心点的权重变小)
g ( x , y ) = 1 2 π σ 2 e − ( x 2 + y 2 ) 2 σ 2 g(x,y)=\frac{1}{2\pi\sigma^{2}}e^{-\frac{(x^{2}+y^{2})}{2\sigma^{2}}} g(x,y)=2πσ21e−2σ2(x2+y2)
如3*3的核权重矩阵是[[1/16,1/8,1/16],[1/8,1/4,1/8],[1/16,1/8,1/16]]
python"> img_jz1 = cv2.GaussianBlur(img_jy,(3,3),10) # 图像 核大小 sigma的值 值越大 模糊效果越明显 img_jz2 = cv2.GaussianBlur(img_gs,(3,3),10)
- 中值滤波
对核值大小范围内像素值排序,取中位数,对椒盐噪声和斑点效果较好,效率较低
python"> img_jz1 = cv2.medianBlur(img_gs,3) # 图像 核大小img_jz2 = cv2.medianBlur(img_jy,3) # 均值滤波
- 双边滤波
同时考虑像素点周围的点和像素值的大小
核值范围内每个像素点的权重值由位置的权重和像素值的权重相乘得到
ω ( i , j , k , l ) = w s ∗ w r \omega(i,j,k,l)=w_{s}*w_{r} ω(i,j,k,l)=ws∗wr
空间位置的权重值
ω s = e − ( i − k ) 2 + ( j − l ) 2 2 σ s 2 \omega_{s}=e^{-{\frac{(i-k)^{2}+(j-l)^{2}}{2\sigma_{s}{}^{2}}}} ωs=e−2σs2(i−k)2+(j−l)2
像素值大小得到的权重
ω r = e − ∥ f ( i , j ) − f ( k , l ) ∥ 2 2 σ r 2 \omega_{r}=e^{-{\frac{\|f(i,j)-f(k,l)\|^{2}}{2\sigma_{r}{}^{2}}}} ωr=e−2σr2∥f(i,j)−f(k,l)∥2
python"> img_jz1 = cv2.bilateralFilter(img_gs,9,70,70)img_jz2 = cv2.bilateralFilter(img_jy,9,70,70)
边缘检测
- Sobel 算子
k = [ − 1 0 1 − 1 0 1 − 1 0 1 ] k=\left[{\begin{array}{r r r}{-1}&{0}&{1}\\ {-1}&{0}&{1}\\ {-1}&{0}&{1}\end{array}}\right] k= −1−1−1000111
python"> boder_x = cv2.Sobel(img_nut,-1,1,0) # x方向的梯度,就是y方向的边缘boder_y = cv2.Sobel(img_nut,-1,0,1) # y方向的梯度cv2.imshow('boder_x',boder_x)cv2.imshow('boder+y',boder_y)
- Scharr算子
k = [ − 3 0 3 − 10 0 10 − 3 0 3 ] k=\left[{\begin{array}{r r r}{-3}&{0}&{3}\\ {-10}&{0}&{10}\\ {-3}&{0}&{3}\end{array}}\right] k= −3−10−30003103
python"> boder_x = cv2.Scharr(img_nut,-1,1,0)boder_y = cv2.Scharr(img_nut,-1,0,1)
- Laplacian算子
k = [ 1 1 1 1 − 8 1 1 1 1 ] k=\left[\begin{array}{c c c}{1}&{1}&{1}\\ {1}&{-8}&{1}\\ {1}&{1}&{1}\end{array}\right] k= 1111−81111
python">boder = cv2.Laplacian(img_nut,-1)
-
Canny边缘检测
边缘的像素值和周围的像素值有着其差异,表现为较大的像素差值,通过这个特点找到图像的边缘
Canny边缘检测步骤
4.1 读取图像
4.2 二值化图像
4.3 高斯滤波
4.4 计算图像的梯度和方向- 图像梯度
- 通过算子也就是特定的核(矩阵)对图像进行运算,从而得到图像像素值的变化值。也就是对图像做差分,得到图像的梯度。梯度的大小,描述了图像像素值的变化程度
- Canny中使用Subol算子对x反向和y方向进行求梯度
- 两个方向的梯度相加取绝对值得到像素点的梯度
- 通过反正弦函数求出梯度的方向
- θ = arctan ( G y G x ) \theta=\arctan\,({\frac{G_{\mathrm{y}}}{G_{x}}}) θ=arctan(GxGy)
- 为了简化计算统一角度值,对角度进行插值,指定范围的角度统一到同一个角度
4.5 非极大值抑制
- 得到图像每个像素点的梯度值和方向,通过在比较同方向的相邻像素点的梯度值,(梯度方向和边缘的方向垂直)保留最大的像素值,不是最大的就舍去,可以去掉一些不是边缘的像素点
- 比较的像素点是梯度方向指向的领域内的像素点,确保得到的是局部最大值
4.6 双阈值筛选
- 通过指定两个阈值,去掉一些弱边缘
- 大于高阈值,就是强边缘点
- 小于低阈值就不是边缘点
- 介于两者之间,弱边缘点
- 根据连通性判断 是否保留,如果弱边缘点和强边缘有连通性,就保留弱边缘
- 图像梯度
python"> boder = cv2.Canny(img_nut,60,120) # 图像 低阈值 高阈值
绘制图像轮廓
- 寻找图像轮廓
contours,hierarchy = cv2.findContours(image,mode,method)
contours 返回轮廓点的列表,子列表的格式就是轮廓的个数
hierarchy 轮廓的关系
mode:轮廓的搜索模式
- RETR_LIST所有轮廓
- RETE_EXTERNAL最外层轮廓
- RETE_-CCOMP列出所有轮廓
- RETR_TREE所有轮廓
method:对轮廓点的存储方式
-
CHAIN_APPROX_NONE表示将所有的轮廓点都进行存储;
-
CHAIN_APPROX_SIMPLE只存储有用的点 默认使用这个方法;
-
CHAIN_APPROX_TC89_L1减少轮廓中的冗余点,更加准确地表示轮廓的形状。
-
CHAIN_APPROX_TC89_L1是一种较为精确的轮廓逼近方法,适用于需要较高精度的轮廓表示的情况。
- 绘制轮廓
cv2.drawContours(image, contours, contourIdx, color, thickness)
图片,轮廓点,要绘制哪些轮廓,颜色,线条粗细
python">def contours():img_nut = cv2.imread('./media/nut.png')img_nut_gray = cv2.cvtColor(img_nut,cv2.COLOR_BGR2GRAY)nut_erzhi = cv2.adaptiveThreshold(img_nut_gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,25,10)cv2.imshow('nut_erzhi',nut_erzhi)contours,h = cv2.findContours(nut_erzhi,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(img_nut,contours,-1,(255,0,0))cv2.imshow('nut',img_nut)contours()
cv2.waitKey(0)