图像阈值化-threshold、adaptivethreshold

在图像处理中阈值化操作,从一副图像中利用阈值分割出我们需要的物体部分(当然这里的物体可以是一部分或者整体)。这样的图像分割方法是基于图像中物体与背景之间的灰度差异,而且此分割属于像素级的分割。opencv的二值化操作函数,如果你是一位经验丰富的专业人员,可以发现阈值化操作有很多小技巧,不只是单单调用二值化操作函数,就完成阈值化操作,往往还是结合形态学处理。

阈值化操作在图像处理中是一种常用的算法,比如图像的二值化就是一种最常见的一种阈值化操作。opencv2和opencv3中提供了直接阈值化操作cv::threshold()和自适应阈值化操作cv::adaptiveThreshold()两种阈值化操作接口,这里将对这两个接口进行介绍和对比。本文将重点讲解两个函数的应用特点和应用场景,以及在使用的注意事项。

一、阈值化操作介绍

二进制阈值

阈值化类型如下式所示:

解释:在运用该阈值类型的时候,先要选定一个特定的阈值量,比如:125,这样,新的阈值产生规则可以解释为大于125的像素点的灰度值设定为最大值(如8位灰度值最大为255),灰度值小于125的像素点的灰度值设定为0。

反二进制阈值化

阈值类型如下式所示:

解释:该阈值化与二进制阈值化相似,先选定一个特定的灰度值作为阈值,不过最后的设定值相反。(在8位灰度图中,例如大于阈值的设定为0,而小于该阈值的设定为255)。

截断阈值化

该阈值化类型如下式所示:

解释:同样首先需要选定一个阈值,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变。(例如:阈值选取为125,那小于125的阈值不改变,大于125的灰度值(230)的像素点就设定为该阈值)。

阈值化为0

该阈值类型如下式所示:

解释:先选定一个阈值,然后对图像做如下处理:1 像素点的灰度值大于该阈值的不进行任何改变;2 像素点的灰度值小于该阈值的,其灰度值全部变为0。

反阈值化为0

该阈值类型如下式所示:

解释:原理类似于0阈值,但是在对图像做处理的时候相反,即:像素点的灰度值小于该阈值的不进行任何改变,而大于该阈值的部分,其灰度值全部变为0。

二、直接阈值化—THRESHOLD

2.1 代码说明

threshold(src,thresh,maxval, type,dst=None)#输出图像
src:原图像。

thresh:当前阈值。

maxVal:最大阈值,一般为255.

thresholdType:阈值类型,主要有下面几种:
enum { THRESH_BINARY=0, THRESH_BINARY_INV=1,
THRESH_TRUNC=2, THRESH_TOZERO=3,
THRESH_TOZERO_INV=4};

在二值化操作中常用的阈值类型为THRESH_BINARY,THRESH_BINARY_INV,但在二值化操作中有个特殊的阈值化操作为Otsu算法。

2.2 Otsu算法

算法的主要思想是,在进行阈值化时,考虑所有可能的阈值,分别计算低于阈值和高于阈值像素的方差,使下式最小化的值作为阈值:

其中,两类像素方差的权值由两类像素的个数决定。这种阈值化的结果相对来说比较理想,可以避免寻找合适阈值的操作,但是这种方式运算量较大,费时。

对图像Image,记t为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。图像的总平均灰度为:u=w0*u0+w1*u1。从最小灰度值到最大灰度值遍历t,当t使得值g=w0*(u0-u)2+w1*(u1-u)2 最大时t即为分割的最佳阈值。对大津法可作如下理解:该式实际上就是类间方差值,阈值t分割出的前景和背景两部分构成了整幅图像,而前景取值u0,概率为 w0,背景取值u1,概率为w1,总均值为u,根据方差的定义即得该式。因方差是灰度分布均匀性的一种度量,方差值越大,说明构成图像的两部分差别越大, 当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。

img = cv2.imread(‘noisy2.png‘,0)
blur = cv2.GaussianBlur(img,(5,5),0)
# find normalized_histogram, and its cumulative distribution function
hist = cv2.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()
bins = np.arange(256)
fn_min = np.inf
thresh = -1
for i in xrange(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
    q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
    b1,b2 = np.hsplit(bins,[i]) # weights
    # finding means and variances
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2
    # calculates the minimization function
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i
# find otsu‘s threshold value with OpenCV function
ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )

其中:numpy.hsplit表示为:https://docs.scipy.org/doc/numpy/reference/generated/numpy.hsplit.html

cv2.threshold函数是有两个返回值的,前面一直用的第二个返回值,也就是阈值处理后的图像,在简单的阈值处理上,我们选择的阈值都是127,那么实际情况下,怎么去选择这个127呢?有的图像可能阈值不是127得到的效果更好。Otsu’s就可以自己找到一个认为最好的阈值,并且Otsu’s非常适合于图像灰度直方图具有双峰的情况,他会在双峰之间找到一个值作为阈值,对于非双峰图像,可能并不是很好用。那么经过Otsu’s得到的那个阈值就是函数cv2.threshold的第一个参数了。因为Otsu’s方法会产生一个阈值,那么函数cv2.threshold的的第二个参数(设置阈值)就是0了,并且在cv2.threshold的方法参数中还得加上语句cv2.THRESH_OTSU。那么什么是双峰图像(只能是灰度图像才有),就是图像的灰度统计图中可以明显看出只有两个波峰,比如下面一个图的灰度直方图就可以是双峰图:

一个实例如下:

#简单滤波
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
#Otsu 滤波
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print ret2

上面中其中thresh直接设置为0,因为otsu算法可以直接计算一个合适的阈值,当然效率会比较低。

1.3 实验代码

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread(‘gradient.png‘,0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
titles = [‘Original Image‘,‘BINARY‘,‘BINARY_INV‘,‘TRUNC‘,‘TOZERO‘,‘TOZERO_INV‘]
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],‘gray‘)
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread(‘noisy2.png‘,0)
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu‘s thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu‘s thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = [‘Original Noisy Image‘,‘Histogram‘,‘Global Thresholding (v=127)‘,
          ‘Original Noisy Image‘,‘Histogram‘,"Otsu‘s Thresholding",
          ‘Gaussian filtered Image‘,‘Histogram‘,"Otsu‘s Thresholding"]
for i in xrange(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],‘gray‘)
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],‘gray‘)
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

看看上面的例子。输入图像是一个嘈杂的图像。在第一种情况下,我申请了一个价值127的全局阈值分割。在第二种情况下,我应用Otsu阈值直接。在第三的情况下,我与一个5x5高斯内核过滤图像去除噪声,然后利用Otsu阈值。看看噪声滤波改善结果。

三、自适应阈值化——cv::adaptiveThreshold()

上述的二值化本质上还是全局二值化,重点在于如何获取最佳阈值,这次我们讲解一种局部阈值方式,即opencv集成的自适应二值化。自适应阈值化能够根据图像不同区域亮度分布的,改变阈值。

void cv::adaptiveThreshold(
    cv::InputArray src, // 输入图像
    double maxValue, // 向上最大值
    int adaptiveMethod, // 自适应方法,平均或高斯
    int thresholdType // 阈值化类型
    int blockSize, // 块大小
    double C // 常量
);

cv::adaptiveThreshold()支持两种自适应方法,即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread(‘sudoku.png‘,0)
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,            cv2.THRESH_BINARY,11,2)
titles = [‘Original Image‘, ‘Global Thresholding (v = 127)‘,
            ‘Adaptive Mean Thresholding‘, ‘Adaptive Gaussian Thresholding‘]
images = [img, th1, th2, th3]
for i in xrange(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],‘gray‘)
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

四、参考文献

OTSU算法原理说明:文中对原理进行详细说明,并有代码进行实现。

官方阈值化操作说明:文中详细对各个函数进行详细介绍,很好。

阈值化操作——cv::threshold()与cv::adaptiveThreshold()详解:文中对这两种方法进行介绍,并进行编码测试。

时间: 2024-11-11 05:13:43

图像阈值化-threshold、adaptivethreshold的相关文章

opencv2函数学习之threshold:实现图像阈值化

在opencv2中,threshold函数可以进行阈值化操作. double threshold( const Mat& src, Mat& dst, double thresh,double maxVal, int thresholdType ); 参数: src:原图像. dst:结果图像. thresh:当前阈值. maxVal:最大阈值,一般为255. thresholdType:阈值类型,主要有下面几种: enum { THRESH_BINARY=0, THRESH_BINARY

opencv学习之路(13)、图像阈值化

一.图像阈值化简介 二.固定阈值 三.自适应阈值 1 #include<opencv2/opencv.hpp> 2 using namespace cv; 3 4 void main(){ 5 Mat src=imread("E://1.jpg",0);//以灰度模式读入 6 Mat dst; 7 //threshold(src,dst,100,255,CV_THRESH_BINARY); 8 //adaptiveThreshold(src,dst,255,CV_ADAPT

OpenCV实现图像阈值化

纯粹阅读,请移步OpenCV实现图像阈值化 效果图 源码 KqwOpenCVBlurDemo 阈值化是一种将我们想要在图像中分析的区域分割出来的方法. 我们把每个像素值都与一个预设的阈值做比较,再根据比较的结果调整像素值. 类似这样 Imgproc.threshold(src,src,100,255,Imgproc.THRESH_BINARY); 其中100是阈值,255是最大值(纯白色的值). 常量 名称 常量 二值阈值化 Imgproc.THRESH_BINARY 阈值化到零 Imgproc

openCV—Python(10)—— 图像阈值化处理

一.函数简介 1.threshold-图像简单阈值化处理 函数原型:threshold(src, thresh, maxval, type, dst=None) src:图像矩阵 thresh:阈值 maxVal:像素最大值 type:阈值化类型 2.adaptiveThreshold-图像自适应阈值化处理 函数原型:adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None) sr

自适应阈值化操作:adaptiveThreshold()函数

在图像阈值化操作中,更关注的是从二值化图像中,分离目标区域和背景区域,但是仅仅通过设定固定阈值很难达到理想的分割效果.而自适应阈值,则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值.这样做的好处: 1. 每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的. 2. 亮度较高的图像区域的二值化阈值通常会较高,而亮度低的图像区域的二值化阈值则会相适应的变小. 3. 不同亮度.对比度.纹理的局部图像区域将会拥有相对应的局部二值化阈值. 函数原型 1. void a

【数字图像处理】五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理具体解释

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说.主要通过MFC单文档视图实现显示BMP图片点运算处理.包含图像灰度线性变换.灰度非线性变换.图像阈值化处理.图像均衡化处理等知识,并结合前一篇论文灰度直方图进行展示 .同一时候文章比較具体基础,希望该篇文章对你有所帮助,尤其是刚開始学习的人和学习图像处理的学生. [数字图像处理]一.MFC具体解释显示BMP格式图片 [数字图像处理]二.MFC单文档切割窗体显示图片 [数字图像处理]

OpenCV阈值化处理

图像的阈值化就是利用图像像素点分布规律,设定阈值进行像素点分割,进而得到图像的二值图像.图像阈值化操作有多种方法,常用方法有经典的OTSU.固定阈值.自适应阈值.双阈值及半阈值化操作.这里对各种阈值化操作进行一个总结. OTSU阈值化 在阈值化处理中,常用的算法就是OTSU.发明人是Nobuyuki Ostu.这种二值化操作阈值的选取非常重要,阈值选取的不合适,可能得到的结果就毫无用处.简单的说,这种算法假设衣服图像由前景色和背景色组成.通过统计学的方法来选取一个阈值,使这个阈值可以将前景色和背

阈值化

一.固定阈值化Threshold()函数 double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type ); 二.自适应阈值操作:adaptiveThreshold()函数 void adaptiveThreshold( InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresh

OpenCV的阈值化函数threshold

在OpenCV中,threshold用来进行对图像(二维数组)的二值化阈值处理 通过查找OpenCV在线文档,发现存在很多函数: 其函数原型如下: 1. C版本的:函数原型: void cvThreshold( const CvArr* src, CvArr* dst, double threshold,double max_value, int threshold_type ); src,dst: 不必多说,其要求类型一致性: threshold:需要设置的阈值,当像素值大于某个数字时,设定一