adaptiveThreshold自适应二值化源码分析
自适应二值化介绍:
二值化算法是用输入像素的值I与一个值C来比较,根据比较结果确定输出值。
自适应二值化的每一个像素的比较值C都不同,比较值C由这个像素为中心的一个块范围计算在减去差值delta得到。
C的常用计算方法有两种:
1.平均值减去差值delta(使用盒过滤boxfilter,性能会非常不错)
2.高斯分布加权和减去差值delta (使用高斯滤波GaussionBlur)
只要高兴用什么其他方法都行。
最后,总算法就是用每一个像素的灰度值I,与所对应的比较值C,确定结果输出到对应的像素。
举个例子:如果使用平均值方法,平均值mean为190,差值delta为30。那么灰度小于160的像素为0,大于等于160的像素为255。如下图:

如果是反向二值化,如下图:

delta选择负值也是可以的。
opencv中adaptiveThreshold函数分析:
参数:
_src 要二值化的灰度图
_dst 二值化后的图
maxValue 二值化后要设置的那个值
method 块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)
type 二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)
blockSize 块大小(奇数,大于1)
delta 差值(负值也可以)
源码和注释如下:
/** @brief 自适应二值化
*@param _src 要二值化的灰度图
*@param _dst 二值化后的图
*@param maxValue 二值化后要设置的那个值
*@param method 块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)
*@param type 二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)
*@param blockSize 块大小(奇数,大于1)
*@param delta 差值(负值也可以)
*/
void cv::adaptiveThreshold(InputArray _src, OutputArray _dst, double maxValue,
int method, int type, int blockSize, double delta)
{
Mat src = _src.getMat(); // 原图必须是单通道无符号8位
CV_Assert(src.type() == CV_8UC1); // 块大小必须大于1,并且是奇数
CV_Assert(blockSize % == && blockSize > );
Size size = src.size(); // 构建与原图像相同的图像
_dst.create(size, src.type());
Mat dst = _dst.getMat(); if (maxValue < )
{
// 二值化后值小于0,图像都为0
dst = Scalar();
return;
} // 用于比较的值
Mat mean; if (src.data != dst.data)
mean = dst; if (method == ADAPTIVE_THRESH_MEAN_C)
// 计算平均值作为比较值
boxFilter(src, mean, src.type(), Size(blockSize, blockSize),
Point(-, -), true, BORDER_REPLICATE);
else if (method == ADAPTIVE_THRESH_GAUSSIAN_C)
// 计算高斯分布和作为比较值
GaussianBlur(src, mean, Size(blockSize, blockSize), , , BORDER_REPLICATE);
else
CV_Error(CV_StsBadFlag, "Unknown/unsupported adaptive threshold method"); int i, j; // 将maxValue夹到[0,255]的uchar范围区间,用作二值化后的值
uchar imaxval = saturate_cast<uchar>(maxValue); // 根据二值化类型计算delta值
int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta); // 计算生成每个像素差对应的值表格,以后查表就可以。但像素差范围为什么是768,我确实认为512已经够了
uchar tab[]; if (type == CV_THRESH_BINARY)
for (i = ; i < ; i++)
// i = src[j] - mean[j] + 255
// i - 255 > -idelta ? imaxval : 0
// = src[j] - mean[j] + 255 -255 > -idelta ? imaxval : 0
// = src[j] > mean[j] - idelta ? imaxval : 0
tab[i] = (uchar)(i - > -idelta ? imaxval : );
else if (type == CV_THRESH_BINARY_INV)
for (i = ; i < ; i++)
// i = src[j] - mean[j] + 255
// i - 255 <= -idelta ? imaxval : 0
// = src[j] - mean[j] + 255 - 255 <= -idelta ? imaxval : 0
// = src[j] <= mean[j] - idelta ? imaxval : 0
tab[i] = (uchar)(i - <= -idelta ? imaxval : );
else
CV_Error(CV_StsBadFlag, "Unknown/unsupported threshold type"); // 如果连续,加速运算
if (src.isContinuous() && mean.isContinuous() && dst.isContinuous())
{
size.width *= size.height;
size.height = ;
} // 逐像素计算src[j] - mean[j] + 255,并查表得到结果
for (i = ; i < size.height; i++)
{
const uchar* sdata = src.data + src.step*i;
const uchar* mdata = mean.data + mean.step*i;
uchar* ddata = dst.data + dst.step*i; for (j = ; j < size.width; j++)
// 将[-255, 255] 映射到[0, 510]然后查表
ddata[j] = tab[sdata[j] - mdata[j] + ];
}
}
源码很短小精悍,但查找表为什么是768的大小?512应该足够了:(
使用场景:
对灰度车牌图像做处理或阴阳车牌处理,效果比较行。blockSize根据算法确定。
Mat src = imread("d:\\src.jpg", );
Mat bw;
adaptiveThreshold(src, bw, , CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, , );
原图
的处理结果
OTUS二值化结果
自适应二值化结果
,去掉一些错误区域还算完美。
转载请注明出处,谢谢~
adaptiveThreshold自适应二值化源码分析的更多相关文章
- Java 序列化和反序列化(二)Serializable 源码分析 - 1
目录 Java 序列化和反序列化(二)Serializable 源码分析 - 1 1. Java 序列化接口 2. ObjectOutputStream 源码分析 2.1 ObjectOutputSt ...
- [UGUI]图文混排(二):Text源码分析
UGUI源码: https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=tags 首先下载一份UGUI源码,这里我下载的版本是5.3.2f ...
- 跟厂长学PHP7内核(二):源码分析的环境与工具
本文主要介绍分析源码的方式,其中包含环境的搭建.分析工具的安装以及源码调试的基本操作. 一.工具清单 PHP7.0.12 GDB CLion 二.源码下载及安装 $ wget http://php.n ...
- Flink源码阅读(二)——checkpoint源码分析
前言 在Flink原理——容错机制一文中,已对checkpoint的机制有了较为基础的介绍,本文着重从源码方面去分析checkpoint的过程.当然本文只是分析做checkpoint的调度过程,只是尽 ...
- [dpdk] 熟悉SDK与初步使用 (二)(skeleton源码分析)
接续前节:[dpdk] 熟悉SDK与初步使用 (一)(qemu搭建实验环境) 程序逻辑: 运行参数: 关键API: 入口函数: int rte_eal_init(int argc, char **ar ...
- DataMatrix二维条码源码分析检测识别图像位置
发布时间:2014-10-31 DataMatrix的代码结构和QR码基本相同: 其中Detector的功能还是从原始图像中找出符号码的部分,并且进行透视转换纠正扭曲. 其解码流程与QR码差不多,关键 ...
- keystone系列二:keystone源码分析
六 keystone架构 6.1 Keystone API Keystone API与Openstack其他服务的API类似,也是基于ReSTFul HTTP实现的. Keystone API划分为A ...
- 【Zookeeper】源码分析之Watcher机制(二)
一.前言 前面已经分析了Watcher机制中的第一部分,即在org.apache.zookeeper下的相关类,接着来分析org.apache.zookeeper.server下的WatchManag ...
- Java集合源码分析(二)Linkedlist
前言 前面一篇我们分析了ArrayList的源码,这一篇分享的是LinkedList.我们都知道它的底层是由链表实现的,所以我们要明白什么是链表? 一.LinkedList简介 1.1.LinkedL ...
随机推荐
- 我是如何通过一个 XSS 探测搜狐内网扫描内网并且蠕动前台到最后被发现的
我是如何通过一个 XSS 探测搜狐内网扫描内网并且蠕动前台到最后被发现的!(附带各种 POC) | WooYun-2014-76685 | WooYun.orghttp://wooyun.org/bu ...
- POJ 开关问题 1830【高斯消元求矩阵的秩】
Language: Default 开关问题 Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 6656 Accepted: ...
- Msfvenom 学习笔记与总结
平台:Android,可用Payload: android/meterpreter/reverse_http Run a meterpreter server on Android. Tunnel c ...
- Linux系统运维之路
九月份开始,半年内搞定运维,博客会慢慢的更新,vim编辑器,Nginx配置文件优化 运维基础 运维基础-Linux发展史.安装.基本操作 运维基础-用户和组管理 运维基础-文件权限管理 运维基础-进程 ...
- SpringBoot开启https以及http重定向
一.使用JDK keytool创建SSL证书 进入$JAVA_HOME/bin目录,运行以下命令 keytool -genkey -alias WeChatAppletsDemo -keypass - ...
- 【Python】Selenium元素定位错误之解决办法
当使用class定位元素时发现报错: 错误信息:selenium.common.exceptions.InvalidSelectorException: Message: Compound class ...
- linux环境tomcat配置及hadoop 2.6伪分布模式安装配置
一.ubuntu 15.04.openjdk1.7.tomcat7环境配置 1. 配置openjdk1.7,输入命令: -jdk 2. 查看java是否安装成功,输入命令: envjava -vers ...
- 膨胀和腐蚀 - cvErode() 和 cvDilate() 函数实现
前言 膨胀就是对图中的每个像素取其核范围内最大的那个值,腐蚀就相反.这两个操作常用来突出显示图的某个高亮部分或者昏暗部分以及去噪.本文展示两个分别对图像进行膨胀和腐蚀的例子. 膨胀和腐蚀函数 cvEr ...
- CString 成员函数用法大全(转)
CString( );例:CString csStr; CString( const CString& stringSrc );例:CString csStr("ABCDEF中文12 ...
- python爬虫入门篇
优质爬虫入门源码:https://github.com/lining0806/PythonSpiderNotes Python Spider:https://www.cnblogs.com/wangy ...