阈值分割

阈值分割

简介:
图像分割:1.基于阈值的分割方法,2.基于区域的分割方法3.基于边缘的分割方法
阈值分割适合于那些前景与背景有较强对比度的图,如果不明显可以增大对比度(不知道怎么弄)

方法概述:

全局阈值分割

全局指对整个图像进行,阈值分割指给定一个阈值,大于阈值就放大为255,不大于就变为零,或者可以反过来操作
这里介绍一下python中的一个语法糖:

import numpy as np
import cv2 as cv
# src=np.array([[[123,144,156],[222,32,67]],[[123,144,156],[222,32,67]]],dtype=np.uint8)
src=cv.imread(r'C:\Users\19583\Desktop\3.png',cv.IMREAD_GRAYSCALE)
src[src>180]=255
src[src<=180]=0#这个语法糖爱了
cv.imshow('1',src)
cv.waitKey(0)

在这里插入图片描述
在这里插入图片描述

上面这个写法对于所有类型的矩阵都行,直接遍历
然后opencv也提供了现成的函数threshold:
在这里插入图片描述
注意返回值,第一个是阈值,第二个才是矩阵

import numpy as np
import cv2 as cv
# src=np.array([[[123,144,156],[222,32,67]],[[123,144,156],[222,32,67]]],dtype=np.uint8)
src=cv.imread(r'C:\Users\19583\Desktop\3.png',cv.IMREAD_COLOR)
a,gj1=cv.threshold(src,100,255,cv.THRESH_BINARY)
a,gj2=cv.threshold(src,100,255,cv.THRESH_BINARY_INV)
a,gj3=cv.threshold(src,100,255,cv.THRESH_MASK)
#a,gj4=cv.threshold(src,100,255,cv.THRESH_OTSU)
a,gj5=cv.threshold(src,100,255,cv.THRESH_TOZERO)
a,gj6=cv.threshold(src,100,255,cv.THRESH_TOZERO_INV)
#a,gj7=cv.threshold(src,100,255,cv.THRESH_TRIANGLE)
#a,gj8=cv.threshold(src,100,255,cv.THRESH_TRUNC)
cv.imshow('1',gj1)
cv.imshow('2',gj2)
cv.imshow('3',gj3)
#cv.imshow('4',gj4)
cv.imshow('5',gj5)
cv.imshow('6',gj6)
#cv.imshow('7',gj7)
#cv.imshow('8',gj8)
cv.waitKey(0)

_INV是反过来
THRESH_BINARY模式:大于阈值取max,小于等于阈值取0

src = np.array([[123,234,68],[33,51,17],[48,98,234],
                    [129,89,27],[45,167,134]],np.uint8)
#手动设置阈值
the = 150
maxval = 255
dst = cv.threshold(src,the,maxval,cv.THRESH_BINARY)
# Otsu 阈值处理
otsuThe = 0
otsuThe,dst_Otsu = cv.threshold(src,otsuThe,maxval,cv.THRESH_OTSU)#先用otsh得到阈值再用binary(默认是这个)
print(otsuThe,dst_Otsu)
# TRIANGLE 阈值处理
triThe = 0
triThe,dst_tri = cv.threshold(src,triThe,maxval,cv.THRESH_TRIANGLE+cv.THRESH_BINARY_INV)#先用training得到阈值再用binary_INV
print(triThe,dst_tri)

98.0 [[255 255 0]
[ 0 0 0]
[ 0 0 255]
[255 0 0]
[ 0 255 255]]
232.0 [[255 0 255]
[255 255 255]
[255 255 0]
[255 255 255]
[255 255 255]]

还要说明一点,otsu,training要求,类型为uint8
其他模式不讲了

局部阈值分割

在这里插入图片描述
不同点的阈值不一样,关键在于各点阈值的计算

直方图技术法

我们的目的是找到下图的位置:
在这里插入图片描述
但是实际情况有时并不会像上面这样,比如可能两个波峰之间会有好几个波谷,而且他们都是最小值,一种思路是对直方图进行高斯平滑处理,但是这样要调好参数使之只有一个波谷,需要手工调,不好,下面介绍一种自动的方法:
思路就是先找到最高的峰,这个很容易取频数最大的灰度值就行了,然后找第二个峰,怎么找?先对原直方图进行量化(不影响原直方图),这个量化与离第一个峰的距离和该点的频数有关(具体的在代码中给出),然后截取两个波峰之间的区域,找出中间频数最低的那个灰度值,如果有多个波峰,就取最左边的那个。这个就是分割的阈值,最好是处理前看一下直方图的形状,有些图压根分不开前景和背景。

python

import numpy as np
import cv2 as cv
def calcGrayHist(img):#获得直方图
    rows,cols=img.shape
    grayhist=np.zeros((256,1),dtype=np.float32)
    for r in range(rows):
        for c in range(cols):
            grayhist[img[r][c]]+=1
    return grayhist
src=cv.imread(r'C:\Users\19583\Desktop\4.jpg',cv.IMREAD_GRAYSCALE)
src=cv.resize(src,(500,500))
#print(calcGrayHist(src))
def threshTowPeaks(img):
    histgram=calcGrayHist(img)
    maxloc=np.where(histgram==max(histgram))
    print(maxloc)
    firstpeak=maxloc[0][0]#取出最大值的灰度值,第一个峰
    print(firstpeak)
    measuredists=np.zeros(256,np.float32)
    for k in range(256):
        measuredists[k]=pow(k-firstpeak,2)*histgram[k]#用到第一个峰的的距离和该点灰度值来量化
    print(measuredists)
    maxloc1=np.where(measuredists==max(measuredists))
    secondpeak=maxloc1[0][0]#第二个峰
    print(secondpeak)
    #thresh = 0
    #根据第二个峰与第一个峰的位置关系分类
    if firstpeak > secondpeak:
        temp = histgram[int(secondpeak):int(firstpeak)]#取出之间的区域
        minLoc = np.where(temp == np.min(temp))#找到最小值对应的灰度值(截取的从零开始记,所以这个值是相对的)
        thresh = secondpeak + minLoc[0][0] + 1#找到最小值对应的灰度值
    else:
        temp = histgram[int(firstpeak):int(secondpeak)]
        minLoc = np.where(temp == np.min(temp))
        thresh = firstpeak + minLoc[0][0] + 1
    threhimg=img.copy()
    print(thresh)
    threhimg[threhimg>thresh]=255
    threhimg[threhimg <= thresh] = 0
    return thresh,threhimg/255#返回阈值和处理好的图

a,dst=threshTowPeaks(src)
cv.imshow('src',src)
cv.imshow('dst',dst)
cv.waitKey(0)

(array([11], dtype=int64), array([0], dtype=int64))
11
[0.0000000e+00 1.4000000e+03 4.9410000e+03 1.5680000e+04 2.5333000e+04
2.9412000e+04 2.9925000e+04 2.4544000e+04 1.6974000e+04 7.6680000e+03
1.9890000e+03 0.0000000e+00 1.8450000e+03 6.4960000e+03 1.1169000e+04
1.9136000e+04 3.4175000e+04 5.2416000e+04 7.0805000e+04 9.5872000e+04
1.1161800e+05 1.3160000e+05 1.4144900e+05 1.5696000e+05 1.6832400e+05
1.7816400e+05 1.9845000e+05 2.1452800e+05 2.4507200e+05 2.7734400e+05
3.1190400e+05 3.2840000e+05 3.2854500e+05 3.4218800e+05 3.8669900e+05
3.9225600e+05 4.5187500e+05 4.8536800e+05 5.1030000e+05 5.8564800e+05
5.8197200e+05 5.5170000e+05 5.8044400e+05 7.1168000e+05 6.8280300e+05
7.6527200e+05 9.2487500e+05 1.0108800e+06 1.0130600e+06 1.1032160e+06
1.0829520e+06 1.2112000e+06 1.1918290e+06 1.1818800e+06 1.2000010e+06
1.2796960e+06 1.2048750e+06 1.3732840e+06 1.5153740e+06 1.6773120e+06
2.0072360e+06 2.0975000e+06 2.2134510e+06 2.5255360e+06 2.7387750e+06
2.9130840e+06 3.2004500e+06 3.5091840e+06 3.8208240e+06 4.0401640e+06
4.0762510e+06 4.2372000e+06 4.5284570e+06 4.8511280e+06 4.6794510e+06
4.4236800e+06 4.3559750e+06 4.2688800e+06 4.2241490e+06 4.5823840e+06
4.6467360e+06 4.6991000e+06 5.4291570e+06 5.9823360e+06 6.5919730e+06
7.0640400e+06 7.7568750e+06 8.7737440e+06 9.4864000e+06 9.8013240e+06
1.0285168e+07 1.0758400e+07 1.1849166e+07 1.1787172e+07 1.2606870e+07
1.2721968e+07 1.2911075e+07 1.3712184e+07 1.4509773e+07 1.5023360e+07
1.4693455e+07 1.5681600e+07 1.5816710e+07 1.5057456e+07 1.5395220e+07
1.5330460e+07 1.5369575e+07 1.5879168e+07 1.6955018e+07 1.7316012e+07
1.7524188e+07 1.7780000e+07 1.7198886e+07 1.7405892e+07 1.6794048e+07
1.7381312e+07 1.6250850e+07 1.5752872e+07 1.5055435e+07 1.4323392e+07
1.2475050e+07 1.1168300e+07 9.7212690e+06 7.9027200e+06 7.4187890e+06
7.6676400e+06 6.9960250e+06 7.3469760e+06 7.7069070e+06 8.3822480e+06
9.9693440e+06 1.1203200e+07 1.0702571e+07 1.1788128e+07 1.2012426e+07
1.2823584e+07 1.4265625e+07 1.4590044e+07 1.3854811e+07 1.5024128e+07
1.6191693e+07 1.5801500e+07 1.7452736e+07 1.8504288e+07 2.1828226e+07
2.3468492e+07 2.4038776e+07 2.8058432e+07 2.7684276e+07 2.6871084e+07
2.7686992e+07 2.8341600e+07 2.8270782e+07 3.0205672e+07 3.1286970e+07
3.2514048e+07 3.4859448e+07 3.3935072e+07 3.1505922e+07 3.2001744e+07
3.2191450e+07 2.9205000e+07 3.1465380e+07 3.2715264e+07 3.0642380e+07
3.1067960e+07 3.1640924e+07 3.2147856e+07 3.3818428e+07 3.6347584e+07
3.7668688e+07 3.6121600e+07 3.6626372e+07 3.6269208e+07 3.7807688e+07
3.8326800e+07 3.9775724e+07 3.8302840e+07 3.6925036e+07 3.5534016e+07
3.8100376e+07 3.7916800e+07 3.7984060e+07 3.7275840e+07 3.7351392e+07
3.7481688e+07 3.5341248e+07 3.8781952e+07 3.7939420e+07 3.7260384e+07
3.7263684e+07 3.6028800e+07 3.9509768e+07 3.7628864e+07 4.0890068e+07
4.0356352e+07 4.0488176e+07 3.8263176e+07 3.6297824e+07 3.3930240e+07
3.3399136e+07 3.2309500e+07 3.0315712e+07 2.9048832e+07 2.5850806e+07
2.7060284e+07 2.3347350e+07 2.5008816e+07 2.4449670e+07 2.4267276e+07
2.6017856e+07 2.5000000e+07 2.2907368e+07 1.8606624e+07 2.0975380e+07
2.0932848e+07 2.0172000e+07 1.6719784e+07 1.5382791e+07 1.3498368e+07
1.1750189e+07 1.1113200e+07 1.0373393e+07 9.5281280e+06 9.7543350e+06
7.9685040e+06 5.9630250e+06 4.8055680e+06 3.5316750e+06 8.5543200e+05
1.4388300e+06 8.7120000e+05 8.3029700e+05 7.3926000e+05 6.4647700e+05
7.0246400e+05 9.1125000e+05 8.6829200e+05 1.0305800e+06 1.0396800e+06
9.9637900e+05 5.8190000e+05 7.4705400e+05 1.1303040e+06 9.2291300e+05
1.1498760e+06 1.2149500e+06 1.5594880e+06 1.0672110e+06 1.1895240e+06
1.7707510e+06 1.6704000e+06 2.0909160e+06 5.0950680e+06 8.0897130e+06
5.3463328e+07]
255
242

在这里插入图片描述

熵算法

在这里插入图片描述

python实现

import cv2 as cv
import numpy as np
import math
src=cv.imread(r'C:\Users\19583\Desktop\4.jpg',cv.IMREAD_GRAYSCALE)
src=cv.resize(src,(500,500))
def threshentroy(img):
    rows,cols=img.shape
    #获得灰度直方图
    threshgram=np.ones(256,dtype=np.float32)#这里选一防止后面log真值为0,差个1应该没关系吧
    for r in range(rows):
        for c in range(cols):
            threshgram[img[r][c]]+=1
    threshentroygram=np.zeros(256,dtype=np.float32)
    threshgram/=np.sum(threshgram)
    for i in range(1,256,1):
        #重新归一化
        H=threshgram[0:i+1].copy()
        T=threshgram[i+1:].copy()
        #print(np.sum(H))
        if np.sum(H)==0:
            H=0
        else:
            H/=np.sum(H)
        if np.sum(T)==0:
            T=0
        else:
            T/=np.sum(T)
        #定义两个变量存前后两个熵的值
        f1=0
        f2=0
        #计算两部分的值
        for j in range(i+1):
            f1+=-H[j]*math.log(H[j],2.71)
        for j in range(255-i):
            f2+=-T[j]*math.log(T[j],2.71)
        threshentroygram[i]=f1+f2
    thresh=np.where(threshentroygram==max(threshentroygram))
    ret=thresh[0][0]
    img1=img.copy()
    img1[img1>ret]=255
    img1[img1<=ret]=0
    return ret,img1
thresh,dst=threshentroy(src)
print(thresh)
cv.imshow('src',src)
cv.imshow('dst',dst)
cv.waitKey(0)

117

在这里插入图片描述

otsu阈值处理

在这里插入图片描述

python

import numpy as np
import cv2
import math
#计算图像灰度直方图
def calcGrayHist(image):
    #灰度图像矩阵的宽高
    rows,cols = image.shape
    #存储灰度直方图
    grayHist = np.zeros([1,256],np.uint32)
    for r in range(rows):
        for c in range(cols):
            grayHist[0][image[r][c]] +=1
    return grayHist
def ostu(image):
    rows,cols = image.shape
    #计算图像的灰度直方图
    grayHist = calcGrayHist(image)
    #归一化灰度直方图
    uniformGrayHist = grayHist/float(rows*cols)
    #计算零阶累积矩(sigma概率)和一阶累积矩(sigma概率乘灰度值)
    zeroCumuMoment = np.zeros([1,256],np.float32)
    oneCumuMoment = np.zeros([1,256],np.float32)
    for k in range(256):
        if k == 0:
            zeroCumuMoment[0][k] = uniformGrayHist[0][0]
            oneCumuMoment[0][k] = (k+1)*uniformGrayHist[0][0]
        else:
            zeroCumuMoment[0][k] = zeroCumuMoment[0][k-1] + uniformGrayHist[0][k]
            oneCumuMoment[0][k] = oneCumuMoment[0][k-1] + k*uniformGrayHist[0][k]
    #计算类间方差
    variance = np.zeros([1,256],np.float32)
    for k in range(255):
        if zeroCumuMoment[0][k] == 0:
            variance[0][k] = 0
        else:
            variance[0][k] = math.pow(oneCumuMoment[0][255]*zeroCumuMoment[0][k] - oneCumuMoment[0][k],2)/(zeroCumuMoment[0][k]*(1.0-zeroCumuMoment[0][k]))
    #找到阈值
    threshLoc = np.where(variance[0][0:255] == np.max(variance[0][0:255]))
    thresh = threshLoc[0]
    #阈值处理
    threshold = np.copy(image)
    print(thresh)
    threshold[threshold > thresh] = 255
    threshold[threshold <= thresh] = 0
    return threshold
src=cv2.imread(r'C:\Users\19583\Desktop\4.jpg',cv2.IMREAD_GRAYSCALE)
src=cv2.resize(src,(500,500))
dst=ostu(src)
cv2.imshow('src',src)
cv2.imshow('dst',dst)
cv2.waitKey(0)

在这里插入图片描述

opencv中提供了现成的函数

import cv2 as cv
import numpy as np
src=cv.imread(r'C:\Users\19583\Desktop\3.jpg',cv.IMREAD_GRAYSCALE)
src=cv.resize(src,(500,500))
thresh,dst=cv.threshold(src,0,255,type=cv.THRESH_OTSU|cv.THRESH_BINARY)#这个0是随便写的,OTSU模式加会用otsu得到的阈值做二值处理
print(thresh)
cv.imshow('src',src)
cv.imshow('dst',dst)
cv.waitKey(0)

139.0
在这里插入图片描述

自适应阈值分割

如果一个图像光照不均(没有明显的双峰)用上面的方法就不好了,用自适应阈值分割就好了,根据不同地方周围的情况不同地方的阈值不一样。
以平滑的值作为阈值,根据经验,平滑的算子大小要大于被识别物体的大小。
在这里插入图片描述
自适应操作过程

  1. 对图像进行平滑处理结果存在一个矩阵中
  2. 将(1-a)*b作为各点的阈值(a为调整用的参数一般取0.15,b是对应位置的平滑结果)

python实现:

import cv2 as cv
import numpy as np
src=cv.imread(r'C:\Users\19583\Desktop\4.jpg',cv.IMREAD_GRAYSCALE)
src=cv.resize(src,(500,500))

def adaptiveThresh(img,size,x):
    a = cv.GaussianBlur(img, size, 2, borderType=cv.BORDER_REFLECT)
    rows,cols=img.shape
    img1=img.copy()
    for r in range(rows):
        for c in range(cols):
            if img1[r][c]>a[r][c]*(1-x):
                img1[r][c]=255
            else:
                img1[r][c]=0
    return img1
dst1=adaptiveThresh(src,(3,3),0.15)
dst2=adaptiveThresh(src,(23,23),0.15)
cv.imshow('src',src)
cv.imshow('dst1',dst1)
cv.imshow('dst2',dst2)
cv.waitKey(0)

在这里插入图片描述

opencv自带函数:

import cv2 as cv
import numpy as np
src=cv.imread(r'C:\Users\19583\Desktop\4.jpg',cv.IMREAD_GRAYSCALE)
src=cv.resize(src,(500,500))
dst1=cv.adaptiveThreshold(src,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,thresholdType=cv.THRESH_BINARY,blockSize=3,C=0.15)#图,最大值(阈值分割后),平滑方法(只有均值和高斯),取阈值方法,算子大小.C是那个a
cv.imshow('src',src)
cv.imshow('dst1',dst1)
cv.waitKey(0)

在这里插入图片描述

二值图的逻辑运算

对图像进行阈值分割后得到二值图,可以进行或,与的运算,opencv提供了现成的函数:
在这里插入图片描述
在这里插入图片描述
很简单就直接放图了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值