任意半径局部直方图类算法在PC中快速实现的框架。
在图像处理中,局部算法一般来说,在很大程度上会获得比全局算法更为好的效果,因为他考虑到了图像领域像素的信息,而很多局部算法可以借助于直方图获得加速。同时,一些常规的算法,比如中值滤波、最大值滤波、最小值滤波、表面模糊等等都可以通过局部直方图进行加速。而传统的获取局部直方图计算量很大,特别是半径增加时,耗时会成平方关系增加。一些局部算法只有在半径较大时才会获得很好的效果,因此,必须找到一种合适的加速计算局部直方图的方式。
在参考Median Filter in Constant Time.pdf一文附带的C的代码的基础上,本文提出了基于SSE加速的恒长任意半径局部直方图获取技术,可以大大加速算法的计算时间,特别是大半径时的提速更为明显。
主要的优化思路是,沿着列方向一行一行的更行整行的列直方图,新的一行对应的列直方图更新时只需要减去已经不再范围内的那个像素同时加入新进入的像素的直方图信息。之后,对于一行中的第一个像素点,累加半径辐射范围内的列直方图,得到改点的局部直方图,对于行中的其他的像素,则类似于更新行直方图,先减去不在范围内那列的列直方图,然后加上移入范围内的列直方图。由于采用了基于SSE函数的加速过程,直方图想加和相减的速度较普通的加减法有了10倍以上的提速,因此大大的提高了整体的实用性。
具体的过程我用代码加以说明:
1、一些公用的内存分配过程
TMatrix *Row = NULL, *Col = NULL;unsigned char *LinePS, *LinePD;int X, Y, K, Width = Src->Width, Height = Src->Height;int *RowOffset, *ColOffSet;unsigned short *ColHist = (unsigned short *)IS_AllocMemory(256 * (Width + 2 * Radius) * sizeof(unsigned short), true); if (ColHist == NULL) {Ret = IS_RET_ERR_OUTOFMEMORY; goto Done8;}unsigned short *Hist = (unsigned short *)IS_AllocMemory(256 * sizeof(unsigned short), true); if (Hist == NULL) {Ret = IS_RET_ERR_OUTOFMEMORY; goto Done8;}Ret = GetValidCoordinate(Width, Height, Radius, Radius, Radius, Radius, Edge, &Row, &Col); // 获取坐标偏移量if (Ret != IS_RET_OK) goto Done8;
其中的ColHist用于保存一行像素对应的列直方图 ,注意这里的行是用的扩展后的行的大小即:Width + 2 * Radius。IS_AllocMemory是个内部使用了_mm_malloc定义的内存分配函数,主要是考虑SSE函数的16字节对齐问题。
Hist变量用于保存每个像素点的局部直方图数据,任何基于局部直方图技术的函数最终都演变为对于该函数进行各种各样的计算。
GetValidCoordinate是一个用于辅助边界处像素点处理的函数,具体可详见附件中给出的代码。
2、更新一行像素的列直方图
for (Y = 0; Y < Height; Y++) {if (Y == 0) // 第一行的列直方图,要重头计算 {for (K = -Radius; K <= Radius; K++) {LinePS = Src->Data + ColOffSet[K] * Src->WidthStep;for (X = -Radius; X < Width + Radius; X++){ColHist[X * 256 + LinePS[RowOffset[X]]]++;}}}else // 其他行的列直方图,更新就可以了 {LinePS = Src->Data + ColOffSet[Y - Radius - 1] * Src->WidthStep; for (X = -Radius; X < Width + Radius; X++) // 删除移出范围内的那一行的直方图数据 {ColHist[X * 256 + LinePS[RowOffset[X]]]--;}LinePS = Src->Data + ColOffSet[Y + Radius] * Src->WidthStep;for (X = -Radius; X < Width + Radius; X++) // 增加进入范围内的那一行的直方图数据 {ColHist[X * 256 + LinePS[RowOffset[X]]]++;}} // 依次获取一行每个像素的局部直方图 // 根据局部直方图获的结果}
可见,这部分和普通的局部优化方式类似,没有什么特殊的地方。
3、依次获取一行每个像素的局部直方图
for (Y = 0; Y < Height; Y++){// 更新一行像素的列直方图memset(Hist, 0, 256 * sizeof(unsigned short)); // 每一行直方图数据清零先LinePS = Src->Data + Y * Src->WidthStep;LinePD = Dest->Data + Y * Dest->WidthStep;for (X = 0; X < Width; X++){if (X == 0){for (K = -Radius; K <= Radius; K++) // 行第一个像素,需要重新计算 HistgramAddShort(ColHist + K * 256, Hist);}else{/* HistgramAddShort(ColHist + RowOffset[X + Radius] * 256, Hist); HistgramSubShort(ColHist + RowOffset[X - Radius - 1] * 256, Hist);*/HistgramSubAddShort(ColHist + RowOffset[X - Radius - 1] * 256, ColHist + RowOffset[X + Radius] * 256, Hist); // 行内其他像素,依次删除和增加就可以了 }
// 根据局部直方图获的结果
LinePS++;LinePD++;}}
上面处理的过程其实和2的过程的优化道理是类似的,只不过一个是行方向,一个是列方向,聪明者自然能明白,稍微愚钝者请自己多多斟酌,自然有豁然开朗的时刻。
4、 根据局部直方图获的结果
根据不同的算法需求,结合局部直方图信息来获取结果,比如最大值算法可以用如下方式获得:
for (K = 255; K >= 0; K--){if (Hist[K] != 0){LinePD[X] = K;break;}}
关于直方图累加的代码如下:
/// <summary> /// 无符号短整形直方图数据相加,Y = X + Y, 整理时间2014.12.28; /// </summary> /// <param name="X">加数。</param> /// <param name="Y">被加数,结果保存于该数中。</param> /// <remarks>使用了SSE优化。</remarks> void HistgramAddShort(unsigned short *X, unsigned short *Y) {*(__m128i*)(Y + 0) = _mm_add_epi16(*(__m128i*)&Y[0], *(__m128i*)&X[0]); // 不要想着用自己写的汇编超过他的速度了,已经试过了*(__m128i*)(Y + 8) = _mm_add_epi16(*(__m128i*)&Y[8], *(__m128i*)&X[8]);*(__m128i*)(Y + 16) = _mm_add_epi16(*(__m128i*)&Y[16], *(__m128i*)&X[16]);*(__m128i*)(Y + 24) = _mm_add_epi16(*(__m128i*)&Y[24], *(__m128i*)&X[24]);*(__m128i*)(Y + 32) = _mm_add_epi16(*(__m128i*)&Y[32], *(__m128i*)&X[32]);*(__m128i*)(Y + 40) = _mm_add_epi16(*(__m128i*)&Y[40], *(__m128i*)&X[40]);*(__m128i*)(Y + 48) = _mm_add_epi16(*(__m128i*)&Y[48], *(__m128i*)&X[48]);*(__m128i*)(Y + 56) = _mm_add_epi16(*(__m128i*)&Y[56], *(__m128i*)&X[56]);*(__m128i*)(Y + 64) = _mm_add_epi16(*(__m128i*)&Y[64], *(__m128i*)&X[64]);*(__m128i*)(Y + 72) = _mm_add_epi16(*(__m128i*)&Y[72], *(__m128i*)&X[72]);*(__m128i*)(Y + 80) = _mm_add_epi16(*(__m128i*)&Y[80], *(__m128i*)&X[80]);*(__m128i*)(Y + 88) = _mm_add_epi16(*(__m128i*)&Y[88], *(__m128i*)&X[88]);*(__m128i*)(Y + 96) = _mm_add_epi16(*(__m128i*)&Y[96], *(__m128i*)&X[96]); *(__m128i*)(Y + 104) = _mm_add_epi16(*(__m128i*)&Y[104], *(__m128i*)&X[104]);*(__m128i*)(Y + 112) = _mm_add_epi16(*(__m128i*)&Y[112], *(__m128i*)&X[112]);*(__m128i*)(Y + 120) = _mm_add_epi16(*(__m128i*)&Y[120], *(__m128i*)&X[120]);*(__m128i*)(Y + 128) = _mm_add_epi16(*(__m128i*)&Y[128], *(__m128i*)&X[128]);*(__m128i*)(Y + 136) = _mm_add_epi16(*(__m128i*)&Y[136], *(__m128i*)&X[136]);*(__m128i*)(Y + 144) = _mm_add_epi16(*(__m128i*)&Y[144], *(__m128i*)&X[144]);*(__m128i*)(Y + 152) = _mm_add_epi16(*(__m128i*)&Y[152], *(__m128i*)&X[152]);*(__m128i*)(Y + 160) = _mm_add_epi16(*(__m128i*)&Y[160], *(__m128i*)&X[160]);*(__m128i*)(Y + 168) = _mm_add_epi16(*(__m128i*)&Y[168], *(__m128i*)&X[168]);*(__m128i*)(Y + 176) = _mm_add_epi16(*(__m128i*)&Y[176], *(__m128i*)&X[176]);*(__m128i*)(Y + 184) = _mm_add_epi16(*(__m128i*)&Y[184], *(__m128i*)&X[184]);*(__m128i*)(Y + 192) = _mm_add_epi16(*(__m128i*)&Y[192], *(__m128i*)&X[192]);*(__m128i*)(Y + 200) = _mm_add_epi16(*(__m128i*)&Y[200], *(__m128i*)&X[200]);*(__m128i*)(Y + 208) = _mm_add_epi16(*(__m128i*)&Y[208], *(__m128i*)&X[208]);*(__m128i*)(Y + 216) = _mm_add_epi16(*(__m128i*)&Y[216], *(__m128i*)&X[216]);*(__m128i*)(Y + 224) = _mm_add_epi16(*(__m128i*)&Y[224], *(__m128i*)&X[224]); *(__m128i*)(Y + 232) = _mm_add_epi16(*(__m128i*)&Y[232], *(__m128i*)&X[232]);*(__m128i*)(Y + 240) = _mm_add_epi16(*(__m128i*)&Y[240], *(__m128i*)&X[240]);*(__m128i*)(Y + 248) = _mm_add_epi16(*(__m128i*)&Y[248], *(__m128i*)&X[248]); }
_mm_add_epi16可以一次性完成16个short类型的数据的加法,比传统的add指令快了很多倍。
由于_mm_add_epi16是这对短整形数据进行的处理,因此,一般情况下改指令所能处理的半径不能大于127,如果需要大于127,则需要修改过程序中的short类型为int,同时需要使用_mm_add_epi32指令,这样程序的速度会有所下降。
经过测试,在我的I5的台式机中,1024*768图像在直方图更新上所需要的平均之间约为30ms,相比局部算法的核心就算部分时间(比如上述的求最大值),可能大部分耗时并不在这里。
附件的代码中有个完整的测试工程,并有我目前所有的TMatrix结构的完整代码,我以后的文章都将以改结构为依托进行处理。
代码还共享了很多处理的函数,我很自信一定值得朋友去学习的。
这种前后依赖的算法都有一个很致命的缺点,就是不可以并行,把图像分段处理,也会造成过多初始化耗时。
代码下载地址:http://files.cnblogs.com/files/Imageshop/BaseFile.rar
****************************作者: laviewpbt 时间: 2015.4.20 联系QQ: 33184777 转载请保留本行信息**********************
任意半径局部直方图类算法在PC中快速实现的框架。相关推荐
- 学习使用非局部平均值去噪算法去除图像中的噪音-图像去噪
图像去噪 目标 • 学习使用非局部平均值去噪算法去除图像中的噪音 • 学习函数 cv2.fastNlMeansDenoising(),cv2.fastNlMeansDenoisingColored() ...
- halcon区域腐蚀膨胀算子_超越halcon速度的二值图像的腐蚀和膨胀,实现目前最快的半径相关类算法(附核心源码)。...
超越halcon速度的二值图像的腐蚀和膨胀,实现目前最快的半径相关类算法(附核心源码). 发布时间:2019-03-20 12:32, 浏览次数:1259 , 标签: halcon 我在两年前的博客里 ...
- 算法 msrcr_一种快速简便优秀的全局曲线调整与局部信息想结合的非线性彩色增强算法(多图深度分析和探索)...
点击上方↑↑↑"OpenCV学堂"关注我 作者网名:laviewpbt 排版编辑: gloomyfish 作者是图像处理,算法实现与加速优化方面的大神!其开发的imageshop软 ...
- [Python从零到壹] 五十四.图像增强及运算篇之局部直方图均衡化和自动色彩均衡化处理
首先,祝大家教师节和中秋节快乐! 欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文 ...
- 【OpenCV 例程200篇】49. 图像增强—局部直方图处理
[OpenCV 例程200篇]49. 图像增强-局部直方图处理 欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『Python小白的OpenCV学习课』 系列,持续更新中 图像直 ...
- 路径规划之RRT类算法简述
关注同名微信公众号"混沌无形",有趣好文! 原文链接:机器人空间采样算法研究现状简述(包含原文PDF百度云下载链接) 空间采样算法按照采样空间不同,可分为:状态空间采样和运动空间采 ...
- 梯度类算法原理:最速下降法、牛顿法和拟牛顿法
文章目录 算法结构 最速下降法 牛顿法 拟牛顿法 算法结构 梯度类算法有很多,本文主要学习最常见的3个算法:最速下降法.牛顿法和拟牛顿法.算法名称虽多,但是他们的算法结构都是一样的,可以描述为 (1) ...
- 非局部相似性 matlab,基于引导核聚类的非局部均值图像去噪算法
非局部均值(nonlocal means, NLM)图像去噪算法是根据图像中存在的大量冗余信息,用非局部自相似性原理抑制噪声的算法.最初的NLM算法由文献[ 在NLM改进算法中,文献[[在相似窗结构张 ...
- 2018-4-7 进化类算法------1、遗传算法(GA)
学习资料<智能优化算法及其Matlab实例> 包子阳 余继周 编著 第二章遗传算法: 1.遗传算法:就是借鉴达尔文以及孟德尔的进化理论,而创造的一种模拟自然生物进化的算法.它的本 ...
最新文章
- AngulerJS学习(五)按需动态载入文件
- PTA数据结构与算法题目集(中文)7-25
- Java爬虫——B站弹幕爬取
- php图片等比例压缩,php实现图片上传并等比例压缩
- 答与微博前端教主在吃饭时讨论到的一道微软面试题
- 【AI白身境】学深度学习你不得不知的爬虫基础
- Linux系统基础网络配置老鸟精华篇
- 0116互联网新闻 | “DaDa英语”近日完成2.55亿美元D轮融资;腾讯推今年首个手游“闹闹天宫”...
- java利用求余水仙花数_java求水仙花数
- mysql表操作_MySQL表操作语句用法百科
- 【渝粤题库】陕西师范大学209011商业银行信贷管理Ⅱ 作业(专升本)
- 【 POJ - 3628 】Bookshelf 2(dfs 或 dp,0-1背包)
- 信息安全工程师考试大纲
- 6-6 归并排序(递归法) (10分)
- linux python pymssql,如何在UbuntuLinux上将pymssql安装到Python3.4而不是2.7?
- OpenCV:图像锐化
- 联想计算机不能进入系统桌面,联想电脑无法重装系统-联想电脑怎么重装系统我的电脑启动后到不了桌面,最后屏幕上没有任何 爱问知识人...
- java错误代码查询_在Java代码中调用SPARQL查询(在DBPedia上)时出现HttpException错误...
- strcpy与strncpy的实现
- 【BP回归预测】基于matlab随机蛙跳算法SFLA优化神经网络数据回归预测【含Matlab源码 2272期】
热门文章
- jzoj3085. 图的计数
- sourceTree
- Linux内存管理 (4)分配物理页面
- java 12-3 StringBuffer的添加和删除功能
- Ffmpeg 定位文件(seek file)
- shell 水平测试
- 快速生成解决方案 ctrl + shilf + b
- ArcEngine 获取HDF文件中的子文件
- Envy-便当的显卡驱动布置剧本
- linux安装web服务器httpd,Linux_linux构建动态WEB服务器安装篇,基本配置 安装web服务器:httpd-2. - phpStudy...