文档章节

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

abcijkxyz
 abcijkxyz
发布于 2016/11/22 16:40
字数 1686
阅读 33
收藏 0
点赞 0
评论 0

 

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

     我们常见的模糊算法比如均值模糊、高斯模糊等其基本的过程都是计算一个像素周边的的某个领域内,相关像素的某个特征值的累加和及对应的权重,然后得到结果值。比如均值模糊的各像素的权重是一样的,而高斯模糊的权重和像素距离中心点的距离成高斯分布。这样的过程是无法区分出图像的边缘等信息的,导致被模糊后的图像细节严重丢失,一种简单的改进方式就是设置某个阈值,当领域像素和中心点像素的差距大于阈值时,设置其权重很小,甚至为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;
    }
}

 

 

****************************作者: laviewpbt   时间: 2015.8.1    联系QQ:  33184777 转载请保留本行信息**********************

 

本文转载自:http://www.cnblogs.com/Imageshop/p/4694540.html

共有 人打赏支持
abcijkxyz
粉丝 60
博文 6196
码字总数 1876
作品 0
深圳
项目经理
浙大的游戏设计教程

第一部分 游戏程序设计概览 计算机游戏简介:什么是游戏、游戏的分类等 游戏的基本开发流程? 游戏开发的基本理念及方法 游戏软件的体系结构:包括三维游戏引擎的架构分析 游戏的调试与测试 ...

Matrix4X4
2012/08/19
361
2
零基础入门:对象检测及其算法指南

图像分类是拍摄一张图像并对其中的对象进行预测。例如:当我们构建一个猫狗分类器时,我们拍摄了猫或狗的图像,并预测它们属于哪个类别。 如果猫和狗都出现在同一张图像中,你会怎样做呢? ...

【方向】
01/23
0
0
视频质量评价方法:VQM

如何确定一个视频质量的好坏一直以来都是个棘手的问题。目前常用的方法就是通过人眼来直接观看,但是由于人眼的主观性及观看人员的单体差异性,对于同样的视频质量,不同的人的感受是不一样的...

leixiaohua1020
2013/10/13
0
0
如何理解并掌握 Java 数据结构

一说起“数据结构”可能很多同学都又交给老师了。但是实际工作中如果做得深入一些,特别是越往上发展,越大公司越离不开数据结构。本场 Chat 作者将带领大家重温《Java 数据结构》,讲解的内...

valada
04/12
0
0
高斯模糊算法的 C++ 实现

  2008 年在一个 PS 讨论群里,有网友不解 Photoshop 的高斯模糊中的半径是什么含义,因此当时我写了这篇文章:   对Photoshop高斯模糊滤镜的算法总结;   在那篇文章中,主要讲解了高...

hoodlum1980
2015/05/25
0
0
自定义控件三部曲之绘图篇(十六)——给控件添加阴影效果与发光效果

前言:要么出击,要么出局,命运女神总会眷顾拼劲全力的一方 相关文章: 《Android自定义控件三部曲文章索引》:http://blog.csdn.net/harvic880925/article/details/50995268 这节我们将学到...

harvic880925
2016/07/04
0
0
探索推荐引擎内部的秘密,第 3 部分: 深入推荐引擎相关算法 - 聚类 (三)

Canopy 聚类算法 Canopy 聚类算法的基本原则是:首先应用成本低的近似的距离计算方法高效的将数据分为多个组,这里称为一个 Canopy,我们姑且将它翻译为“华盖”,Canopy 之间可以有重叠的部...

东方神剑
2014/11/13
0
0
用现有的资源开发第一个人工智能系统

你需要咋样的队伍才可以开发人工智能系统?   在这个AI概念满天飞的今天,你一定也被老板要求开发人工智能系统,如果老板又加了一句资源可以给你配置,你想招什么人都可以,但是这时候你如...

MAKOfly
06/04
0
0
2-D 图像卷积计算

卷积其实是图像处理中最基本的操作,我们常见的一些算法比如:均值模糊、高斯模糊、锐化、Sobel、拉普拉斯、边缘检测等等一些和领域相关的算法,都可以通过卷积算法实现。 实现 这是一个简化...

兔之
2015/12/07
61
0
图像处理——形态学

形态学一般是使用二值图像,进行边界提取,骨架提取,孔洞填充,角点提取,图像重建。 基本的算法:膨胀腐蚀,开操作,闭操作,击中击不中变换 几种算法进行组合,就可以实现一些非常复杂的功...

li_wen01
2017/06/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JPA @MappedSuperclass 注解说明

基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中。 1.@MappedSuperclass注解只能标准在类上:@Target({java.lang....

海博1600
16分钟前
0
0
Scala Configuration 相关API

Play使用了 Typesafe config library,但是也提供了一个有着更多Scala高级特性的的 Configuration 封装。不熟悉Typesafe配置的开发者可以移步 configuration文件的语法和特性文档。 读取配置...

Landas
今天
1
0
使用cookie技术 记住账号

1. 效果 2. 实现过程 2.1 前端 将用户的选中传递给后台 这个参数的获取是 参考:https://my.oschina.net/springMVCAndspring/blog/1860498 // var rememberLogin = $("#rememberLoginId").i...

Lucky_Me
今天
1
0
《趣谈网络协议》02之网络分层的真实含义

一、提出问题 1.提出问题 当你听到什么二层设备、三层设备、四层 LB 和七层 LB 中层的时候,是否有点一头雾水,不知道这些所谓的层,对应的各种协议具体要做什么“工作”? 2.这四个问题你弄...

aibinxiao
今天
2
0
Python3学习日志二 Python中的集合set和字典dict

1.集合set 定义一个集合set 我们可以看到定义集合set有两种不同的形式,如果要定义一个空的集合set不能用{}而是要用set();另外,集合是无序的,而且set中的元素是不可重复的,如果你定义了一...

Mr_bullshit
今天
0
0
adb 操作指令详解

ADB,即 Android Debug Bridge,它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具。 注:有部分命令的支持情况可能与 Android 系统版本及定制 ROM 的实现有关。...

孟飞阳
今天
0
0
nodejs安装以及环境配置(很好的node安装和配置文章,少走很多弯路)

一、安装环境 1、本机系统:Windows 10 Pro(64位) 2、Node.js:v6.9.2LTS(64位) 二、安装Node.js步骤 1、下载对应你系统的Node.js版本:https://nodejs.org/en/download/ 2、选安装目录进...

sprouting
今天
1
0
Redisson

了解了Redisson,发现使用挺简单的,接下来准备深入学习一下。 Redisson介绍 Redisson是架设于Redis基础之上的一个Java驻内存数据网格(In-Memory Data Grid) Redisson在基于NIO的Netty框架上...

to_ln
今天
0
0
python有哪些好玩的应用实现,用python爬虫做一个二维码生成器

python爬虫不止可以批量下载数据,还可以有很多有趣的应用,之前也发过很多,比如天气预报实时查询、cmd版的实时翻译、快速浏览论坛热门帖等等,这些都可以算是爬虫的另一个应用方向! 今天给...

python玩家
今天
0
0
python爬虫日志(3)-爬去异步加载网页

在浏览器检查元素页面中,选取Network中的XHR选项即可观察每次加载页面,网页发出的请求,观察url的规律即可利用封装的函数对每一页进行爬取。

茫羽行
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部