选择性模糊及其算法的实现。

我们常见的模糊算法比如均值模糊、高斯模糊等其基本的过程都是计算一个像素周边的的某个领域内,相关像素的某个特征值的累加和及对应的权重,然后得到结果值。比如均值模糊的各像素的权重是一样的,而高斯模糊的权重和像素距离中心点的距离成高斯分布。这样的过程是无法区分出图像的边缘等信息的,导致被模糊后的图像细节严重丢失,一种简单的改进方式就是设置某个阈值,当领域像素和中心点像素的差距大于阈值时,设置其权重很小,甚至为0,这样对于本身比较平滑的区域,和原始的算法区别不大,而对于像素值变化较为明显的边缘地带,则能够有效地保留原始信息,这样就能起到降低噪音的同时保留边缘的信息。

在实际的处理,小半径的领域往往处理能力有限,处理的结果不慎理想,而随着半径的增加,算法的直接实现耗时成平方关系增长,传统的优化方式由于这个判断条件的增加,已经无法继续使用,为了解决速度问题,我们可以采用基于直方图算法的优化,如果能够统计出领域内的直方图信息,上述的判断条件及权重计算就可以简单的用下述代码实现:

void Calc(unsigned short *Hist, int Intensity, unsigned char *&Pixel, int Threshold)
{int K, Low, High, Sum = 0, Weight = 0;Low = Intensity - Threshold; High = Intensity + Threshold;if (Low < 0) Low = 0;if (High > 255) High = 255;
    for (K = Low; K <= High; K++)    {Sum += Hist[K] * K;Weight += Hist[K];}if (Weight != 0) *Pixel = Sum / Weight;
}

注意在for之前的越界判断。

在任意半径局部直方图类算法在PC中快速实现的框架一文中我们已经实现了任意半径恒长时间的直方图信息的获取,因此算法的执行时间只于上for循环中的循环量有关,也就是取决于Threshold参数,当Threshold取得越大,则最终的效果就越接近标准的模糊算法(上述代码是接近均值模糊),而在实际有意义的算法应用中而只有Threshold往往要取得较小才有保边的意义,因此,计算量可以得到适度的控制。

如果要实现选择性的高斯模糊,则要在for循环中的权重项目中再乘以一个系数,当然这会增加一定的计算量。

我们选择了一些其他保边滤波器的测试图像进行了测试,在效果上通过调整参数能得到相当不错的效果,举例如下:

   

                          原图                                                                               结果图: 参数r =10, Threshold = 16

    

                        原图                                                                               结果图: 参数r =10, Threshold = 16

    

          原图                                                                               结果图: 参数r =10, Threshold = 16

    

              原图                                                                              结果图: 参数r =10, Threshold = 40

在处理时间上,使用如上参数,在I3的笔记本电脑上测试,一幅1024*768的彩色图像使用时间约为250ms,如果考虑使用YUV颜色空间中只处理Y分量,则速度越能提升到100ms,在结果上,同同样参数的表面模糊比较,似乎很类似,但比表面模糊速度快了近3倍。

附上工程函数的主要代码:

/// <summary>
/// 实现图像选择性图像模糊效果,O(1)复杂度,最新整理时间 2015.8.1。
/// </summary>
/// <param name="Src">需要处理的源图像的数据结构。</param>
/// <param name="Dest">保存处理后的图像的数据结构。</param>
/// <param name="Radius">指定模糊取样区域的大小,有效范围[1,127]。</param>
/// <param name="Threshold">选项控制相邻像素色调值与中心像素值相差多大时才能成为模糊的一部分,色调值差小于阈值的像素被排除在模糊之外,有效范围[1,255]。</param>
IS_RET __stdcall SelectiveBlur(TMatrix *Src, TMatrix *Dest, int Radius, int Threshold, EdgeMode Edge)
{if (Src == NULL || Dest == NULL) return IS_RET_ERR_NULLREFERENCE;if (Src->Data == NULL || Dest->Data == NULL) return IS_RET_ERR_NULLREFERENCE;if (Src->Width != Dest->Width || Src->Height != Dest->Height || Src->Channel != Dest->Channel || Src->Depth != Dest->Depth || Src->WidthStep != Dest->WidthStep) return IS_RET_ERR_PARAMISMATCH;if (Src->Depth != IS_DEPTH_8U || Dest->Depth != IS_DEPTH_8U) return IS_RET_ERR_NOTSUPPORTED;if (Radius < 0 || Radius >= 127 || Threshold < 2 || Threshold > 255) return IS_RET_ERR_ARGUMENTOUTOFRANGE;IS_RET Ret = IS_RET_OK;if (Src->Data == Dest->Data){TMatrix *Clone = NULL;Ret = IS_CloneMatrix(Src, &Clone);if (Ret != IS_RET_OK) return Ret;Ret = SelectiveBlur(Clone, Dest, Radius, Threshold, Edge);IS_FreeMatrix(&Clone);return Ret;}if (Src->Channel == 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 += Radius * 256;        RowOffset = ((int *)Row->Data) + Radius;        ColOffSet = ((int *)Col->Data) + Radius;                //    进行偏移以便操作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]]]++;}}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{HistgramSubAddShort(ColHist + RowOffset[X - Radius - 1] * 256, ColHist + RowOffset[X + Radius] * 256, Hist);  //    行内其他像素,依次删除和增加就可以了
                }Calc(Hist, LinePS[0], LinePD, Threshold);    LinePS++;LinePD++;}}ColHist -= Radius * 256;        //    恢复偏移操作
    Done8:IS_FreeMatrix(&Row);IS_FreeMatrix(&Col);IS_FreeMemory(ColHist);IS_FreeMemory(Hist);return Ret;}else{TMatrix *Blue = NULL, *Green = NULL, *Red = NULL, *Alpha = NULL;            //    由于C变量如果不初始化,其值是随机值,可能会导致释放时的错误。IS_RET Ret = SplitRGBA(Src, &Blue, &Green, &Red, &Alpha);if (Ret != IS_RET_OK) goto Done24;Ret = SelectiveBlur(Blue, Blue, Radius, Threshold, Edge);if (Ret != IS_RET_OK) goto Done24;Ret = SelectiveBlur(Green, Green, Radius, Threshold, Edge);if (Ret != IS_RET_OK) goto Done24;Ret = SelectiveBlur(Red, Red, Radius, Threshold, Edge);if (Ret != IS_RET_OK) goto Done24;                                            //    32位的Alpha不做任何处理,实际上32位的相关算法基本上是不能分通道处理的
        CopyAlphaChannel(Src, Dest);Ret = CombineRGBA(Dest, Blue, Green, Red, Alpha);Done24:IS_FreeMatrix(&Blue);IS_FreeMatrix(&Green);IS_FreeMatrix(&Red);IS_FreeMatrix(&Alpha);return Ret;}
}

  测试源代码及工程下载地址(VS2010开发): SelectiveBlur.rar

选择性模糊及其算法的实现。相关推荐

  1. 模糊C均值聚类算法的实现

     模糊C均值聚类算法的实现 研究背景 聚类分析是多元统计分析的一种,也是无监督模式识别的一个重要分支,在模式分类 图像处理和模糊规则处理等众多领域中获得最广泛的应用.它把一个没有类别标记的样本按照 ...

  2. python边缘检测代码_python Canny边缘检测算法的实现

    图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.对于数字图像的离散信号, ...

  3. python canny检测_python Canny边缘检测算法的实现

    图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.对于数字图像的离散信号, ...

  4. 计算机图形学 区域填充,计算机图形学 区域填充算法的实现

    . '. 实验四区域填充算法的实现班级 08信计学号 58 姓名陈瑞雪分数 一.实验目的和要求: 1.掌握区域填充算法基本知识 2.理解区域的表示和类型,能正确区分四连通和八连通的区域 3.了解区域填 ...

  5. OpenCV中图像旋转(warpAffine)算法的实现过程

    在OpenCV中,目前并没有现成的函数直接用来实现图像旋转,它是用仿射变换函数cv::warpAffine来实现的,此函数目前支持4种插值算法,最近邻.双线性.双三次.兰索斯插值,如果传进去的参数为基 ...

  6. JAVA实现中点画线_实验1-中点画线和Bresenham画线算法的实现

    <实验1-中点画线和Bresenham画线算法的实现>由会员分享,可在线阅读,更多相关<实验1-中点画线和Bresenham画线算法的实现(9页珍藏版)>请在人人文库网上搜索. ...

  7. 干货回顾丨TensorFlow四种Cross Entropy算法的实现和应用

    交叉熵介绍 交叉熵(Cross Entropy)是Loss函数的一种(也称为损失函数或代价函数),用于描述模型预测值与真实值的差距大小,常见的Loss函数就是均方平方差(Mean Squared Er ...

  8. C++基础代码--20余种数据结构和算法的实现

    C++基础代码--20余种数据结构和算法的实现 过年了,闲来无事,翻阅起以前写的代码,无意间找到了大学时写的一套C++工具集,主要是关于数据结构和算法.以及语言层面的工具类.过去好几年了,现在几乎已经 ...

  9. ML之SVM:基于Js代码利用SVM算法的实现根据Kaggle数据集预测泰坦尼克号生存人员

    ML之SVM:基于Js代码利用SVM算法的实现根据Kaggle数据集预测泰坦尼克号生存人员 目录 实验数据 设计思路​ 实现代码(部分代码) 实验数据 设计思路 实现代码(部分代码) /**js代码实 ...

最新文章

  1. OpenStack 实现技术分解 (5) 应用开发 — 使用 OpenStackClients 进行二次开发
  2. Python知识: scipy signal.chirp用法例
  3. css less 不要作用到子对象_使用Less实现网站主题切换
  4. 工程之道,解读业界最佳的深度学习推理性能优化方案
  5. android 命名空间解析,Android Bluetooth、Android AdapterView等命名空间-Android中文API文档...
  6. 一文看尽 2020 年谷歌 AI 重大突破
  7. 编辑手机pad端调试方法
  8. HttpClient4
  9. OpenDaylight-Boron学习笔记: 6 VTN模块
  10. 分享材料(不断更新)
  11. [网鼎杯 2018]Fakebook
  12. Java 操作 ElasticSearch
  13. NLP逻辑回归模型(LR)实现分类问题实例详解
  14. rono在oracle的作用_Oracle中存储过程的作用和用法
  15. mysql 写锁和读锁_mysql的封锁机制以及读锁和写锁的区别
  16. Linux(CentOS7)搭建LAMP服务环境
  17. matlab中text竖着写,科学网—matlab中text函数的用法 - 张瑞龙的博文
  18. 吴恩达2022机器学习——第二部分高级学习算法第二周笔记
  19. 埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 A-Wasserstein Distance
  20. Python之利用PyPDF2库实现对PDF的删除和合并

热门文章

  1. 利用OpenCV的SimpleBlobDetector检测图像的奇异区域(斑点)
  2. 用美图秀秀(微软调色版)生成的R分量为255的图片在MATLAB和OpenCV中R分量为254
  3. MATLAB的基础-虽然基础,但全是细节,掌握了这些细节,才是MATLAB高手
  4. linux内核网络协议栈--数据包的网卡转发流程(二十七)
  5. python 数据库的Connection、Cursor两大对象
  6. 补天白帽大会:无处不在的无线电攻击
  7. 静态库符号文件冲突的解决办法,已实践OK, mark
  8. php导出excel数据使用csv替代xls格式
  9. 分享42个超棒的智能手机摄影画廊
  10. 被困69天后,智利矿工重返人间