OpenCV 5~7 阈值分割、图像平滑处理、图像形态学

5 阈值分割

5.1 基础理论

  1. 二进制阈值化:大于等于阈值的为设置的最大值(假设为255),小于阈值的为0;
  2. 反二进制阈值化:大于等于阈值的为设置的0,小于阈值的为最大值(假设为255);
  3. 截断阈值化:大于等于阈值的为设置为该阈值,小于阈值的为0;
  4. 反阈值化为0:大于等于阈值的为0,小于阈值的不变;
  5. 阈值化为0:大于等于阈值的不变,小于阈值的为0;
  6. retval,dst = cv2.threshold(src,thresh,maxval,type) #thresh ==retval阈值

5.2 threhold函数

# 1. 二进制阈值化cv2.THRESH_BINARY 白的更白,黑的更黑
import cv2 
img = cv2.imread('')
r,img1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# 2. 反二进制阈值化cv2.THRESH_BINARY_INV 白的变黑,黑的变白
r,img2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# 3. 截断阈值化cv2.THRESH_TRUNK 把图像中亮的变暗
r,img3 = cv2.threshold(img,127,255,cv2.THRESH__TRUNK)
# 4. 反阈值化为0 cv2.THRESH_TOZERO_INV    把图像中亮的变非常暗
r,img4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
# 5. 阈值化为0 cv2.THRESH_TOZERO   把图像中亮的不变,暗得更暗
r,img5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)

cv2.imshow('img',img)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.imshow('img4',img4)
cv2.imshow('img5',img5)

cv2.waitKey(0)
cv2.destroyAllWindows()

5.3 直方图阈值

  1. 算法描述:根据图像灰度直方图,人工寻找阈值。
  2. 算法特点:适用双峰图像
  3. plt.hist(img.ravel(), 256, [0,256])
  4. cv.threshold(img, th, 255, cv.THRESH_BINARY)
'''  

'''
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./2.png') 

plt.hist(img.ravel(), 256, [0, 256])
plt.show()

plt.hist(img.flatten(), bins=np.arange(-0.5, 256, 1), color='green')
plt.show()

_, img_bin = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY)
plt.imshow(img_bin)

5.4 三角法阈值

  1. 算法思想:几何法,适用单峰图像
  2. th, img_bin = cv.threshold(img, th, 255, cv.THRESH_TRIANGLE)
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./2.png') 


plt.hist(img.ravel(), 256, [0,256], color='blue')
plt.show()


th, img_bin = cv2.threshold(img, -1, 255, cv2.THRESH_TRIANGLE)

plt.imshow(img_bin) 

5.5 迭代法阈值及实现

  1. 选取初始分割阈值,通常选图像灰度平均值T。
  2. 根据T将图像像素分为背景和前景,分别求出平均灰度T0和T1。
  3. 计算新的阈值T_new= (T0+T1)/2
  4. 迭代循环,直到T_new==T
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./2.png') 

T = img.mean()

while True:
    t1 = img[img > T].mean()
    t2 = img[img <= T].mean()
    t  = (t1 + t2) / 2
    if abs(t - T) < 1:
        break
    T = t
T = int(T)

print(f'Best threshold = {T}')
_, img_bin = cv.threshold(img, T, 255, cv.THRESH_BINARY)

plt.imshow(img_bin) 

5.6 大津法(OTSU)阈值及实现

  1. 给定阈值T,根据阈值吧图像分为前景和背景,前背景占总像素的比例p0、p1,平均灰度为m0,m1。上述变量满足以下数学关系
  2. th, img_bin = cv.threshold(img, th, 255, cv.THRESH_OTSU)
p_0+ p_1= 1

\bar{m} = p_0*m_0+ p_1*m_1

\sigma^2 = p_0*(m_0-\bar{m} )^2+ p_1*(m_1-\bar{m} )^2

\sigma^2 = p_0*p_1(m_0-m_1)^2

所有的灰度,找出使得方差最大的阈值T。

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./2.png') 

th, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
plt.imshow(img_bin) 

python实现大津法(OTSU)阈值

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./2.png') 

T = 1
Sigma = 0

for t in range(0, 255):
    bg = img[img <= t]
    obj = img[img > t]
    
    p0 = bg.size / img.size
    p1 = obj.size / img.size
    
    m0 = 0 if bg.size == 0  else bg.mean()
    m1 = 0 if obj.size == 0 else obj.mean()
    
    sigma = p0 * p1 * (m0 - m1)**2
    
    if sigma > Sigma:
        T = t
        Sigma = sigma
        
print(T)

_, img_bin = cv2.threshold(img, T, 255, cv2.THRESH_BINARY)
plt.imshow(img_bin)

5.7 自适应阈值及实现

自适应阈值的本质时局部二值化

  1. 对某个像素值s,取其周围n*n区域,求区域均值或高斯加权值T。
  2. 对8位图像,如果S>T,则该像素点二值化为255,否则为0。
  3. 优化:S>T-C or S>(1-a)T,C,a为超参数。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./2.png') 

plt.hist(img.ravel(), bins=256)
plt.show()
_, img_thres = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
show(img_thres)

img_adapt = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
                cv2.THRESH_BINARY, 21, 12)
show(img_adapt)

plt.imshow(img_adapt) 

python实现自适应阈值分割

# 1 S>T-C
import cv2
import numpy as np
import matplotlib.pyplot as plt

winSize = 21
img_blur = cv.blur(img, (winSize, winSize))
img_bin = (np.float32(img_blur) - np.float32(img) < 8).astype(np.uint8) * 255

plt.imshow(img) 

# 2 S>(1-a)T
import cv2
import numpy as np
import matplotlib.pyplot as plt

winSize = 21
ratio = 0.15

img_blur = cv.blur(img, (winSize, winSize))
thresh = (1 - ratio) * img_blur

img[img < thresh] = 0
img[img >= thresh] = 255

plt.imshow(img) 

6 图像平滑处理

# 卷积
cv2.filter2D(img,-1,kernel)

6.1 均值滤波

  1. 任意一点的像素值,都是周围NN个像素值的均值。k=1/(NN)* np.ones([n,n])
  2. dst = cv2.blur(img,k.shape)
  3. 效用:原图有杂质,可以平滑掉。
import cv2 
img1 = cv2.imread('')
img2 = cv2.blur(img1,(5,5)) 
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.2 方框滤波

  1. dst = cv2.boxFilter(img,目标图像深度,k.shape,normalize属性)
  2. 目标图像深度=-1,表示和原始图像深度一致。
  3. normalize = True,k=1/(NxN)* np.ones([n,n])
  4. normalize = True,k= np.ones([n,n])
import cv2 
img1 = cv2.imread('')
img2 = cv2.cv2.boxFilter(img1,-1,(5,5),normalize = 1)
img3 = cv2.cv2.boxFilter(img1,-1,(5,5),normalize = 0)  # 白色
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.3 高斯滤波

  1. 让临近的像素有更大的权值。
  2. dst = cv2.GaussianBlur(img,k.shape,sigmax) # x 方向的方差,控制权重
  3. sigmax=0时,sigmax=0.3*((ksize-1)*0.5-1)+0.8,sigmax是方差。
import cv2 
img1 = cv2.imread('')
img2 = cv2.GaussianBlur(img1,(3,3),0.5)
img3 = cv2.GaussianBlur(img1,(3,3),6)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.4 中值滤波

  1. 让临近元素按照大小排列,去中间位置的元素的值作为种植滤波的像素值。
  2. dst = cv2.medianBlur(img,k.shape) # k 必须是大于1的奇数。
import cv2 
img1 = cv2.imread('')
img2 = cv2.medianBlur(img1,3)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.5 双边滤波

  1. 考虑空间因素和数值差异
    cv.bilateralFilter(img, -1, sigmaColor=50, sigmaSpace=3)
import cv2 
img1 = cv2.imread('')
img2 = cv2.bilateralFilter(img, -1, sigmaColor=50, sigmaSpace=3)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python实现双边滤波

import numpy as np
import matplotlib.pyplot as plt
import cv2 

def get_C(sigmad, n):   # 空间差异
    C = np.zeros((n,n))
    # 0, 1, 2
    x = np.array([n//2, n//2])
    for i in range(n):
        for j in range(n):
            ksi = np.array([i, j])
            C[i,j] = np.exp(-0.5 * (np.linalg.norm(ksi - x) / sigmad)**2)  
    C /= C.sum()  # 归一化
    return C

def get_S(f, sigmar, n):  # 数值差异
    f = np.float64(f)
    S = np.exp(-0.5 * ((f - f[n//2, n//2]) / sigmar)**2)
    S /= S.sum()
    return S

img = cv2.imread('', 0)
sigmar = 50
sigmad = 3
n = 11

h, w = img.shape
img2 = np.zeros_like(img)


C = get_C(sigmad, n)

for i in range(h-n):
    for j in range(w-n):
        f = img[i:i+n, j:j+n]
        S = get_S(f, sigmar, n)   # 数值权重
        K = C * S                 # 空间权重*数值权重
        K /= K.sum()
        img2[i,j] = (f * K).sum() 

plt.imshow(img)
plt.imshow(img2)

6.6 双边滤波

import cv2 
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('')
kernel = np.ones((5,5), dtype=np.float32)
kernel /= kernel.sum()

img_filter = cv2.filter2D(img, -1, kernel)
plt.imshow(np.hstack([img, img_filter]))

7 图像形态学

7.1 图像腐蚀

  1. 针对二值图像,如果核里的点都是1,核的值为1;核里面有一个0,核中心值为0.
  2. 效果:图像变小,周围的杂质磨平,理解为提纯。
  3. dst = cv2.erode(img,kernel,iterations)
import cv2 
import numpy as np
kernel = np.ones((5,5),np.uint8)
img1 = cv2.imread('')
img2 = cv2.erode(img1,kernel,6)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

7.2 图像膨胀

  1. 针对二值图像,如果核里的点都是0,核的值为0;核里面有一个1,核中心值为
  2. 效果:把腐蚀操作后的图片膨胀,可以保持去噪后的图片。
  3. dst = cv2.dilate(img,kernel,iterations)
import cv2 
import numpy as np
img1 = cv2.imread('')
kernel = np.ones((5,5),np.uint8)
img2 = cv2.dilate(img1,kernel,6)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

7.3 开运算

  1. 先腐蚀后膨胀,去掉外部毛刺
  2. img2 = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
import cv2 
import numpy as np
img1 = cv2.imread('')
kernel = np.ones((5,5),np.uint8)
img2 = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

7.4 闭运算

  1. 先膨胀后腐蚀,去除内部小黑点
  2. img2 = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
import cv2 
import numpy as np
img1 = cv2.imread('')
kernel = np.ones((5,5),np.uint8)
img2 = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

7.5 梯度运算

  1. 梯度 = 膨胀-腐蚀,得到轮廓
  2. img2 = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
import cv2 
import numpy as np
img1 = cv2.imread('')
kernel = np.ones((5,5),np.uint8)
img2 = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

7.6 礼帽操作

  1. 礼帽 = 原始图像-开运算 ,得到外部毛刺
  2. img2 = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
import cv2 
import numpy as np
img1 = cv2.imread('')
kernel = np.ones((5,5),np.uint8)
img2 = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

7.7 黑帽图像处理

  1. 黑帽图像 = 闭运算 - 原始图像 ,得到内部毛刺
  2. img2 = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
import cv2 
import numpy as np
img1 = cv2.imread('')
kernel = np.ones((5,5),np.uint8)
img2 = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值