欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCV threshold函数详解

程序员文章站 2022-05-20 22:14:33
...

threshold函数作用:

去掉噪,例如过滤很小或很大像素值的图像点。

threshold函数python版原型:

retval, dst = cv.threshold( src, thresh, maxval, type[, dst] ) 

参数说明:

src:原图像。

dst:结果图像。
thresh:当前阈值。
maxVal:最大阈值,一般为255.

thresholdType:阈值类型,主要有下面几种:

enum ThresholdTypes {
    THRESH_BINARY     = 0,
    THRESH_BINARY_INV = 1,
    THRESH_TRUNC      = 2,
    THRESH_TOZERO     = 3,
    THRESH_TOZERO_INV = 4,
    THRESH_MASK       = 7,
    THRESH_OTSU       = 8,
    THRESH_TRIANGLE   = 16
};

返回值:
 retval: 与参数thresh一致
dst: 结果图像

编号 阈值类型枚举
注意
1 THRESH_BINARY

2 THRESH_BINARY_INV

3 THRESH_TRUNC

4 THRESH_TOZERO

5 THRESH_TOZERO_INV

6 THRESH_MASK
不支持
7 THRESH_OTSU
不支持32位
8 THRESH_TRIANGLE
不支持32位

具体说明如下:

OpenCV threshold函数详解

注意:

THRESH_OTSU和THRESH_TRIANGLE是作为优化算法配合THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO以及THRESH_TOZERO_INV来使用的。

当使用了THRESH_OTSU和THRESH_TRIANGLE两个标志时,输入图像必须为单通道



生成关系:

OpenCV threshold函数详解


下面通过代码来验证一下threshold的用法:

import numpy as np
import cv2
#创建一个6x6的BGR三通道图片
img6x6 = np.zeros((6,6,3), dtype=np.uint8) 
#Blue通道取值0~99随机值
img6x6[:,:,0] = np.random.randint(0, 100, size=36).reshape(6,6)
#Green通道取值100~199随机值
img6x6[:,:,1] = np.random.randint(100, 200, size=36).reshape(6,6)
#Red通道取值200~255随机值
img6x6[:,:,2] = np.random.randint(200, 256, size=36).reshape(6,6)
print(img6x6)

得到img6x6的BGR三通道数据:

[[[ 62 171 226]
  [ 29 118 212]
  [ 61 151 200]
  [ 43 123 206]
  [ 58 146 232]
  [  2 124 246]]

 [[ 48 101 207]
  [ 32 194 228]
  [ 90 171 241]
  [ 36 152 244]
  [ 64 169 245]
  [ 71 106 202]]

 [[ 27 198 206]
  [ 39 193 213]
  [ 60 128 207]
  [ 53 134 248]
  [ 25 187 229]
  [ 72 116 229]]

 [[ 52 163 201]
  [ 39 189 251]
  [ 63 190 217]
  [ 73 139 212]
  [ 54 166 236]
  [ 43 191 200]]

 [[ 34 119 207]
  [ 36 110 209]
  [ 40 191 229]
  [ 60 100 228]
  [ 62 174 250]
  [ 41 115 209]]

 [[ 35 165 246]
  [ 50 182 218]
  [ 77 110 239]
  [ 44 106 245]
  [ 21 189 252]
  [ 64 144 241]]]

观察结果我们发现img6x6[2][2][1]=128,我们取该值作为thresh值来演示THRESH_BINARY、THRESH_BINARY_INV等的作用。

1) THRESH_BINARY

我们取参数值thresh=128,maxval=255,flag = THRESH_BINARY

cv2.threshold(img6x6, 128, 255, cv2.THRESH_BINARY)

根据前面对THRESH_BINARY flag值的解释:

OpenCV threshold函数详解

预期得到的结果中,img6x6中>128的值均应变为255,<=128的值均应变为0。

我们实际得到的结果为:

[[[  0 255 255]
  [  0   0 255]
  [  0 255 255]
  [  0   0 255]
  [  0 255 255]
  [  0   0 255]]

 [[  0   0 255]
  [  0 255 255]
  [  0 255 255]
  [  0 255 255]
  [  0 255 255]
  [  0   0 255]]

 [[  0 255 255]
  [  0 255 255]
  [  0   0 255]
  [  0 255 255]
  [  0 255 255]
  [  0   0 255]]

 [[  0 255 255]
  [  0 255 255]
  [  0 255 255]
  [  0 255 255]
  [  0 255 255]
  [  0 255 255]]

 [[  0   0 255]
  [  0   0 255]
  [  0 255 255]
  [  0   0 255]
  [  0 255 255]
  [  0   0 255]]

 [[  0 255 255]
  [  0 255 255]
  [  0   0 255]
  [  0   0 255]
  [  0 255 255]
  [  0 255 255]]]

与预期的结果一致。

2)THRESH_BINARY_INV

THRESH_BINARY_INV的作用与THRESH_BINARY相反,大于thresh的值置0,小于等于thresh的值置maxval:

OpenCV threshold函数详解

预期的结果与1)的结果完全相反。

code:

ret,dst=cv2.threshold(img6x6, 128, 255, cv2.THRESH_BINARY_INV)
print(dst)
dst输出:
[[[255   0   0]
  [255 255   0]
  [255   0   0]
  [255 255   0]
  [255   0   0]
  [255 255   0]]

 [[255 255   0]
  [255   0   0]
  [255   0   0]
  [255   0   0]
  [255   0   0]
  [255 255   0]]

 [[255   0   0]
  [255   0   0]
  [255 255   0]
  [255   0   0]
  [255   0   0]
  [255 255   0]]

 [[255   0   0]
  [255   0   0]
  [255   0   0]
  [255   0   0]
  [255   0   0]
  [255   0   0]]

 [[255 255   0]
  [255 255   0]
  [255   0   0]
  [255 255   0]
  [255   0   0]
  [255 255   0]]

 [[255   0   0]
  [255   0   0]
  [255 255   0]
  [255 255   0]
  [255   0   0]
  [255   0   0]]]

与预期结果完全一致。

3)THRESH_TRUNC

THRESH_TRUNC的作用是对大于thresh的值进行截断,其余值保留原值。

OpenCV threshold函数详解

code:

ret,dst=cv2.threshold(img6x6, 128, 255, cv2.THRESH_TRUNC)
print(dst)

dst输出:

[[[ 62 128 128]
  [ 29 118 128]
  [ 61 128 128]
  [ 43 123 128]
  [ 58 128 128]
  [  2 124 128]]

 [[ 48 101 128]
  [ 32 128 128]
  [ 90 128 128]
  [ 36 128 128]
  [ 64 128 128]
  [ 71 106 128]]

 [[ 27 128 128]
  [ 39 128 128]
  [ 60 128 128]
  [ 53 128 128]
  [ 25 128 128]
  [ 72 116 128]]

 [[ 52 128 128]
  [ 39 128 128]
  [ 63 128 128]
  [ 73 128 128]
  [ 54 128 128]
  [ 43 128 128]]

 [[ 34 119 128]
  [ 36 110 128]
  [ 40 128 128]
  [ 60 100 128]
  [ 62 128 128]
  [ 41 115 128]]

 [[ 35 128 128]
  [ 50 128 128]
  [ 77 110 128]
  [ 44 106 128]
  [ 21 128 128]
  [ 64 128 128]]]

4) THRESH_TOZERO

THRESH_TOZERO的作用是对大于thresh的值进行保留原值,小于或等于thresh的值置0:

OpenCV threshold函数详解

code:

ret, dst=cv2.threshold(img6x6, 128, 255, cv2.THRESH_TOZERO)
print(dst)

dst输出:

[[[  0 171 226]
  [  0   0 212]
  [  0 151 200]
  [  0   0 206]
  [  0 146 232]
  [  0   0 246]]

 [[  0   0 207]
  [  0 194 228]
  [  0 171 241]
  [  0 152 244]
  [  0 169 245]
  [  0   0 202]]

 [[  0 198 206]
  [  0 193 213]
  [  0   0 207]
  [  0 134 248]
  [  0 187 229]
  [  0   0 229]]

 [[  0 163 201]
  [  0 189 251]
  [  0 190 217]
  [  0 139 212]
  [  0 166 236]
  [  0 191 200]]

 [[  0   0 207]
  [  0   0 209]
  [  0 191 229]
  [  0   0 228]
  [  0 174 250]
  [  0   0 209]]

 [[  0 165 246]
  [  0 182 218]
  [  0   0 239]
  [  0   0 245]
  [  0 189 252]
  [  0 144 241]]]

5) THRESH_TOZERO_INV

THRESH_TOZERO_INV的作用与THRESH_TOZERO的作用完全相反,对大于thresh的值置0,其余值则保留:

OpenCV threshold函数详解

code:

ret, dst=cv2.threshold(img6x6, 131, 255, cv2.THRESH_TOZERO_INV)
print(dst)

dst输出:

[[[ 62   0   0]
  [ 29 118   0]
  [ 61   0   0]
  [ 43 123   0]
  [ 58   0   0]
  [  2 124   0]]

 [[ 48 101   0]
  [ 32   0   0]
  [ 90   0   0]
  [ 36   0   0]
  [ 64   0   0]
  [ 71 106   0]]

 [[ 27   0   0]
  [ 39   0   0]
  [ 60 128   0]
  [ 53   0   0]
  [ 25   0   0]
  [ 72 116   0]]

 [[ 52   0   0]
  [ 39   0   0]
  [ 63   0   0]
  [ 73   0   0]
  [ 54   0   0]
  [ 43   0   0]]

 [[ 34 119   0]
  [ 36 110   0]
  [ 40   0   0]
  [ 60 100   0]
  [ 62   0   0]
  [ 41 115   0]]

 [[ 35   0   0]
  [ 50   0   0]
  [ 77 110   0]
  [ 44 106   0]
  [ 21   0   0]
  [ 64   0   0]]]

6)THRESH_OTSU

THRESH_OTSU是需要搭配THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO以及THRESH_TOZERO_INV来使用的。并且输入图像必须是灰度图像。

所以,我们首先需要创建一个灰度图像:

code:

img_gray = cv2.cvtColor(img6x6,cv2.COLOR_BGR2GRAY)
print(img_gray)

得到的img_gray为:

[[175   0   0   0 162   0]
 [  0 186 183 166 180   0]
 [181 181   0 159 181   0]
 [162 190 184   0 174 177]
 [  0   0 185   0 184   0]
 [174 178   0   0 189 164]]

然后在通过THRESH_OTSU标准搭配其他标志位来对输入图像做处理,这里只演示搭配THRESH_BINARY标志的用法,

code:

ret,dst=cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO|cv2.THRESH_OTSU)
print(dst)

dst输出:

[[175   0   0   0 162   0]
 [  0 186 183 166 180   0]
 [181 181   0 159 181   0]
 [162 190 184   0 174 177]
 [  0   0 185   0 184   0]
 [174 178   0   0 189 164]]

对比一下不使用THRESH_OTSU时的输出,

code:

ret,dst=cv2.threshold(img_gray, 166, 255, cv2.THRESH_TOZERO)
print(dst)

dst输出:

[[175   0   0   0   0   0]
 [  0 186 183   0 180   0]
 [181 181   0   0 181   0]
 [  0 190 184   0 174 177]
 [  0   0 185   0 184   0]
 [174 178   0   0 189   0]]

7) THRESH_TRIANGLE

THRESH_TRIANGLE用法与THRESH_OTSU用法一致,这里不做演示。

综合示例

Demo Code

#encoding=utf-8


import sys, cv2, numpy as np
from ui_thresholdDemo import Ui_ThresoldDemo
from PyQt5.QtWidgets import QApplication, QWidget, QFileDialog
from PyQt5.QtGui import QImage, QPixmap


class ThresholdDemo(QWidget, Ui_ThresoldDemo):
    
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setupSigSlots()
        self.param_threshold = 1
        self.param_maxVal    = 255
        self.param_thresholdType = cv2.THRESH_BINARY
        self.param_ExtendType = 0
        self.checkGray = False
        
    def setupSigSlots(self):
        self.btnBrowse.clicked.connect(self.slotBtnBrowse)
        self.parmThreshold.valueChanged.connect(self.slotThresholdChanged)
        self.paramMaxVal.valueChanged.connect(self.slotMaxValChanged)
        self.parmThresholdType.currentTextChanged[str].connect(self.slotThresholdTypeChanged)
        self.btnCheckGray.toggled.connect(self.slotCheckGray)
        self.parmThresholdType2.currentTextChanged[str].connect(self.slotThresholdType2Changed)
    
    def slotBtnBrowse(self):
        try:
            file, _ = QFileDialog.getOpenFileName(self, 'Open Image', 'D:\\tmp\\pics', '*.*', '*.*',)
            if file:
                self.imagePath.setText(file)
                img_init = cv2.imdecode(np.fromfile(file, dtype=np.uint8), -1)
                self.img_threshold = img_init.copy()
                cv2.cvtColor(img_init, cv2.COLOR_BGR2RGB, img_init)
                h,w,c = img_init.shape
                qImg = QImage(img_init, w, h, w*c, QImage.Format_RGB888)
                self.initPicFrame.setPixmap(QPixmap.fromImage(qImg))
                self.updateThresholdImage()
        except Exception as e:
            print(e)
            
    def updateThresholdImage(self):
        try:
            img = self.img_threshold.copy()
            if self.checkGray:
                img_gray = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
                cv2.cvtColor(img, cv2.COLOR_BGR2GRAY, img_gray)
                ret, img_threshold = cv2.threshold(img_gray, self.param_threshold, self.param_maxVal, self.param_thresholdType|self.param_ExtendType)
                print('thresh:{}, maxval:{}, flags:{}|{}'.format(self.param_threshold, self.param_maxVal, self.param_thresholdType, self.param_ExtendType))
                h,w = img_threshold.shape
                qImg = QImage(img_threshold, w, h, w, QImage.Format_Indexed8)
                self.thresholdPicFrame.setPixmap(QPixmap.fromImage(qImg))
            else:
                ret, img_threshold = cv2.threshold(img, self.param_threshold, self.param_maxVal, self.param_thresholdType)
                #ret: ret equals to self.param_threshold, it canbe ignored
                h,w,c = img_threshold.shape
                cv2.cvtColor(img_threshold, cv2.COLOR_BGR2RGB, img_threshold)
                qImg = QImage(img_threshold, w, h, w*c, QImage.Format_RGB888)
                self.thresholdPicFrame.setPixmap(QPixmap.fromImage(qImg))
        except Exception as e:
            print(e)
    
    def slotThresholdChanged(self, val):
        self.param_threshold = val
        self.labelThreshold.setText('threshold:{:>3}'.format(val))
        self.updateThresholdImage()
    
    def slotMaxValChanged(self, val):
        self.param_maxVal    = val
        self.labelMaxVal.setText(' maxValue:{:>3}'.format(val))
        self.updateThresholdImage()
    
    def slotThresholdTypeChanged(self, type):
        type_dic = {
            'THRESH_BINARY': cv2.THRESH_BINARY,
            'THRESH_BINARY_INV': cv2.THRESH_BINARY_INV,
            'THRESH_TRUNC': cv2.THRESH_TRUNC,
            'THRESH_TOZERO': cv2.THRESH_TOZERO,
            'THRESH_TOZERO_INV': cv2.THRESH_TOZERO_INV,
            #'THRESH_MASK': cv2.THRESH_MASK,
            #'THRESH_OTSU': cv2.THRESH_OTSU,
            #'THRESH_TRIANGLE': cv2.THRESH_TRIANGLE,
            }
        self.param_thresholdType = type_dic[type]
        #print(type,self.param_thresholdType )
        self.updateThresholdImage()
        
    def slotThresholdType2Changed(self, type):
        try:
            extend_type = {
                "THRESH_OTSU":cv2.THRESH_OTSU,
                "THRESH_TRIANGLE":cv2.THRESH_TRIANGLE
                }
            if type == 'NONE':
                self.param_ExtendType = 0
                self.checkGray = False
                self.btnCheckGray.setEnabled(True)
            else:
                self.param_ExtendType = extend_type[type]
                self.checkGray = True
                self.btnCheckGray.setEnabled(False)
                
            print('self.param_ExtendType: ', self.param_ExtendType)
            self.updateThresholdImage()
        except Exception as e:
            print(e)
            


    def slotCheckGray(self, bGray):
        self.checkGray = bGray
        self.updateThresholdImage()




def thresholdDemo():
    img6x6 = np.zeros((6,6,3), dtype=np.uint8)
    img6x6[:,:,0] = np.random.randint(0, 100, size=36).reshape(6,6)
    img6x6[:,:,1] = np.random.randint(100, 200, size=36).reshape(6,6)
    img6x6[:,:,2] = np.random.randint(200, 256, size=36).reshape(6,6)
    cv2.threshold(img6x6, 127, 255, cv2.THRESH_BINARY)




if __name__ == '__main__':
    qApp = QApplication(sys.argv)
    demo = ThresholdDemo()
    demo.show()
    qApp.exec_()









程序运行结果:

OpenCV threshold函数详解

完整Code下载,请点这里


相关标签: opencv threshold