阈值处理

阈值处理

阈值处理即图像二值化。是图像分割的一种最简单的方法。二值化可以把灰度图像转换成二值图像。把大于某个临界灰度值的像素灰度设为灰度极大值,把小于这个值的像素灰度设为灰度极小值,从而实现二值化。

简单阈值

ret, dst = cv2.threshold(src, thresh, maxval, type)

参数意义如下:

  • src: 输入图,只能输入单通道图像,通常来说为灰度图

  • thresh: 阈值

  • maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值

  • type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV

  • cv2.THRESH_BINARY :正向二值化,如果当前的像素值大于设置的阈值(thresh),则将该点的像素值设置为maxval;否则,将该点的像素值设置为0;
    具体的公式如下:
    \operatorname{dst}(x, y)=\left\{\begin{array}{ll}{\max \text { val }} & {\text { if } \operatorname{src}(x, y)>\text { thresh }} \\ {0} & {\text { otherwise }}\end{array}\right.

  • cv2.THRESH_BINARY_INV :反向二值化,如果当前的像素值大于设置的阈值(thresh),则将该点的像素值设置为0;否则,将该点的像素值设置为maxval;
    具体的公式如下:
    \operatorname{dst}(x, y)=\left\{\begin{array}{ll}{0} & {\text { if } \operatorname{src}(x, y)>\text { thresh }} \\ {\text { maxval }} & {\text { otherwise }}\end{array}\right.

  • cv2.THRESH_TRUNC :如果当前的像素值大于设置的阈值(thresh),则将该点的像素值设置为threshold;否则,将该点的像素值不变;
    具体的公式如下:
    \operatorname{dst}(x, y)=\left\{\begin{array}{ll}{\text { threshold }} & {\text { if } \operatorname{src}(x, y)>\text { thresh }} \\ {\operatorname{src}(x, y)} & {\text { otherwise }}\end{array}\right.

  • cv2.THRESH_TOZERO :如果当前的像素值大于设置的阈值(thresh),则将该点的像素值不变;否则,将该点的像素值设置为0;
    具体的公式如下:
    \operatorname{dst}(x, y)=\left\{\begin{array}{ll}{\operatorname{src}(x, y)} & {\text { if } \operatorname{src}(x, y)>\text { thresh }} \\ {0} & {\text { otherwise }}\end{array}\right.

  • cv2.THRESH_TOZERO_INV:如果当前的像素值大于设置的阈值(thresh),则将该点的像素值设置为0;否则,将该点的像素值不变;
    具体的公式如下:
    \operatorname{dst}(x, y)=\left\{\begin{array}{ll}{0} & {\text { if } \operatorname{src}(x, y)>\text { thresh }} \\ {\operatorname{src}(x, y)} & {\text { otherwise }}\end{array}\right.

例子

def cv_show(name,image):
    """图像显示函数
    name:字符串,窗口名称
    img:numpy.ndarray,图像
    """
    cv2.namedWindow(name,cv2.WINDOW_NORMAL)
    cv2.imshow(name,image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def img_show(name,image):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(image.shape) == 3:
        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    plt.imshow(image,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
if __name__=="__main__":
    
    image = cv2.imread('data/Pavlovsk_Railing_of_bridge_Yellow_palace_Winter.jpg')
    gray = cv2.cvtColor(image,cv2.COLOR_BGRA2GRAY)
    blurred = cv2.GaussianBlur(gray,(5,5),0)
    #('original image',image)
    
    (T,thresh_inv) = cv2.threshold(blurred,127,255,cv2.THRESH_BINARY_INV)
    #cv_show('original image',thresh_inv)
    image_mask = cv2.bitwise_and(gray,gray,mask = thresh_inv)
    #color = cv2.cvtColor(image_mask,cv2.COLOR_GRAY2BGR)
    
    #cv_show('image_mask',image_mask)
    
    plt.figure(figsize=(10,8),dpi=100)
    plt.subplot(131)
    img_show('original image',image)
    plt.subplot(132)
    img_show('thresh_inv',thresh_inv)
    plt.subplot(133)
    img_show('image_mask',image_mask)
thresh.png

自适应阈值

在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的
每一个小区域计算与其对应的阈值。因此,在同一幅图像上的不同区域采用的不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。这种方法需要我们指定三个参数,返回值只有一个。

cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C) 

参数意义如下:

  • src:原图,即输入图像,是一个8位单通道的图像;

  • maxValue:分配给满足条件的像素的非零值;

  • adaptiveMethod:自适应阈值的方法,通常有以下几种方法;

    (1)ADAPTIVE_THRESH_MEAN_C,阈值T(x,y)是(x,y)减去C的Blocksize×Blocksize邻域的平均值。

    (2)ADAPTIVE_THRESH_GAUSSIAN_C ,阈值T(x,y)是(x,y)减去C的Blocksize×Blocksize邻域的加权和(与高斯相关),默认sigma(标准差)用于指定的Blocksize;具体的情况可以参见getGaussianKernel函数;

  • thresholdType:阈值的类型必须是以下两种类型,

    (1)THRESH_BINARY,正向二值化

    (2)THRESH_BINARY_INV ,反向二值化

  • blockSize:像素邻域的大小,用来计算像素的阈值,blockSize必须为奇数,例如,3,5,7等等;

  • C:从平均数或加权平均数减去常量。通常,它是正的,但也可能是零或负数。

例子

def img_show(name,image):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(image.shape) == 3:
        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    plt.imshow(image,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
if __name__=="__main__":
    
    image = cv2.imread('data/text1.png')
    gray = cv2.cvtColor(image,cv2.COLOR_BGRA2GRAY)
    
    blurred = cv2.medianBlur(gray,1)
    #('original image',image)
    
    (T,thresh) = cv2.threshold(blurred,127,255,cv2.THRESH_BINARY)
    #cv_show('original image',thresh_inv)
    th1 = cv2.adaptiveThreshold(gray,255,
    cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)
    th1_1 = cv2.medianBlur(th1,5)
    th2 = cv2.adaptiveThreshold(gray,255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
    
    #color = cv2.cvtColor(image_mask,cv2.COLOR_GRAY2BGR)
    
    #cv_show('image_mask',image_mask)
    
    plt.figure(figsize=(7,10),dpi=100)
    plt.subplot(221)
    img_show('Original Image',gray)
    plt.subplot(222)
    img_show('Global Thresholding (v = 127)',thresh)
    plt.subplot(223)
    img_show('Adaptive Mean Thresholding',th1_1)
    plt.subplot(224)
    img_show('Adaptive Gaussian Thresholding',th2)
自适应阈值处理.png

OTSU(大津算法)

OTSU用来自动对基于聚类的图像进行二值化,或者说,将一个灰度图像退化为二值图像。该算法以大津展之命名。该算法假定该图像根据双模直方图(前景像素和背景像素)把包含两类像素,于是它要计算能将两类分开的最佳阈值,使得它们的类内方差最小;由于两两平方距离恒定,所以即它们的类间方差最大。

下面的例子中,输入图像是一副带有噪声的图像。第一种方法,我们设127 为全局阈值。第二种方法,我们直接使用 Otsu 二值化。第三种方法,我们首先使用一个 5x5 的高斯核除去噪音,然后再使用 Otsu 二值化。看看噪音去除对结果的影响有多大吧。

例子

def img_show(name,image):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(image.shape) == 3:
        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    plt.imshow(image,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
 
if __name__=="__main__":
    
    image = cv2.imread('data/noise.jpg')

    gray = cv2.cvtColor(image,cv2.COLOR_BGRA2GRAY)
    gray[100:300,100:700]=gray[100:300,100:700]+100
    (T,thresh) = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    #cv_show('original image',thresh_inv)
    (T,th1) = cv2.threshold(gray,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    blurred = cv2.GaussianBlur(gray,(5,5),0)
    
    (T,th2) = cv2.threshold(blurred,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    
    #color = cv2.cvtColor(image_mask,cv2.COLOR_GRAY2BGR)
    
    #cv_show('image_mask',image_mask)
    images = [gray, 0, thresh,gray, 0, th1,blurred, 0, th2]
    titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
              'Original Noisy Image','Histogram',"Otsu's Thresholding",
              'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
    plt.figure(figsize=(7,10),dpi=100)
    for i in range(3):
        plt.subplot(3,3,i*3+1)
        img_show(titles[i*3],images[i*3])
        plt.subplot(3,3,i*3+2)
        plt.hist(images[i*3].ravel(),256)
        plt.xlabel(titles[i*3+1])
        plt.xticks([])
        plt.yticks([])
        plt.subplot(3,3,i*3+3)
        img_show(titles[i*3+2],images[i*3+2])
otus.png

参考资料:
网址:https://zh.wikipedia.org/wiki/%E5%A4%A7%E6%B4%A5%E7%AE%97%E6%B3%95
书籍:《数字图像处理》《OpenCV-Python-Toturial-中文版》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343