1、简单阈值设置

  像素值高于阈值时,给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。这个函数就是 cv2.threshhold()。这个函数的第一个参数就是原图像,原图像应该是灰度图。第二个参数就是用来对像素值进行分类的阈值。第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。 OpenCV提供了多种不同的阈值方法,这是有第四个参数来决定的。这些方法包括:
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV

上图摘选自《学习 OpenCV》中文版
  这个函数有两个返回值,第一个为 retVal,我们后面会解释。第二个就是阈值化之后的结果图像了.
  为了同时在一个窗口中显示多个图像,我们使用函数 plt.subplot(),可以通过查看 Matplotlib 的文档获得更多详细信息

import cv2
import numpy as np
from matplotlib import pyplot as plt img = cv2.imread('image/lufei.jpeg',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','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()

结果图:

2 、自适应阈值

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

• Adaptive Method- 指定计算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域的加权和,权重为一个高斯窗口。
• Block Size - 邻域大小(用来计算阈值的区域大小)。
• C - 这就是是一个常数,阈值就等于的平均值或者加权平均值减去这个常数。
  使用下面的代码来展示简单阈值与自适应阈值的差别:

import cv2
import numpy as np
from matplotlib import pyplot as plt img = cv2.imread('image/lufei.jpeg',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','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()

结果图:

3 、Otsu’s 二值化

  在第一部分中我们提到过 retVal,当我们使用 Otsu
二值化时会用到它。那么它到底是什么呢?在使用全局阈值时,就是随便给了一个数来做阈值,那我们怎么知道选取的这个数的好坏呢?答案就是不停的尝试。如果是一幅双峰图像(双峰图像是指图像直方图中存在两个峰)我们岂不是应该在两个峰之间的峰谷选一个值作为阈值?这就是
Otsu 二值化要做的。简单来说就是对一幅双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法得到的结果可能会不理想)。
  这里用到到的函数还是 cv2.threshold(),但是需要多传入一个参数(flag): cv2.THRESH_OTSU。这时要把阈值设为
0。然后算法会找到最优阈值,这个最优阈值就是返回值 retVal。如果不使用 Otsu 二值化,返回的retVal 值与设定的阈值相等。
  下面的例子中,输入图像是一副带有噪声的图像。第一种方法,设127 为全局阈值。第二种方法,直接使用 Otsu 二值化。第三种方法,首先使用一个 5x5 的高斯核除去噪音,然后再使用 Otsu 二值化。看看噪音去除对结果的影响有多大吧。

import cv2
import numpy as np
from matplotlib import pyplot as plt img = cv2.imread('image/lufei.jpeg',0)
ret1,th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret2,th2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
blur = cv2.GaussianBlur(img, (5,5), 0)
ret3,th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
images = [img,0,th1,img,0,th2,blur,0,th3]
titles = ['Original Noisy Image','Histogram','Global Threshilding(v = 127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian fifltered 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()

结果图:

4 、Otsu’s 二值化是如何工作的

  在这一部分演示怎样使用 Python 来实现 Otsu 二值化算法,从而告诉大家它是如何工作的。因为是双峰图, Otsu 算法就是要找到一个阈值(t), 使得同一类加权方差最小,需要满足下列关系式:

  其实就是在两个峰之间找到一个阈值 t,将这两个峰分开,并且使每一个峰内的方差最小。实现这个算法的 Python 代码如下:

import cv2
import numpy as np img = cv2.imread('image/lufei.jpeg',0)
blur = cv2.GaussianBlur(img, (5,5), 0)
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])
q1,q2 = Q[i],Q[255]-Q[i]
b1,b2 = np.hsplit(bins, [i])
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
fn = v1*q1 + v2*q2
if fn < fn_min:
fn_min = fn
thresh = i
ret,otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print thresh,ret
 

opencv图像阈值设置的三种方法的更多相关文章

  1. opencv 3.1.0 访问像素值的三种方法(C++)

    三种方法分别问: 指针访问:void colorReduce_ptr(cv::Mat &inputImage, cv::Mat &outputImage, int div); 迭代器访 ...

  2. Halcon一日一练:读取文件目录图像的三种方法

    第一种方法: 读了一个单一图像: read_image(Image,'fabrik') 这种方式可以快速的读取软件自身携带的库图像文件,系统设定了库图像映像文件的快速读取方式,我们也可以通过绝对地址的 ...

  3. 【Android】Eclipse自动编译NDK/JNI的三种方法

    [Android]Eclipse自动编译NDK/JNI的三种方法 SkySeraph Sep. 18th  2014 Email:skyseraph00@163.com 更多精彩请直接访问SkySer ...

  4. c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)

    c#封装DBHelper类   public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...

  5. 【Android】Eclipse自己主动编译NDK/JNI的三种方法

    [Android]Eclipse自己主动编译NDK/JNI的三种方法 SkySeraph Sep. 18th  2014 Email:skyseraph00@163.com 一.Eclipse关联cy ...

  6. Qt 设置背景图片3种方法(三种方法:QPalette调色板,paintEvent,QSS)

    方法1. setStylSheet{"QDialog{background-image:url()"}}  //使用styleSheet 这种方法的好处是继承它的dialog都会自 ...

  7. vue自定义指令,比onerror更优雅的方式实现当图片加载失败时使用默认图,提供三种方法

    首先,来看下效果图(演示一下图片正常加载与加载失败时的效果) 在线体验地址:https://hxkj.vip/demo/vueImgOnerror/ 一.常规方法解决 我们都知道,img标签支持one ...

  8. 像画笔一样慢慢画出Path的三种方法(补充第四种)

    今天大家在群里大家非常热闹的讨论像画笔一样慢慢画出Path的这种效果该如何实现. 北京-LGL 博客号@ligl007发起了这个话题.然后各路高手踊跃发表意见.最后雷叔 上海-雷蒙 博客号@雷蒙之星 ...

  9. JAVA之线程同步的三种方法

    最近接触到一个图片加载的项目,其中有声明到的线程池等资源需要在系统中线程共享,所以就去研究了一下线程同步的知识,总结了三种常用的线程同步的方法,特来与大家分享一下.这三种方法分别是:synchroni ...

随机推荐

  1. nyoj448 寻找最大数

    寻找最大数 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 请在整数 n 中删除m个数字, 使得余下的数字按原次序组成的新数最大. 比方当n=920813467185 ...

  2. 【转】Android Fragment中使用SurfaceView切换时闪一下黑屏的解决办法

    重构了下之前自己的一个新闻客户端,全部使用了Fragment来进行页面切换,只有一个入口Activity作为程序的启动Activity,其中有一个界面需要调用摄像头识别二维码, 于是就会用到Surfa ...

  3. Hadoop之父Doug Cutting:Lucene到Hadoop的开源之路

    Hadoop之父Doug Cutting:Lucene到Hadoop的开源之路 Doug Cutting,凭借自己对工作的热情和脚踏实地的态度,开创了Lucene和Nutch两个成功的开源搜索引擎项目 ...

  4. JAVA小记(一)

    java中向上转型.向下转型.内部类中所需注意的问题: 向上转型与向下转型: 举个例子:有2个类,Father是父类,Son类继承自Father. Father f1 = new Son();   / ...

  5. Wannafly挑战赛19 A-队列Q

    题目描述 ZZT 创造了一个队列 Q.这个队列包含了 N 个元素,队列中的第 i 个元素用 Qi 表示.Q1 表示队头元素,QN 表示队尾元素.队列中的元素是 N 的一个全排列. ZZT 需要在这个队 ...

  6. Ubuntu下搭建repo服务器(三): 搭建Android repo服务器

    1. 配置repo 1.1  下载git-repo.git(B端) mkdir -p ~/gitCfg cd ~/gitCfg git clone https://gerrit.googlesourc ...

  7. Elasticsearch之CURL命令的mget查询

    我这里, 再,创建一个zhouls2的索引库. [hadoop@master elasticsearch-]$ curl -XPUT 'http://master:9200/zhouls2/' {]$ ...

  8. MyBatis分页组件--PageHelper

    一.介绍 PageHelper是国内非常优秀的一款开源的 mybatis 分页插件,它支持基本主流与常用的数据库,例如 Oracle.Mysql.MariaDB.SQLite.Hsqldb 等. 官网 ...

  9. sql 列集合转换成逗号分隔的字符类型

    CREATE function [dbo].[getGroupPath](@groupId int) returns nvarchar(2000) as begin declare @path nva ...

  10. [ NOIP 2002 ] TG

    \(\\\) \(\#A\) 均分纸牌 有\(N\)堆纸牌,每堆有若干张,但纸牌总数必为\(N\)的倍数.可以在任一堆上取若干张纸牌,然后移动给其左右任意一侧的纸牌堆,求将所有的牌堆牌数都变为平均值最 ...