S0.4 二值图与阈值化
二值图的定义
二值图是一种特殊的灰度图,即每个像素点要么是白(0),要么是黑(255)
无论是灰度图还是二值图都是用阈值化的知识。

二值图的应用
图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。
阈值化
二值化只是阈值化的一个特例。
阈值化就是设定一个阈值,使超过或者低于该阈值的像素变成某一个给定值。
二值化/阈值化方法
1,无脑简单判断
通过搜索灰度图每个像素,判断灰度值是否大于127 [(255+0)/2 = 127.5]
//二值化 一
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
Mat srcImage = imread("images/favorite/Lena.jpg", 0);
Mat dstImage;
srcImage.copyTo(dstImage);
int rows = srcImage.rows;
int cols = srcImage.cols * srcImage.channels();
for(int i = 0; i < rows; i++)
{
uchar* data = dstImage.ptr<uchar>(i);
for(int j = 0; j < cols; j++)
{
if(data[j] > 127)
data[j] = 255;
else
data[j] = 0;
}
}
imshow("Lena", dstImage);
waitKey(30000);
return 0;
}
opencv3函数threshold()实现
threshold是阈值化方法,也可以大材小用一下做二值化。
在imgproc.hpp中可以看到形参
//看函数参数
//CV_EXPORTS_W 就是double
CV_EXPORTS_W double threshold(
InputArray src, //第一个参数表示输入图像,必须为单通道灰度图。
OutputArray dst, //第二个参数表示输出图像,为单通道黑白图。
double thresh, //第三个参数表示阈值,例如127
double maxval, //第四个参数表示最大值,例如255
int type //第五个参数表示运算方法。
);
在OpenCV的imgproc\types_c.h中可以找到运算方法的定义。
/** Threshold types */
enum
{
CV_THRESH_BINARY =0, /**< value = value > threshold ? max_value : 0 */
CV_THRESH_BINARY_INV =1, /**< value = value > threshold ? 0 : max_value */
CV_THRESH_TRUNC =2, /**< value = value > threshold ? threshold : value */
CV_THRESH_TOZERO =3, /**< value = value > threshold ? value : 0 */
CV_THRESH_TOZERO_INV =4, /**< value = value > threshold ? 0 : value */
CV_THRESH_MASK =7,
CV_THRESH_OTSU =8, /**< use Otsu algorithm to choose the optimal threshold value;
combine the flag with one of the above CV_THRESH_* values */
CV_THRESH_TRIANGLE =16 /**< use Triangle algorithm to choose the optimal threshold value;
combine the flag with one of the above CV_THRESH_* values, but not
with CV_THRESH_OTSU */
};
实例:
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
using namespace cv;
int main()
{
Mat srcImage = imread("images/favorite/Lena.jpg", 0);
Mat dstImage;
threshold(srcImage, dstImage, 127, 255, 0);
imshow("Lena", dstImage);
waitKey(30000);
return 0;
}
2,Otsu算法(大律法或最大类间方差法)
大津法由大津(日本学者,名叫OTSU)于1979年提出,对图像Image,记t为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。图像的总平均灰度为:\(u=w0*u0+w1*u1\)。
我们的目标是从最小灰度值到最大灰度值找到一个合适的分隔值t(即阈值),遍历\(t\),当\(t\)使得值\(g=w0*(u0-u)^2+w1*(u1-u)^2\)最大时t即为分割的最佳阈值。对大津法可作如下理解:该式实际上就是类间方差值,阈值t分割出的前景和背景两部分构成了整幅图像,而前景取值u0,概率为 w0,背景取值u1,概率为w1,总均值为u,根据方差的定义即得该式。
因方差是灰度分布均匀性的一种度量,方差值越大,说明构成图像的两部分差别越大, 当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。
直接应用大津法计算量较大,因此我们在实现时采用了等价的公式\(g=w0*w1*(u0-u1)^2\)。(把u代入g得到)
OpenCV3 纯代码实现大津法
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst;
int best_t = 1;
long long best_g = 0;
for(int t = 1; t < 255; t++)
{
int u0 = 0;
int u1 = 0;
int num_of_u0 = 0;
int num_of_u1 = 0;
long long sum_of_u0 = 0;
long long sum_of_u1 = 0;
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
int pixel = src.at<uchar>(i, j);
if(pixel >= t)
{
num_of_u0++;
sum_of_u0+=pixel;
}
else
{
num_of_u1++;
sum_of_u1+=pixel;
}
}
}
if(num_of_u0 == 0 || num_of_u1 == 0)
continue;
u0 = sum_of_u0/num_of_u0;
u1 = sum_of_u1/num_of_u1;
long long g = num_of_u0*num_of_u1/(src.rows*src.cols)*(u1-u0)*(u1-u0);
// long long g = num_of_u0/(src.rows*src.cols)*num_of_u1/(src.rows*src.cols)*(u1-u0)*(u1-u0);精度太低,全是0
// long long g = num_of_u0*num_of_u1*(u1-u0)*(u1-u0);精度太高,容易产生误差
if(g > best_g)
{
best_g = g;
best_t = t;
}
}
printf("best_g:%d\nbest_t:%d\n", best_g, best_t);
threshold(src, dst, best_t, 255, 0);
imshow("Lena0", dst);
waitKey(0);
return 0;
}
当然你可以基于直方图,这样只需要遍历0-255像素就ok了。
OpenCV3 threshold算法调用Otsu阈值化
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst;
threshold(src, dst, 100, 127, THRESH_OTSU);
imshow("Lena0", dst);
waitKey(0);
return 0;
}
经过实验我们可以得到:当thresholdType为THRESH_OTSU时,thresh参数没有用了。
改进版本
OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。
算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。划分点就是求得的阈值。
OpenCV3函数adaptiveThreshold实现自适应阈值
在imgproc.hpp中找到adaptiveThreshold的形参
CV_EXPORTS_W void adaptiveThreshold(
InputArray src, //输入图像
OutputArray dst, //输出图像
double maxValue, //最大值,一般为255
int adaptiveMethod, //0或1
int thresholdType,
int blockSize, //bxb区域,必须奇数
double C //减去的常量
);
| adaptiveMethod参数 | 效果 |
|---|---|
| ADAPTIVE_THRESH_MEAN_C | bxb区域平均值-C |
| ADAPTIVE_THRESH_GAUSSIAN_C | bxb区域高斯加权平均值-C |
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1;
adaptiveThreshold(src, dst0, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 41, 0.0);
adaptiveThreshold(src, dst1, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 41, 0.0);
imshow("src", src);
imshow("mean", dst0);
imshow("gaussian", dst1);
waitKey(0);
return 0;
}

S0.4 二值图与阈值化的更多相关文章
- opencv删除二值图中较小的噪点色块
CvSeq* contour = NULL; double minarea = 100.0; double tmparea = 0.0; CFileDialog dlg(true); if (dlg. ...
- 用 Python 通过马尔可夫随机场(MRF)与 Ising Model 进行二值图降噪
前言 这个降噪的模型来自 Christopher M. Bishop 的 Pattern Recognition And Machine Learning (就是神书 PRML……),问题是如何对一个 ...
- c语言实现灰度图转换为二值图
将上篇得到的灰度图转换为二值图,读取像素数据,低于某一值置0,否则设置为255,为得到更好的效果不同图片应采用不同的值 /* 2015年6月2日11:16:22 灰度图转换为二值图 blog:http ...
- 使用OpenCV查找二值图中最大连通区域
http://blog.csdn.net/shaoxiaohu1/article/details/40272875 使用OpenCV查找二值图中最大连通区域 标签: OpenCVfindCoutour ...
- C语言实现将彩色BMP位图转化为二值图
CTF做了图片的隐写题,还没有形成系统的认识,先来总结一下BMP图的组成,并通过将彩色图转为二值图的例子加深下理解. 只写了位图二进制文件的格式和代码实现,至于诸如RGB色彩和调色板是什么的一些概念就 ...
- zw·准专利·高保真二值图细部切分算法
zw·准专利·高保真二值图细部切分算法 高保真二值图细部切分算法,是中国字体协会项目的衍生作品. 说准专利算法,是因为对于图像算法的标准不了解,虽然报过专利,但不是这方面的,需要咨询专 ...
- coco数据集标注图转为二值图python(附代码)
coco数据集大概有8w张以上的图片,而且每幅图都有精确的边缘mask标注. 后面后分享一个labelme标注的json或xml格式转二值图的源码(以备以后使用) 而我现在在研究显著性目标检测,需要的 ...
- 超越OpenCV速度的MorphologyEx函数实现(特别是对于二值图,速度是CV的4倍左右)。
最近研究了一下opencv的 MorphologyEx这个函数的替代功能, 他主要的特点是支持任意形状的腐蚀膨胀,对于灰度图,速度基本和CV的一致,但是 CV没有针对二值图做特殊处理,因此,这个函数对 ...
- BMP彩色转成黑色二值图
一天半把彩色bmp转成黑白了. 原理是: 第一步:读出位图数据的偏移位置:即第11个字节,用fseek即可. 然后将偏移位置之前的数据全部写入新的bmp图中. 第二步:用fseek移到位图数据这前,判 ...
随机推荐
- Kafka(一)简介
1.Kafka简介 Kafka已经被很多公司广泛应用,一款实时流式消息组件.发送消息端称为Producer,接收端称为Consumer,Kafka集群有多个kafka实例组成,每个实例称为broker ...
- Keras的一些功能函数
摘自: https://www.cnblogs.com/Anita9002/p/8136357.html 1.模型的信息提取 # 节点信息提取 config = model.get_config() ...
- 自适应rem.js
用rem.js来实现自适应屏幕大小,要注意border不用rem做单位 代码如下: (function (doc, win) { //orientationchange : 判断手机是水平方向还是垂 ...
- ueditor接入秀米编辑器
秀米编辑器用来编辑微信页面很方便,功能也比较强大.秀米提供了第三方编辑器接入的功能,接入方法可以参照官网示例:http://hgs.xiumi.us/uedit/ 但是这里有几点要注意: 1. 示例中 ...
- 为什么HashMap线程不安全,Hashtable和ConcurrentHashMap线程安全
HashMap源码 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final ...
- Linux Input子系统浅析(二)-- 模拟tp上报键值【转】
转自:https://blog.csdn.net/xiaopangzi313/article/details/52383226 版权声明:本文为博主原创文章,未经博主允许不得转载. https://b ...
- Java 入门
Java 入门 入门书籍 Java相关书籍: <Java编程思想> 算是比较经典和全面的书籍; 10章可以快速过一下,都是基本语法,不需要花太多时间. 中后段的一些章节,类型信息.泛型.容 ...
- 漫画:一招学会TCP的三次握手和四次挥手
TCP三次握手和四次挥手的问题在面试中是最为常见的考点之一.很多读者都知道三次和四次,但是如果问深入一点,他们往往都无法作出准确回答. 本篇尝试使用动画来对这个知识点进行讲解,期望读者们可以更加简单地 ...
- 删除 $PATH 路径下多余的文件地址
将如下去 多余文件删除就可以了
- VMware workstation 上克隆CentOS 6.x 系统后网卡无法启动的问题
在日常学习中,我们往往没有足够的物理机资源来搭建多节点的实验环境,一个比较好的解决方案就是利用虚拟机来模拟物理机完成实验. 这样一来,多节点操作系统的部署就可以利用VMware 自带的系统“克隆”功能 ...