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移到位图数据这前,判 ...
随机推荐
- 统一配置管理 windows linux ide maven gradle docker 【渐进式备份更新~~】
Tips 系统盘放轻量配置(%HOMEPATH%),仓库盘放大容量文件(自己维护一份 语义化目录结构.txt). Tips 系统盘放 不经常写操作的文件(除轻量配置) ...
- python的copy模块理解
首先直接上结论: —–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. —–而浅复制并不会产生一个独立的对 ...
- 20155324《网络对抗》Exp06 信息搜集与漏洞扫描
20155324<网络对抗>Exp06 信息搜集与漏洞扫描 实践内容 各种搜索技巧的应用 DNS IP注册信息的查询 基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 ...
- python-类对象以字典模式操作
#类对象以字典模式操作 class Person: def __init__(self): self.cache={} def __setitem__(self, key, value): #增加或修 ...
- 程序到CPU的路径
汇编 源码->编译->CPU C/C++ 源码->编译->机器码->系统(执行)->CPU Java/.NET 源码->编译->J字节码->虚拟机 ...
- ssm多数据源配置
1.在.properties配置文件中 添加第二个数据源信息(type2,driver2, url2,username2,pawwword2) 2.修改spring-context.xml(src/m ...
- sql的四种匹配模式
1. % 表示任意0个或多个字符.如下语句:Select * FROM user Where name LIKE '%三%'; 将会把name为“张三”,“三脚猫”,“唐三藏”等等有“三”的全找出来. ...
- Java并发编程之美之并发编程线程基础
什么是线程 进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一个进程至少有一个线程,进程的多个线程共享进程的资源. java启动main函数其实就 ...
- C++自己实现一个String类
C++自己实现一个String类(构造函数.拷贝构造函数.析构函数和字符串赋值函数) #include <iostream> #include <cstring> using ...
- Jquery笔记和ajax笔记
Jquery笔记:jQuery是一个JavaScript函数库,专为事件处理设计 1.jQuery的引入 <script text="type/javascript" src ...