Opencv图像阈值之Otsu’s二值化

今天我们来学习Opencv图像阈值之Otsu’s二值化,大家看到Hungry Lips的作品了吗?看了她的作品,我感觉打了鸡血一样的充满力量。

啥是Otsu’s 二值化呢?

往下看,具体例子中看

我们来看张图

小海豹来了~

我来解释一下这些都是什么

  • Original Noisy Image:这是原图像
  • Histogram:直方图
  • Global Thresholding:全局阈值
  • Otsu’s Thresholding:Otsu’s 阈值
  • Gaussian filtered Image:高斯过滤图像

-啊!我的眼睛,我怎么看不出有什么不一样!

-啊!我的眼睛,我也看不出有什么不一样!

我们来听下书面的解释:

 

============================================================

Otsu又叫大津法,也叫最大类间方差法,是一种自适应的阈值确定的方法,它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均
灰度记为μ,类间方差记为g。假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:

==============================================================

到此为止吧,我的眼睛又瞎了。。。

我就知道你们不会去看的,

所以我先上代码

# -*- coding:utf-8 -*-
"""
Created on Mon Mar 6 19:35:55 2017

@author: Y

"""

import cv2  
import numpy as np  
from matplotlib import pyplot as plt  
 
img = cv2.imread('C:\Users\Administrator\Desktop\opencvimg\haibaobaobao.jpg',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
# (5,5)为高斯核的大小,0为标准差
blur = cv2.GaussianBlur(img,(5,5),0)
# 阈值设为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()
cv2.waitKey(0)
cv2.destroyAllWindows()

 

 

代码中用了三种方法:

  1. 127为全局阈值
  2. 直接使用Otsu二值化
  3. 先用5*5 的高斯核去噪,然后使用Otsu二值化

其实就是在

cv2.threshold的基础上多传了个参数,cv2.THRESH_OTSU,

这时我们把阈值设为0,

算法会自动找到最优阈值retVal。

 

我说下我的理解吧:

我们把图像分为前景和背景两部分

图像整体:

  • 分割阈值T
  • 大小M*N
  • 图像的总平均灰度b
  • 类间方差g

前景:

  • 像素点数占整幅图的比例为a1
  • 平均灰度b1

背景:

  • 像素点数占整幅图的比例为a2
  • 平均灰度b2

 

则:

  • a1=b1/(M*N)
  • a2=b2/(M*N)
  • a1+a2=1
  • b1+b2=1
  • b=a1*b1+a2*b2
  • g=a1(b1-b)^2 +a2(b2-b)^2

结合最后两个得:

b=a1*a2(b1-b2)^2

(ps:^是平方)

Otsu标准是:

类间方差最大的分割意味着错分概率最小。

 

然后我们可以用便利的方法得到使类间方差最大的阈值T(retVal)

给出原图像

这张可爱的海豹宝宝就是原图像

 

大家也可以拿别的图试试!

Opencv图像阈值之Otsu’s阈值,写完这一章我整整用了两天的空闲时间,去组织语言与简化,今天终于发出来了,终于可以去睡个好觉了!我知道自己这一章还有提升的空间,但我真的尽力了,不知道如何再去写的更加具有可读性。这一章对于日后的大项目而言真的至关重要,整整好几个小时就是为了以后的顺利进行,所以大家务必务必好好理解。我是Y,希望大家坚定向前!

 

Opencv图像阈值之自适应阈值

美好的一个晚上,让我们来学习下Opencv图像阈值之自适应阈值吧!开车啦!

我们来回顾一下什么是简单阈值?

用一句话来说就是:

当图像像素值高于/低于阈值时做出什么情况的变化。

 

今天我们的自适应阈值是啥呢?

用一句话来说:

在图像内不同区域采用不同的阈值处理以得到更好的结果。

 

我们先来看一组效果图:

看下效果图先~

我来说一下具体的内容:

Original Image:这个是原图像;

Global Thresholding(v = 127):全局阈值化;

Adaptive Mean Thresholding:自适应均值阈值;

Adaptive Gaussian Thresholding:自适应高斯阈值。

 

-MDZZ,说的啥我一点都看不懂。说人话!

-按上边顺序,我说下大白话(●—●)

第一个:原图像就是你准备的那个图

第二个:设个阈值全图像都按简单阈值处理

(ps:简单阈值蒙圈的,回 去 看!附链接:

http://opencvblog.com/?p=385

第三个,第四个我也有点蒙圈

-这水平还出来教别人。。。

-我也是初学者,摸索着前进,数学不好伤不起,不过我会努力的!

 

我在这留下个记号:

到底第三第四个具体是什么意思。

 

下面我们来说一下具体的实现方法:

我们需要指定3个参数和一个返回值。

  • Adaptive Method(指定计算阈值的方法)

这个方法有两种:

               cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平均值;
               cv2.ADAPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域的加权和,
                                                                                                          权重为一个高斯窗口。
  • Block Size(邻域大小:用来计算阈值的区域大小)
  • C(是一个常数,阈值就等于平均值或者加权平均值减去这个常数,这个常数可以是负数。)

 

 

说实话,这一章还真是不好理解,既然难理解我们就要找到让它变得简单的办法。

我的办法就是多找几个图像试验下,

然后总结出到底哪种方法适合干什么。

 

我给出原图像:

dave.jpg原图像给大家

然后我们来试着写下代码:

老套路,

调用库,

读取图片,

我们的图片可能有噪声,需要进行一步处理:中值滤波,不懂不要担心,博主也不懂。(开个玩笑=。=,中值滤波简单来说就是去噪声,以后会接触到,我会详细的讲的~)

然后就是按3个参数来写方法,

其实我们说的返回值:就是三个参数一起得到一个返回值

(返回值到底是个啥?估计输出图像就是了吧。。。真是晕晕的LOL)

输出显示,

结束。

 

来上一下代码吧:

# -*- coding:utf-8 -*-
"""
Created on Thu Mar 2 20:24:06 2017

@author: Y

"""

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:\Users\Administrator\Desktop\opencvimg\haibaobaobao.jpg',0)

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()
cv2.destroyAllWindows()

 

再来上几张不同的图像效果:

可爱的小企鹅~
BeHappy~

 

小海豹~

别忘了先把图像灰度处理,要不会出错的啊!(在调用的图像后加0,你们还记得吗?)

我的肉眼实在是看不出第三第四啥分别,以后遇到这个一定会补充出来。

而且会补充出具体的使用地方。

这些图像的原图像在原来的章中都出现过,去找吧勇士!

 

这一章有些蒙圈啊,不过随着知识的积累,自然而然会得心应手的,学习Opencv是个精细活,一定不要半途而废。今天的内容有些多了,大家好好领悟下。我是Y,时间就在手中一点点的流逝了,我所说的Opencv的深水会随时间一点点的出现的,勇士们!穿上泳衣,我们去游泳吧!晚安~

Opencv图像阈值之简单阈值

我们来到了Opencv图像阈值之简单阈值,这一章图像阈值我尽量用最简洁的语言给大家讲解,让大家能更好的运用所学去做些有利于生活的事~

在本章的学习之前我强烈建议大家去复习一下《给图像加水印》

附上链接:http://opencvblog.com/?p=288

阈(yu)值:阈值是临界值的意思。

就是这么简单,

Opencv图像阈值之简单阈值:

设定一个临界值,

高于这个临界值,会出现什么情况;

低于这个临界值,会出现什么情况。

这就是简单与之的方法,不过这个“什么情况”是啥呢?

这个情况,我们要用参数来表示。

我来举个例子:

上一张图片,一会我们就用这张图片了~

这是原图像,不要怀疑你自己的眼睛,就是这个效果的图像,哈哈

我们先来设置一个阈值:127,

不知道大家回头看我推荐的那章了吗?

那一章就是用的简单阈值。

接下来我想说的话,都在那推荐的一章中,

下面我直接上代码,然后在最后坐下总结

# -*- coding:utf-8 -*-
"""
Created on Mon Feb 27 10:35:52 2017

@author: Y

"""

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:\Users\Administrator\Desktop\opencvimg\gradient.png')
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()
cv2.destroyAllWindows()

 

看一下最后的效果图吧~

看下效果图,我来解释下

Original Image:这是原图像;

BINARY:这是原图像的黑白阈值;

BINARY_INV:这是原图像的黑白阈值的反转;

TRUNC:这是原图像的的多像素处理(也叫截断阈值);

cv2.THRESH_TOZERO :这是原图像的0阈值;

cv2.THRESH_TOZERO_INV :这是原图像的0阈值的反转。

我们拿另一张图试一下:

另一张图片,拿去玩耍~

看看我们得到了什么?

第二张图的效果图~

这个没用matplotlib,而是直接用cv2.imshow()了,

一个一个输出放在一块给你们对比一下。

好啦,大家好好对比一下效果,认真理解一下这些处理究竟能干什么呢,在车牌识别的时候会很舒服的。

大家掌握的怎么样?大家一定要回头看我推荐的那章内容,链接就在片首,我是Y,欢迎大家来我的 网站做客。目前我们正在通往Opencv的大道上。以后会慢慢出现人脸识别,车牌识别,AR,VR的内容。大家拜拜喽~