日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

《OpenCV算法精解——基于Python与C++》第六章阈值分割

發(fā)布時(shí)間:2023/12/10 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《OpenCV算法精解——基于Python与C++》第六章阈值分割 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第六章代碼總結(jié):

Github地址

本章通過(guò)選取閾值點(diǎn),對(duì)圖像主體與背景進(jìn)行分割。分為手動(dòng)與自動(dòng)。

自動(dòng):直方圖技術(shù)法,熵算法(太麻煩了),Otsu(全局法中最棒),自適應(yīng)閾值法(無(wú)敵)

  • 手動(dòng)閾值
thresh = 150#閾值 maxVal = 255#輸出主體的像素值 type = cv2.THRESH_BINARY#用0替代,大于閾值輸出maxVal,小于等于輸出0;THRESH_BINARY_INV=1相反 dst = cv2.threshold(src,thresh,maxVal,type)
  • 自動(dòng)閾值 效果Otsu > Triangle > histogram = 熵
#Otsu(只支持8位圖) otsu_thresh = 0 otsu_thresh,dst_otsu = cv2.threshold(src,otsu_thresh,255,8)#最后的8,代表type為cv2.THRESH_OTSU #Triangle三角形法(直方圖法原理同三角形法) triangle_thresh = 0 triangle_thresh,dst_tri = cv2.threshold(src,triangle_thresh,255,16) #直方圖histogram與熵算法效果幾乎相同,過(guò)程太復(fù)雜,想看原理的看6.2,6.3
  • 自適應(yīng)閾值法:
  • 全局法對(duì)光照不均的圖像效果不好,根據(jù)每個(gè)像素點(diǎn)位置及其領(lǐng)域來(lái)設(shè)置每一像素點(diǎn)的閾值就是自適應(yīng)閾值法。
  • 先需對(duì)圖像進(jìn)行平滑處理:均值(mean),高斯(gaussian),中值(median)
  • 計(jì)算像素領(lǐng)域灰度均值乘以比例系數(shù)(1-ratio),ratio一般指定0.15。
  • 結(jié)果作為閾值參考值。平滑算子高寬為基數(shù),須大于被識(shí)別主體寬度保證效果。
  • import cv2 import numpy as np import matplotlib.pyplot as plt #平滑處理采用均值平滑(cv2.blur或者cv2.boxFilter) def adaptiveThresh(I,winSize,ratio=0.15):#比例系數(shù)ratio一般0.15I_mean = cv2.blur(I,winSize)#I_mean = cv2.boxFilter(I,cv2.CV_32FC1,winSize)#結(jié)果相同,必須指定32位out = I - (1.0-ratio)*I_meanout[out>=0] = 255out[out<0] = 0out = out.astype(np.uint8)#圖像格式轉(zhuǎn)換為255,return outsrc = cv2.imread("image3.png",0) dst = adaptiveThresh(src,(7,7),0.15)#PythonAPI,效果輸出沒(méi)上面編寫(xiě)的好,奇怪,可能是我src沒(méi)預(yù)先平滑好?評(píng)論大佬解答下 #7代表平滑算子(7,7),0.15為ratio(不懂的,就在上段啊喂,別跳),中值平滑adaptive.Threshold沒(méi)給預(yù)設(shè) dst_adaptive_mean = cv2.adaptiveThreshold(src,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,0.15) dst_adaptive_gaussian = cv2.adaptiveThreshold(src,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,7,0.15)

    最后6.6介紹二值圖的邏輯運(yùn)算,要求圖像格式相同

    • dst_and = cv2.bitwise_and(src1,src2)#與運(yùn)算
    • dst_or = cv2.bitwise_or(src1,src2)#或運(yùn)算

    6.1_閾值分割

    閾值分割(cv2.threshold)又稱二值化處理,通過(guò)選取閾值分割,對(duì)圖像分割成不同的像素集合。對(duì)前景與背景有較強(qiáng)對(duì)比度的特別有效。

    threshold(src,dst,thresh,maxval,type)

    thresh:閾值;maxVal:輸出的最大灰度,一般為255;type:THRESH_BINARY = 0 , 大于閾值輸出maxVal,小于等于輸出0;THRESH_BINARY_INV =1 相反THRESH_OTSU = 8 ,自動(dòng)計(jì)算閾值,并默認(rèn)搭配THRESH_BINARY輸出。THRESH_TRIANGLE =16 ,同OTSU

    Python API:

    #-*- coding:utf-8 -*- import numpy as np import cv2 src = np.array([[123,234,68],[33,51,17],[48,98,234],[129,89,27],[45,167,134]],np.uint8)#手動(dòng)設(shè)置閾值 thresh = 150 maxVal = 255 dst = cv2.threshold(src,thresh,maxVal,cv2.THRESH_BINARY) print dst #otsu自動(dòng)閾值處理 otsu_thresh = 0 otsu_thresh,dst_otsu = cv2.threshold(src,otsu_thresh,255,8)#最后的參數(shù)8代表cv2.THRESH_OTSU print otsu_thresh,dst_otsu#TRIANGLE處理 triangle_thresh = 0 triangle_thresh,dst_tri = cv2.threshold(src,triangle_thresh,255,16) print triangle_thresh,dst_tri (150.0, array([[ 0, 255, 0],[ 0, 0, 0],[ 0, 0, 255],[ 0, 0, 0],[ 0, 255, 0]], dtype=uint8)) 98.0 [[255 255 0][ 0 0 0][ 0 0 255][255 0 0][ 0 255 255]] 232.0 [[ 0 255 0][ 0 0 0][ 0 0 255][ 0 0 0][ 0 0 0]]

    原理:

    import numpy as np src = np.array([[123,234,68],[33,51,17],[48,98,234],[129,89,27],[45,167,134]]) #大于閾值的像素點(diǎn)輸出255,小于等于閾值輸出0 src[src>150]=255 src[src<=150]=0 src array([[ 0, 255, 0],[ 0, 0, 0],[ 0, 0, 255],[ 0, 0, 0],[ 0, 255, 0]])

    6.2_直方圖技術(shù)法

    • 0:黑色,255:白色,理解為亮度值;
    • 直方圖技術(shù)法通過(guò)選出直方圖中的兩峰頂間的最小峰谷作為閾值。
    • 方法同THRESH_TRIANGLE:三角法是將最高峰頂置于圖像亮側(cè),連接原點(diǎn)與峰頂,選擇直方圖距離這條連線的最遠(yuǎn)點(diǎn)就為峰谷,及閾值。

    原理:

    import numpy as npdef calcGrayHist(image):#灰度圖像矩陣的高,寬rows,cols = image.shape#存儲(chǔ)灰度直方圖grayHist = np.zeros([256],np.uint64)for r in xrange(rows):for c in xrange(cols):grayHist[image[r][c]] +=1 #這里應(yīng)該指的是,image[r][c]對(duì)應(yīng)灰度數(shù)值,在grayHist上+1return grayHistdef threshTwoPeaks(image):#計(jì)算灰度直方圖histogram = calcGrayHist(image)#找最大峰頂maxLoc = np.where(histogram==np.max(histogram))firstPeak = maxLoc[0][0]#尋找第二個(gè)峰值對(duì)應(yīng)的灰度值measureDists = np.zeros([256],np.float32)for k in xrange(256):measureDists[k] = pow(k-firstPeak,2)*histogram[k]maxLoc2 = np.where(measureDists==np.max(measureDists))secondPeak = maxLoc2[0][0]#找到兩個(gè)峰值間的最小值對(duì)應(yīng)的灰度值thresh = 0 #先給thresh賦值,不然無(wú)定義if firstPeak > secondPeak:temp = histogram[int(secondPeak):int(firstPeak)]minLoc = np.where(temp == np.min(temp))thresh = secondPeak + minLoc[0][0] + 1else:temp = histogram[int(firstPeak):int(secondPeak)]minLoc = np.where(np.min(temp))thresh = firstPeak + minLoc[0][0] + 1#找到閾值后,對(duì)圖像進(jìn)行閾值化處理threshImage_out = image.copy()#把src拷貝一份threshImage_out[threshImage_out>thresh]=255threshImage_out[threshImage_out<=thresh]=0return (thresh,threshImage_out) import cv2 import numpy as np import matplotlib.pyplot as pltsrc = cv2.imread("img7.jpg",0)#otsu the_otsu = 0 the_otsu,dst_otsu = cv2.threshold(src,the_otsu,255,8)#triangle the_tra = 0 the_tra,dst_tra = cv2.threshold(src,the_tra,255,16)#histogram the_hist = 0 the_hist,dst_hist = threshTwoPeaks(src)titles = ["src","otsu","tra","histogram"] images = [src,dst_otsu,dst_tra,dst_hist] for i in range(4):plt.subplot(1,4,i+1)plt.title(titles[i])plt.imshow(images[i]) plt.show()


    講道理,otsu自動(dòng)計(jì)算的更好

    6.3_熵算法

    • 熵算法使用信息論的概念,將圖像看做信源,來(lái)計(jì)算灰度級(jí)熵,一頓操作猛如虎計(jì)算出閾值,我反正沒(méi)看懂。
    • 結(jié)果與histogram相近
    # -*- coding: utf-8 -*- import sys import numpy as np import cv2 import math import matplotlib.pyplot as plt #計(jì)算圖像灰度直方圖 def calcGrayHist(image):#灰度圖像矩陣的寬高rows,cols = image.shape#存儲(chǔ)灰度直方圖grayHist = np.zeros([256],np.uint32)for r in xrange(rows):for c in xrange(cols):grayHist[image[r][c]] +=1return grayHist #熵閾值法 def threshEntroy(image):rows,cols = image.shape#求灰度直方圖grayHist = calcGrayHist(image)#歸一化灰度直方圖normGrayHist = grayHist/float(rows*cols)#計(jì)算累加直方圖,也稱零階累加矩zeroCumuMoment = np.zeros([256],np.float32)for k in xrange(256):if k==0:zeroCumuMoment[k] = normGrayHist[k]else:zeroCumuMoment[k] = zeroCumuMoment[k-1] + normGrayHist[k]#計(jì)算各個(gè)灰度級(jí)的熵entropy = np.zeros([256],np.float32)for k in xrange(256):if k==0:if normGrayHist[k] ==0:entropy[k] = 0else:entropy[k] = - normGrayHist[k]*math.log10(normGrayHist[k])else:if normGrayHist[k] ==0:entropy[k] = entropy[k-1]else:entropy[k] = entropy[k-1] - normGrayHist[k]*math.log10(normGrayHist[k])#找閾值fT = np.zeros([256],np.float32)ft1,ft2 = 0.0,0.0totalEntroy = entropy[255]for k in xrange(255):#找最大值maxFront = np.max(normGrayHist[0:k+1])maxBack = np.max(normGrayHist[k+1:256])if(maxFront == 0 or zeroCumuMoment[k] == 0 or maxFront==1 or zeroCumuMoment[k]==1 or totalEntroy==0):ft1 = 0else:ft1 =entropy[k]/totalEntroy*(math.log10(zeroCumuMoment[k])/math.log10(maxFront))if(maxBack == 0 or 1 - zeroCumuMoment[k]==0 or maxBack == 1 or 1-zeroCumuMoment[k] ==1):ft2 = 0else:if totalEntroy==0:ft2 = (math.log10(1-zeroCumuMoment[k])/math.log10(maxBack))else:ft2 = (1-entropy[k]/totalEntroy)*(math.log10(1-zeroCumuMoment[k])/math.log10(maxBack))fT[k] = ft1+ft2#找最大值的索引,作為得到的閾值threshLoc = np.where(fT==np.max(fT))thresh = threshLoc[0][0]#閾值處理threshold = np.copy(image)threshold[threshold > thresh] = 255threshold[threshold <= thresh] = 0return (threshold,thresh) #主函數(shù) image = cv2.imread("img7.jpg",0) #閾值處理 threshold,thresh = threshEntroy(image); #顯示閾值后的二值化圖像 cv2.imshow("threshEntroy",threshold) print thresh cv2.waitKey(0) cv2.destroyAllWindows() plt.title("entroy") plt.imshow(threshold) plt.show 95

    效果與histogram直方圖法差不多,原理太復(fù)雜

    6.4_Otsu

    終于要介紹Otsu算法了,Otsu算法是最大方差法。在前面已經(jīng)使用過(guò)了

    • otsu_thresh,dst_otsu =
      cv2.threshold(src,otsu_thresh,255,8)#最后的參數(shù)8代表cv2.THRESH_OTSU
    • 只支持8位圖

    原理:

    def calcGrayHist(image):rows,cols = image.shapegrayHist = np.zeros([256],np.unit64)for r in xrange(rows):for c in xrange(cols):grayHist[image[r][c]] += 1return grayHistdef otsu(image):rows,cols =image.shape#計(jì)算灰度直方圖histogram = calcGrayHist(image)#歸一化uniformGrayHist = grayHist/float(rows*cols)#計(jì)算零階累計(jì)矩和一階累積矩zeroCumuMoment = np.zeros([256],np.float32)oneCumuMoment = np.zeros([256],np.float32)for k in xrange(256):if k == 0:zeroCumuMoment[k] = uniformGrayHist[0]oneCumuMoment[k] = (k)*uniformGrayHist[0]else:zeroCumuMoment[k] = zeroCumuMoment[k-1] + uniformGrayHist[k]oneCumuMoment[k] = oneCumuMoment[k-1] + k*uniformGrayHist[k]#計(jì)算類間方差variance = np.zeros([256],np.float32)for k in xrange(255):if zeroCumuMoment(k) == 0 or zeroCumuMoment[k] ==1:variance[k] = 0else:variance[k] = math.pow(oneCumuMonet[255]*zeroCumuMoment[k] - oneCumuMoment[k],2)/(zeroCumuMoment[k]*(1.0-zeroCumuMoment[k]))#找到閾值threshLoc = np.where(variance[0:255] == np.max(variance[0:255]))thresh = threshLoc[0][0]#閾值處理threshold = np.copy(image)threshold[threshold > thresh] = 255threshold[threshold <=thresh] = 0return (threshold,thresh)

    Otsu核心在計(jì)算最大類間方差,找到其所在像素值也就對(duì)應(yīng)了閾值。效果相當(dāng)可以。

    6.5_自適應(yīng)閾值

    • 全局閾值分割以O(shè)tsu算法為首,表現(xiàn)出了很好的分割效果。缺點(diǎn)是對(duì)光照不均的圖面,全局閾值分割無(wú)法完全分割出主體。
    • 自適應(yīng)閾值算法針對(duì)每一個(gè)位置的灰度值設(shè)置相對(duì)應(yīng)的閾值。通過(guò)對(duì)圖像進(jìn)行平滑處理(均值(mean),高斯(Gaussian),中值(median)),計(jì)算像素鄰域的灰度均值,乘以比例系數(shù)(1-ratio),ratio一般取0.15,結(jié)果作為該像素的閾值參考值。
    • 平滑算子寬度決定分割出的物體尺寸,書(shū)本經(jīng)驗(yàn)提出,平滑算子寬度必須大于被識(shí)別物體的寬度。當(dāng)然,高寬為基數(shù)(平滑處理要求)

    原理:

    import cv2 import numpy as np import matplotlib.pyplot as plt #平滑處理采用均值平滑(cv2.blur或者cv2.boxFilter) def adaptiveThresh(I,winSize,ratio=0.15):#比例系數(shù)ratio一般0.15#第一步:圖像平滑I_mean = cv2.blur(I,winSize)#I_mean = cv2.boxFilter(I,cv2.CV_32FC1,winSize)#結(jié)果相同,但不知道blur沒(méi)有指定32位有沒(méi)有影響,等下試試#第二步:原圖與平滑結(jié)果做差out = I - (1.0-ratio)*I_mean#第三步: 當(dāng)差值大于或等于0,輸出255,;小于0,輸出0out[out>=0] = 255out[out<0] = 0out = out.astype(np.uint8)#圖像格式轉(zhuǎn)換為255,return outsrc = cv2.imread("image3.png",0) dst = adaptiveThresh(src,(7,7),0.15) plt.subplot(1,2,1) plt.imshow(src) plt.subplot(1,2,2) plt.imshow(dst) plt.show

    • PythonAPI:cv2.adaptiveThreshold(src,dst,maxValue,adaptiveMethod,thresholdType,blockSize,c)
    • maxValue:最大輸出灰度值
    • adaptiveMethod:
      ADAPTIVE_THRESH_MEAN_C:均值平滑
      ADAPTIVE_THRESH_GAUSSIAN_C:高斯平滑
      ADAPTIVE_THRESH_MEDIAN_C:中值平滑
    • thresholdType:THRESH_BINARY、THRESH_BINARY_INV
    • blockSIZE:滑動(dòng)窗口大小,原理里的winSize
    • C:比例算子,原理里的ratio
    import cv2 import matplotlib.pyplot as pltsrc = cv2.imread("image3.png",0)#Otsu算法 the_Otsu = 0 the_Otsu,dst_Otsu = cv2.threshold(src,the_Otsu,255,8)#用上面定義的adaptiveThresh進(jìn)行閾值分割 dst_adaptiveThresh = adaptiveThresh(src,(7,7),0.15)#7*7的自適應(yīng)算法,PythonAPI dst_adaptive_mean = cv2.adaptiveThreshold(src,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,0.15) dst_adaptive_gaussian = cv2.adaptiveThreshold(src,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,7,0.15)titles = ("src","Otsu","adp","adp_mean","adp_gaussian") images = (src,dst_Otsu,dst_adaptiveThresh,dst_adaptive_mean,dst_adaptive_gaussian)for i in xrange(5):plt.subplot(2,3,i+1)plt.title(titles[i])plt.imshow(images[i])cv2.imshow(titles[i],images[i]) plt.show() cv2.waitKey(0) cv2.destroyAllWindows()


    通過(guò)adaptiveThresh進(jìn)行閾值分割效果比OpencvAPI好一些,查找資料,嘗試對(duì)src先進(jìn)行平滑處理,再自適應(yīng)閾值分割

    重新編寫(xiě)的代碼如下

    import cv2 import matplotlib.pyplot as pltsrc = cv2.imread("image3.png",0)#Otsu算法 the_Otsu = 0 the_Otsu,dst_Otsu = cv2.threshold(src,the_Otsu,255,8)#用上面定義的adaptiveThresh進(jìn)行閾值分割 dst_adaptiveThresh = adaptiveThresh(src,(7,7),0.15)#7*7的自適應(yīng)算法,PythonAPI src_mean = cv2.blur(src,(7,7)) dst_adaptive_mean = cv2.adaptiveThreshold(src_mean,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7,0.15) src_gaussian = cv2.GaussianBlur(src,(7,7),5) dst_adaptive_gaussian = cv2.adaptiveThreshold(src_gaussian,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,7,0.15)titles = ("src","Otsu","adp","adp_mean","adp_gaussian") images = (src,dst_Otsu,dst_adaptiveThresh,dst_adaptive_mean,dst_adaptive_gaussian)for i in xrange(5):plt.subplot(2,3,i+1)plt.title(titles[i])plt.imshow(images[i])cv2.imshow(titles[i],images[i]) plt.show() cv2.waitKey(0) cv2.destroyAllWindows()


    效果稍微好一些,噪點(diǎn)去除了,但是邊框模糊了,還是沒(méi)有代碼實(shí)現(xiàn)的好。

    6.6_二值圖的邏輯運(yùn)算

    cv2.bitwise_and & cv2.bitwise_or 為與或運(yùn)算

    #-*-coding:utf-8 -*- import cv2 import numpy as np src1 = np.array([[255,0,255]]) src2 = np.array([[255,0,0]])#與運(yùn)算 dst_and = cv2.bitwise_and(src1,src2) #或運(yùn)算 dst_or = cv2.bitwise_or(src1,src2) print dst_and print dst_or [[255 0 0]] [[255 0 255]]

    總結(jié)

    以上是生活随笔為你收集整理的《OpenCV算法精解——基于Python与C++》第六章阈值分割的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。