简单高效的自适应阈值二值化 C语言的实现
来源:互联网 发布:第一个python web开发 编辑:程序博客网 时间:2024/05/16 10:33
简单高效的自适应阈值二值化 C语言的实现
关于自适应阈值二值化OpenCV中的源码,只从中移植出了部分内容,剩余内容凭借自己的理解进行的补充。本文中的二值化与OpenCV中所介绍的二值化方法最大的一个不同就是,对于模板的核大小,OpenCV中不管核大小为多大,其运行速度都是几乎一样,但是本文中的致命缺陷就是随着核大小的增大,运行速度也会变慢。我唯一能想到弥补这一缺陷的办法就是,核大小根据整个图片的大小自动适合,这样也基本能保证跟OpenCV源码的效率一致。这样做还有个合理的点就是,用一个很大的核去处理一张很小的图片实际上是没有必要的,核只要适合就好。
当然,如果读者有兴趣,有能力解决本文中的缺陷,楼主绝对支持,也欢迎相互学习与沟通。
其中boxFilter函数为未做归一化的均值滤波函数,_Gray为输入BMP灰度图图片的数据段部分,_Width为图片的宽,_Height为图片的高,_CoreSize为滤波核大小。
而函数adaptiveThreshold之中是调用的boxFilter。
void boxFilter( unsigned char* _Gray, const int _Width, const int _Height, int _CoreSize ){unsigned char* grayBorder = NULL;int* firstWidthBlock = NULL;int widthBorder = _Width + _CoreSize - 1;int heightBorder = _Height + _CoreSize - 1;int halfCore = (_CoreSize-1)>>1;int i = 0, j = 0, l = 0, n = 0;int coreCounts = 0;int stepWidthGray = (_Width + 3) & ~3;int stepWidthBorder = (widthBorder + 3) & ~3;firstWidthBlock = ( int *)malloc( _Width * sizeof(int) );memset(firstWidthBlock, 0, _Width * sizeof(int));grayBorder = ( unsigned char *)malloc( stepWidthBorder*heightBorder );memset( grayBorder, 0, stepWidthBorder*heightBorder );//全图置0for ( i = 0; i < _Height; i ++ )//灰度图嵌入边框图中间for ( j = 0; j < _Width; j ++ ){grayBorder[ ( i + halfCore )*stepWidthBorder + j + halfCore ] = _Gray[ i*stepWidthGray + j ];}for ( i = 0; i < _CoreSize; i ++ )for ( j = 0; j < _CoreSize; j ++ ) firstWidthBlock[0] += grayBorder[ i*stepWidthBorder + j ];for ( i = 1; i < _Width; i++ ){firstWidthBlock[i] += firstWidthBlock[i-1];for ( l = 0; l < _CoreSize; l ++ ){ firstWidthBlock[i] += grayBorder[ l*stepWidthBorder + i+_CoreSize-1 ] - grayBorder[ l*stepWidthBorder + i-1 ];}}for ( i = halfCore+1; i < heightBorder-halfCore; i ++ )for ( j = halfCore; j < widthBorder-halfCore; j ++ )//全图均值滤波{coreCounts = 0;for ( n = j-halfCore; n < j+halfCore; n ++ ) firstWidthBlock[j-halfCore] += grayBorder[ (i+halfCore)*stepWidthBorder + n ]- grayBorder[ (i-halfCore)*stepWidthBorder + n ];coreCounts = firstWidthBlock[j-halfCore];_Gray[ (i-halfCore)*stepWidthGray + j-halfCore ] = ( unsigned char)(coreCounts/(_CoreSize*_CoreSize));}}void adaptiveThreshold( const unsigned char* _Gray, unsigned char** _Binary, const int _Width, const int _Height, int _Block, int _Idelta, int _MaxValue ){int i = 0, j = 0;unsigned char _Tab[768] = {0};unsigned char* _GrayFilter = NULL;unsigned char* ptrBinary = NULL;int nRowBytes = (_Width + 3) & ~3;*_Binary = ( unsigned char *)malloc( nRowBytes*_Height );memset( *_Binary, 0, nRowBytes*_Height );ptrBinary = *_Binary;_GrayFilter = ( unsigned char *)malloc( nRowBytes*_Height );memcpy( _GrayFilter, _Gray, nRowBytes*_Height );boxFilter( _GrayFilter, _Width, _Height, _Block );for ( i = 0; i < 768; i ++ )//防止数据溢出的三倍tab_Tab[i] = ( unsigned char)( i-255 > -_Idelta ? _MaxValue : 0 );for ( i = 0; i < _Height; i ++ )//自适应阈值二值化核心代码for ( j = 0; j < _Width; j ++ )ptrBinary[ i*nRowBytes + j] = _Tab[ _Gray[ i*nRowBytes + j] - _GrayFilter[ i*nRowBytes + j]+ 255];}
去年年末一直忙写论文也没时间跟新这篇均值滤波的文章,其实去年代码已经写好,因为实习结束代码没有及时备份,于是那份与滤波窗口大小无关的均值滤波函数丢失,最近有时间于是又重新在Qt上用C++写了一份,现在吧代码贴出来:
#include <QCoreApplication>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>using namespace cv;using namespace std;int main(){ double duration; Mat src = imread("lena.jpg", 0); Mat dst(src.rows, src.cols, CV_8UC1, Scalar(0)), dst2; int coreSize = 31; int coreSizeHalf = (coreSize-1)/2; int coreSizeSquare = coreSize * coreSize; int imgRows = src.rows; int imgCols = src.cols;duration = static_cast<double>(getTickCount()); float temp = 0; Mat buffer(1, imgCols+coreSize-1, CV_32SC1, Scalar(0)); float *bufferPtr = buffer.ptr<float>(0); Mat borderSrc(imgRows+coreSize-1, imgCols+coreSize-1, CV_8UC1, Scalar(128)); for ( int i = 0; i < imgRows; i ++ )//边界填充 { uchar *imgRowPtr = src.ptr<uchar>(i); uchar *borderRowPtr = borderSrc.ptr<uchar>(i+coreSizeHalf); for ( int j = 0; j < imgCols; j ++ ) { borderRowPtr[j+coreSizeHalf] = imgRowPtr[j]; } } for ( int i = 0; i < coreSize; i ++ )//buffer初始化循环还是与coreSize相关 //暂时没有解决办法 { uchar *borderSrcPtr = borderSrc.ptr<uchar>(i); for ( int j = 0; j < buffer.cols; j ++ ) { bufferPtr[j] += borderSrcPtr[j]; } } uchar *dstPtrFirstRow = dst.ptr<uchar>(0);//第一行的均值滤波 temp = 0; for ( int n = 0; n < coreSize; n ++ ) { temp += bufferPtr[n]; } dstPtrFirstRow[0] = temp/coreSizeSquare;//第一行第一个像素的均值滤波 for ( int i = 1; i < imgCols; i ++ )//第一个像素之后的均值滤波 { temp += bufferPtr[i+coreSize-1] - bufferPtr[i-1];//使用向量法加速使循环与coreSize无关 dstPtrFirstRow[i] = temp/coreSizeSquare; } for ( int i = 1; i < imgRows; i ++ )//第一行之后的均值滤波 { uchar *dstPtr = dst.ptr<uchar>(i); for ( int r = 0; r < buffer.cols; r ++ )//buffer数据更新 { uchar *borderSrcPtrLast = borderSrc.ptr<uchar>(i-1); uchar *borderSrcPtrFirst = borderSrc.ptr<uchar>(i+coreSize-1); //使用向量发更新buffer的每个元素 bufferPtr[r] = bufferPtr[r] + borderSrcPtrFirst[r] - borderSrcPtrLast[r]; } temp = 0; for ( int n = 0; n < coreSize; n ++ ) { temp += bufferPtr[n]; } dstPtr[0] = temp/coreSizeSquare;//第一行之后每行的第一个元素滤波 for ( int j = 1; j < imgCols; j ++ )//第一个元素之后的滤波 { temp += bufferPtr[j+coreSize-1] - bufferPtr[j-1];//向量法加速使循环与coreSize无关 dstPtr[j] = temp/coreSizeSquare; } }duration = static_cast<double>(getTickCount()) - duration; duration /= getTickFrequency(); cout << duration << endl; namedWindow("dst", 0); imshow("dst", dst); blur(src,dst2,Size(31,31),Point(-1,-1)); namedWindow("dst2", 0); imshow("dst2", dst2); waitKey(0); return 0;}
dst是本文的与窗口大小无关的均值滤波函数结果,dst2是opencv自带的均值滤波结果:
仔细观察还是有一点不同的,本文的均值滤波颜色灰度更加淡,当然还是opencv自带的函数会比较好,在时间上,还是比opencv自带的均值滤波时间要慢一些,大家可以自行验证运行速度,因为计算机配置不同于是不贴出运行时间。对于本文算法运行时间比opencv自带的算法效率低,笔者分析有以下原因:
1、边界扩充函数占整体滤波算法的1/7~1/6的时间,边界扩充函数没有做优化,有兴趣的的朋友可以试试优化,有时间我也会去完成这个工作。
2、buffer 第一次初始化的时候还是与 coreSize 有关,暂时也没有解决方法。
3、关于图像像素引用并没有采用最高效的像素引用方法,时间有限,有时间我也会去完成这个工作。
以下是与窗口无关的均值滤波算法原理,也是笔者毕业论文中的一部分内容:
具体算法实施过程中要注意加速原理,不论是行运算,和列运算都可以加速,再就是涉及 uchar 和 float 的数据转换,一定要整体运算,整体赋值,否则结果会出问题。
0 0
- 简单高效的自适应阈值二值化 C语言的实现
- 自适应的阈值化
- 最大熵阈值分割算法的C语言实现
- OTSU算法提取图像阈值的C语言实现[转载】
- OTSU算法提取图像阈值的C语言实现
- OTSU算法提取图像阈值的C语言实现
- OTSU算法提取图像阈值的C语言实现
- OTSU算法提取图像阈值的C语言实现
- 高效的C语言
- OTSU方法计算图像二值化的自适应阈值
- OTSU方法计算图像二值化的自适应阈值
- OTSU方法计算图像二值化的自适应阈值
- OpenCV_基于局部自适应阈值的图像二值化
- OpenCV_基于局部自适应阈值的图像二值化
- OpenCV基于局部自适应阈值的图像二值化
- OpenCV基于局部自适应阈值的图像二值化
- 图像分割自适应阈值的求取
- 带有 mask 的 OTSU 自适应阈值
- vim 备忘录
- sprintf 的那点事
- C#中Properties.Settings.Default
- Android与服务器间数据传递及JSON解析
- android判断应用是否有某个权限
- 简单高效的自适应阈值二值化 C语言的实现
- C++中堆、栈中的数据
- MVC4微信支付报警例子
- 在service中定义其它对象指针时用智能指针
- Hbase + Mapreduce + eclipse实例
- 11.2.2 测试结构相等
- Linux下VLAN功能的实现
- wp-autopost采集万方数据
- Android源代码调试中logcat的简单使用