图像处理算法及编程实现_图像处理算法与编程实现 - CSDN
精华内容
参与话题
  • 图像处理算法工程师

    千次阅读 2018-12-02 12:09:32
    图像处理算法工程师    转自http://blog.csdn.net/liuuze5/article/details/44247043 职位要求 编程技能: 1、 具有较强的编程能力和良好的编程习惯, 精通c/c++编程,并熟练使用VS 或matlab开发环境; 2...

    图像处理算法工程师

     

     转自http://blog.csdn.net/liuuze5/article/details/44247043

    职位要求

    编程技能:

    1、 具有较强的编程能力和良好的编程习惯, 精通c/c++编程,并熟练使用VS 或matlab开发环境;

    2、 在计算机技术领域拥有扎实的技术功底,尤其在数据结构、算法和代码、软件设计方面功力深厚;

        对数据结构有一定的研究基础如链表、堆杖、树等,熟悉数据库编程;

    3、 出色的算法分析能力,对某一特定算法可以做广泛的综述,有实际算法实现经验;

    4、 熟悉面向对象编程思想,精于windows下的C/C++、VC++程序设计,熟悉MATLAB,对MFC有相对的了解和应用经验;

    专业技能:

    1、扎实的数学功底和分析技能,精通计算机视觉中的数学方法;

         高等数学(微积分)、线性代数(矩阵论)、随机过程、概率论、

         摄影几何、模型估计、数理统计、张量代数、数据挖掘、数值分析等;

    2、具备模式识别、图像处理、机器视觉、信号处理和人工智能等基础知识;

         对图像特征、机器学习有深刻认识与理解;

    3、精通图像处理基本概念和常用算法包括图像预处理算法和高级处理算法;

         常见的图像处理算法,包括增强、分割、复原、形态学处理等; 

         熟悉常见的模式识别算法,特别是基于图像的模式识别算法,掌握特征提取、特征统计和分类器设计; 
    4、熟练使用OpenCV、Matlab、Halcon中的一种或一种以上工具库;

     

     

     

    5、熟悉机器视觉系统的硬体选型,包括CCD相机,镜头及光源;熟悉相机与镜头搭配;

     

     

    外语:

    1. 英文熟练,能够熟练阅读和理解专业英文资料,有英文文献检索和阅读能力;
    2. 良好的英语沟通能力

    综合能力:

    1.对工作认真负责,积极主动,勤奋踏实;

    2.做事严谨,注重细节,有耐心,能够在压力下独立工作;

    3.学习钻研能力强,有较强的理解能力和逻辑思维能力和良好的创新意识;

    4.良好的协调沟通能力和团队合作精神; 

     

    经验要求:

    1.两年以上C/C++ 程序设计经验;

    2.具有2年以上在Linux/Unix环境下用C/C++语言开发图像处理软件的经验。

    3.数字图像处理、模式识别的理论知识和实践经验;

      有基于OpenCV开发项目经验,机器视觉行业经验;

      具有图像处理算法设计和开发经验;

      参与过机器视觉系统分析和设计;

    4. 在Matlab 或其它数学软件上开发算法的经验;

     

    视觉算法经验:请提供实现的算法列表

        目标识别、图像配准、三维测量、标定和重建、手势识别; 

        表面缺陷检测;尺寸测量;特征识别;

        图像去噪、滤波、融合算法
        3A算法:如自动曝光、自动对焦、自动白平衡

     

    【工作内容】: 


    1.为解决实际问题而进行探索性研究和创新,设计与模式识别、图像/视频智能分析处理相关的算法。

      图形图像处理、计算机视觉相关算法的研发以及应用程序的编写;

      参与核心软件项目算法设计及算法实现;研究图像处理算法,开发和调试算法原型

      软件算法研发:算法的代码实现、优化以及移植及其测试;

      负责机器视觉系统图象处理、分析及识别算法的设计、实现及调试;

      参与图象算法视觉应用软件的设计与实现。参与图象处理技术研究与设计;

    2、对已有的计算机视觉算法进行实用化开发和优化研究;
       精益求精,将算法做到极致,使算法真正实用化;

      参与预研性的算法分析和论证,为产品开发提供基础研究及论证;

     

    岗位职责:

    1、 协助工程师进行算法的测试.;C++语言验证、测试算法;

    2、编写算法规格说明;
    3、相关专业文献的查阅; 
    4、将部分matlab程序转为C或C++语言程序。 

    1) 辅助图像处理工作
    2) 大规模图像搜集与分类 
    3) 与开发人员等进行沟通,跟踪产品的体验效果并改进;
    4)负责公司的机器视觉与传感器项目的技术支持(如项目可行性评估、现场DEMO、装机、培训等)

       和 维护工作;

     

    岗位职责:

    1、负责计算机视觉中的图像采集,处理面阵和线扫描相机的成像和控制 ;
    2、针对特定的计算机视觉问题,设计目标识别与快速定位与检测算法的实现,并进行优化;
    3、对彩色图像和灰度图像实现物体表面的污点划痕检测算法设计和实现;
    4、处理三维物体表面数据获取和实现三维测量算法的实现;
    5、处理点激光和线激光源的成像,散斑噪声滤波和轮廓检测;
    6、负责算法与软件GUI开发工程师接口;
    7、完成上级领导交办的其他的工作。

     

     

     

     

    图像算法工程师三重境界

     

     

     

     

     

     

    一、传统图像算法工程师: 
    主要涉及图形处理,包括形态学、图像质量、相机成像之3A算法、去雾处理、颜色空间转换、滤镜等,主要在安防公司或者机器视觉领域,包括缺陷检测;

    二、现代图像算法工程师: 
    涉及模式识别,主要表现的经验为Adaboost、SVM的研究与应用,特征选取与提取,包括智能驾驶的研究与应用、行人检测、人脸识别;

    三、人工智能时代图像算法工程师: 
    深度学习,主要在大型互联网公司或者研究所机构,具体体现在TensorFlow等开源库的研究与应用,包括机器人的研、基于深度学习的人脸识别;

    展开全文
  • VC++ 数字图像处理典型算法及实现 (此资源为书籍源代码)主要讲述了Visual C 数字图像处理典型算法及实现。全书共12章,分别介绍了数字图像编程基础、图像感知与获取、图像的点运算、几何变换、正交变换、图像增强...
  • 实践的意义——写给图像处理算法爱好者的建议

    千次阅读 多人点赞 2017-06-01 19:55:05
    一些我学习数字图像处理中的心得和建议,欢迎有兴趣的朋友共同参与讨论。工欲善其事,必先利其器。有时一些方法论之类的东西往往能让你少走很多弯路
    陆放翁诗云:“纸上得来终觉浅,绝知此事要躬行”,此乃亘古不变之真理也。


    图像处理研究的一个很大特点就在于,它是一种和实际应用紧密联系的实用型学科。所有的算法都是针对实际中遇到的问题而存在的。无论是我们新提出了一个算法,还是我们新学习了一个算法,都可以直接写一个程序来检验它的处理效果。而且这种“效果”往往还是一目了然的。因为图像处理的输入和输出都是图像,图像就是用来给人看的。这种直观性是其它研究领域所很难具备的。例如,当年何恺明博士向CVPR提交其关于图像去雾算法的论文时,审稿人就很惊讶于这么简单的方法居然有这么意外的效果。于是其中就有好奇的审稿人直接动手编程实现了他的算法。正所谓,是骡子是马,拉出来溜溜。他算法的效果最终征服了审稿人,也征服了大会的评委会,最终那届的最佳论文奖就首次颁给了来自亚洲的研究者。


    而之于正在学习或研究图像算法的同学而言,动手实践的意义就更大了。不要以为你听老师或别人讲了一些算法,或者自己看看冈萨雷斯书上的描述,就觉得自己好像已经get了什么。除非你真的自己能把程序写出了,否则其实你什么都没懂,最多也就是似懂非懂。这一点我最有发言权。很多算法我感觉我也学得不错,但其实我在写Magic House的时候仍然花了很多时间去调试,因为在写的过程中,其实问题是层出不穷的。例如,我在写图像傅立叶逆变换的时候,我感觉这个算法我已经理解的很到位了,但是做逆变换的时候就是得不到原图,而是一篇黑。问题到底出在哪里我其实断断续续想了挺长时间。有一天突然开窍了,因为傅立叶变换的结果存在文件里,其实只是保存了实数的部分,虚数部分根本就没存。因为你在屏幕上看傅立叶变换结果图的时候,看到的也只是实数部分。尽管你可能遇到的问题跟我不一样,但遇到这样或那样的问题总是肯定的。我总结了自己锻炼编写图像处理代码的几个原因:


    1)一方面你会发现过去你的理解可能是有偏差的,因为按照你那个想法去实现的代码效果可能并不理想,那问题出在哪里就很值得你思索;

    2)另一方面,你自己在实现的过程中很可能发现原作者算法的不足(比如我在实现暗通道算法时就发现这个算法处理大面积的天空时会有问题),然后你进一步研究的方向就来了!这在我看来似乎是发paper最容易的方法。

    3)我不得不告诉你,很多paper是会骗人的!中国有学术腐败,国外也有学术造假。洛必达把他老师伯努利教给他的方法写进了自己的书里,于是便有了今天你所学到的洛必达法则。从这个角度来看,18世纪的欧洲就已经有学术腐败了。有些作者paper里的效果很可能是PS过的,所以你按照他的方法,无论怎么做也不可能得到他的效果,这一点如果你不试试,就很可能被骗。

    4)写代码本身就是一项本领或者基本功。你将来还很有可能要靠他生存。曲不离口、拳不离手。你现在不好好练,将来很可能作茧自缚。


    说到这里我就不禁要提一句。懒惰既是推动人类创新的两大动力之一,但也可能是害得你“啥都不会,只会坐等靠要”、最终一事无成的毒草就像中国过去搞扶贫只会一味的输血,本来还有二亩薄田可以耕种,现在政府有救济款,索性连田也懒得种了,结果导致某些地方越扶越贫。现在很多人在网上一张嘴就是“有没有源代码下载”?或者买书看书也是挑那种“带光盘的”或者满篇满篇就只有代码的。抄来的过程当然轻松,但是知识、技术学会了是自己的,抄来的东西始终是别人的。不是说网上的代码、资源不可以参考,但是你绝对不应该对此产生依赖心理,人还是应该靠自己。如果你写不出来,只能说明你还没真正学会,学懂。何况真正有技术含量的东西,你永远也抄不来。两弹一星我们也曾想让苏联帮忙,但人家凭啥给你?结果怎么样,还不得靠中国人自己吗?要知道,这个技术积累的过程本身也很重要。


    说道实践编程,你要么用C/C++,要么用Matlab,可能还有其他小众的(比如我有时也用R做图像处理),但大体上总逃不过这两大阵营。有人说他用Java或者Python, Anyway这其实并不重要。我的讨论还是以C/C++和Matlab为主体来讲。Matlab当然比较好用,什么卷积、直方图、高斯滤波,一个函数搞定!C/C++如果结合OpenCV基本可以达到同样的效果。当这绝对是后话。如果你是初学,最好踏踏实实一点一滴把最基本的图像处理算法实现一下。千里之行,始于足下。九层之台,起于累土。因为建立一个完整的体系思维和拥有一个扎实的基础特别重要。一些看似高大上的算法都是在这些不起眼的算法的堆砌组合下实现的。比如SIFT特征构建时,你会遇到直方图、高斯滤波和图像金字塔这些非常基础的原件。当你看到这些东西的时候,你就应该有马上觉悟到它们的各种特性和作用的能力。这对于你理解SIFT很有帮助。如果你具备了这种素质,详细我,你再在matlab里调那些函数来写SIFT就非常容易。如果说你学了一遍SIFT,但是还是写不出来,结论就是因为最基本的高斯、金字塔、直方图你也没自己写过。跳过了锻炼基础的阶段,直接来高大上的东西,比如会无福消受。就像《天龙八部》里的番僧鸠摩智为了速成,不惜用道教的小无相功来催动少林72绝技,结果走后入魔,前功尽废。前两天有网友给我博客留言:“如果只是把现成的算法实现一遍那也没什么意思,原创算法的话就有技术含量了。”我当时觉得可能这位网友水平比较高,看我这些雕虫小技自然不能入法眼。但我这两天又在想抛开大家水平高低不谈,这句话到底对不对?我发现,这个说法还是有漏洞。你小学时候每天语文课上学了十个新汉字,老师就让你在方格本上每个抄10遍,这种事当然没意思了,但是大家不都是这么没意思过来的吗?如果不这样,你怎么能在高考的时候40分钟写一篇800字命题作文呢?可见没意思的事情未必没意义!


    最后,用荀老夫子的一句话同大家共勉:无冥冥之志者,无昭昭之明,无昏昏之事者,无赫赫之功


    展开全文
  • 数字图像处理算法实现 编程心得

    千次阅读 2007-10-12 17:14:00
    摘要: 关于空间域图像处理算法框架,直方图处理,空间域滤波器算法框架的编程心得,使用GDI+(C++)一,图像文件的读取 初学数字图像处理时,图像文件的读取往往是一件麻烦的事情,我们要面对各种各样的图像文件格式...
    摘要: 关于空间域图像处理算法框架,直方图处理,空间域滤波器算法框架的编程心得,使用GDI+(C++)
    一,图像文件的读取
        初学数字图像处理时,图像文件的读取往往是一件麻烦的事情,我们要面对各种各样的图像文件格式,如果仅用C++的fstream库那就必须了解各种图像编码格式,这对于初学图像处理是不太现实的,需要一个能帮助轻松读取各类图像文件的库。在Win32平台上GDI+(C++)是不错的选择,不光使用上相对于Win32 GDI要容易得多,而且也容易移植到.Net平台上的GDI+。
        Gdiplus::Bitmap类为我们提供了读取各类图像文件的接口,Bitmap::LockBits方法产生的BitmapData类也为我们提供了高速访问图像文件流的途径。这样我们就可以将精力集中于图像处理算法的实现,而不用关心各种图像编码。具体使用方式请参考MSDN中GDI+文档中关于Bitmap类和BitmapData类的说明。另外GDI+仅在Windows XP/2003上获得直接支持,对于Windows 2000必须安装相关DLL,或者安装有Office 2003,Visual Studio 2003 .Net等软件。
    二,空间域图像处理算法框架
     (1) 在空间域图像处理中,对于一个图像我们往往需要对其逐个像素的进行处理,对每个像素的处理使用相同的算法(或者是图像中的某个矩形部分)。即,对于图像f(x,y),其中0≤x≤M,0≤y≤N,图像为M*N大小,使用算法algo,则f(x,y) = algo(f(x,y))。事先实现一个算法框架,然后再以函数指针或函数对象(functor,即实现operator()的对象)传入算法,可以减轻编程的工作量。
        如下代码便是一例:
    #ifndef PROCESSALGO_H
    #define PROCESSALGO_H
     
    #include <windows.h>
    #include <Gdiplus.h>
     
     
    namespace nsimgtk
    {
             template <typename pixelType, Gdiplus::PixelFormat pixelFormat, class Processor>
        bool ProcessPixelsOneByOne(Gdiplus::Bitmap* const p_bitmap, Processor processor, unsigned int x, unsigned int y,
                                                               unsigned int width, unsigned int height)
        {
                       if (p_bitmap == NULL)
                       {
                                return false;
                       }
     
                       if ((width + x > p_bitmap->GetWidth()) || (height + y >p_bitmap->GetHeight()))
                       {
                                return false;
                       }
     
            Gdiplus::BitmapData bitmapData;
                       Gdiplus::Rect rect(x, y, width,height);
           
            if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixelFormat, &bitmapData) != Gdiplus::Ok)
                {
                                return false;
                       }
     
                       pixelType *pixels = (pixelType*)bitmapData.Scan0;
                      
     
            for (unsigned int row=0; row<height; ++row)
                       {
                                for (unsigned int col=0; col<width; ++col)
                                {
                                         processor(&pixels[col+row*bitmapData.Stride/sizeof(pixelType)]);     
                                }
                       }
     
                       if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
                       {
                                return false;
                       }
           
                       return true;
             }
    }
     
    #endif
    ProcessPixelsOneByOne函数可以对图像中从(x,y)位置起始,width*height大小的区域进行处理。模板参数pixelType用于指定像素大小,例如在Win32平台上传入unsigned char即为8位,用于8阶灰度图。模板参数Processor为图像处理算法实现,可以定义类实现void operator(pixelType *)函数,或者传入同样接口的函数指针。
        如下便是一些算法示例(说明见具体注释):
    #ifndef SPATIALDOMAIN_H
    #define SPATIALDOMAIN_H
    #include <cmath>
    #include <string>
     
    namespace nsimgtk
    {
       // 8阶灰度图的灰度反转算法 
             class NegativeGray8
             {
             public:
                       void operator()(unsigned char *const p_value)
                       {
                                *p_value ^= 0xff;
                       }
             };
       
       // 8阶灰度图的Gamma校正算法
             class GammaCorrectGray8
             {
             private:
                       unsigned char d_s[256];
             public:
                       GammaCorrectGray8::GammaCorrectGray8(double c, double gamma);
     
                       void operator()(unsigned char*const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
     
        // 8阶灰度图的饱和度拉伸算法
             class ContrastStretchingGray8
             {
             private:
                       unsigned char d_s[256];
             public:
                       ContrastStretchingGray8::ContrastStretchingGray8(double a1, double b1, unsigned int x1,
                                double a2, double b2, unsigned int x2, double a3, double b3);
     
                       void operator()(unsigned char*const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
       
        // 8阶灰度图的位平面分割,构造函数指定位平面号
             class BitPlaneSliceGray8
             {
             private:      
                       unsigned char d_s[256];
             public:
                       BitPlaneSliceGray8(unsigned char bitPlaneNum);
     
                       void operator()(unsigned char* const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
    }
     
    #endif
     
    // 上述类中各构造函数的实现代码,应该分在另一个文件中,此处为说明方便,一并列出
    #include "SpatialDomain/spatialDomain.h"
     
    namespace nsimgtk
    {
             GammaCorrectGray8::GammaCorrectGray8(double c, double gamma)
             {
                       double temp;
                       for (unsigned int i=0; i<256; ++i)
                       {
                                temp = ceil(c * 255.0 * pow(double(i)/255.0, gamma));
                                d_s[i] = unsigned char(temp);
                       }
             }
     
             ContrastStretchingGray8::ContrastStretchingGray8(double a1, double b1, unsigned int x1,
                                double a2, double b2, unsigned int x2, double a3, double b3)
             {
                       if (x1 > 255 || x2 > 255 || x1 > x1)
                       {
                                for (unsigned int i=0; i<256; ++i)
                                         d_s[i] = i;
                       }
                       else
                       {
                                double tmp;
                                for (unsigned int i=0; i<x1; ++i)
                                {
                                         tmp = ceil(a1*double(i)+b1);
                                         d_s[i] = (unsigned char)tmp;
                                }
     
                                for (unsigned int i=x1; i<x2; ++i)
                                {
                                         tmp = ceil(a2*double(i)+b2);
                                         d_s[i] = (unsigned char)tmp;
                                }
     
                                for (unsigned int i=x2; i<256; ++i)
                                {
                                         tmp = ceil(a3*double(i)+b3);
                                         d_s[i] = (unsigned char)tmp;
                                }
                       }
             }
     
             BitPlaneSliceGray8::BitPlaneSliceGray8(unsigned char bitPlaneNum)
             {
                      unsigned char bitMaskArray[8] =
                       {
                                0x01, 0x02, 0x04, 0x08,
                                0x10, 0x20, 0x40, 0x80
                       };
     
                       for (unsigned int i=0; i<256; ++i)
                       {
                                unsigned char tmp = i;
                                tmp &= bitMaskArray[bitPlaneNum];
                                tmp = (tmp >> bitPlaneNum) * 255;
                                d_s[i] = tmp;
                      }
             }
    }
    (2) 直方图在GDI+1.0中没有获得支持,我们必须自行实现。直方图相关的处理在数字图像处理中占有重要地位,可以通过它获取图像灰度级的统计信息,且可以通过直方图进行一些重要的图像增强技术,如直方图均衡化,直方图规定化,基本全局门限等。
    下面是获取8阶图像直方图的算法实现:
    namespace nsimgtk
    {
             bool GetHistogramNormalizeGray8(Gdiplus::Bitmap * const p_bitmap, float *histogramArray)
             {
                       if (p_bitmap == NULL || histogramArray == NULL)
                       {
                                return false;
                       }
     
                       Gdiplus::BitmapData bitmapData;
                       Gdiplus::Rect rect(0, 0, p_bitmap->GetWidth(), p_bitmap->GetHeight());
     
                       if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat8bppIndexed, &bitmapData) != Gdiplus::Ok)
                {
                                return false;
                       }
     
                       unsigned char *pixels = (unsigned char*)bitmapData.Scan0;
            unsigned int histogram[256];
                       for (int i=0; i<256; ++i)
                       {
                                histogram[i] = 0;
                       }
     
                       for (unsigned int row=0; row<p_bitmap->GetWidth(); ++row)
                       {
                                for (unsigned int col=0; col<p_bitmap->GetHeight(); ++col)
                                {
                                         ++histogram[pixels[col+row*bitmapData.Stride]];
                                }
                       }
     
                       const unsigned int totalPixels = p_bitmap->GetWidth() * p_bitmap->GetHeight();
                       for (int i=0; i<256; ++i)
                       {
                                histogramArray[i] = float(histogram[i]) / float(totalPixels);
                       }
     
                       if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
                       {
                                return false;
                       }
     
                       return true;
             }
    }
    在获取直方图后(即上面算法的第二个参数),再将其作为参数传入下面的对象的构造函数,然后以该对象为仿函数传入ProcessPixelsOneByOne即可实现8阶图像直方图均衡化:
    #ifndef SPATIALDOMAIN_H
    #define SPATIALDOMAIN_H
     
    #include <cmath>
    #include <string>
     
    namespace nsimgtk
    {
        // 8阶灰度图的直方图均衡化
             class HistogramEqualizationGray8
             {
             private:
                       unsigned char d_s[256];
             public:
                       HistogramEqualizationGray8(const float *const histogramArray);
                      
                       void operator()(unsigned char *const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
    }
     
    #endif        
     
    //
    #include "SpatialDomain/spatialDomain.h"
     
    namespace nsimgtk
    {
             HistogramEqualizationGray8::HistogramEqualizationGray8(const float *const histogramArray)
             {
                       if (histogramArray != NULL)
                       {
                                float sum = 0.0;
                                for (int i=0; i<256; ++i)
                                {
                                         sum += histogramArray[i];
                                         d_s[i] = unsigned char(sum * 255);
                                }
                       }
             }
    }      
    (3)空间域滤波器,滤波器是一个m*n大小的掩模,其中m,n均为大于1的奇数。滤波器逐像素地通过图像的全部或部分矩形区域,然后逐像素地对掩模覆盖下的像素使用滤波器算法获得响应,将响应赋值于当前像素即掩模中心像素,另外滤波器算法使用中将会涉及到图像边缘的问题,这可以对边缘部分掩模使用补零法补齐掩模下无像素值的区域,或者掩模的移动范围以不越出图像边缘的方式移动,当然这些处理方法都会给图像边缘部分带来不良效果,但是一般情况下,图像边缘部分往往不是我们关注的部分或者没有重要的信息。
    下面的滤波器算法框架SpatialFilterAlgo即以补零法(zero-padding)实现:
    #ifndef SPATIALFILTER_H
    #define SPATIALFILTER_H
     
    #include <vector>
    #include <numeric>
    #include <algorithm>
    #include <gdiplus.h>
    #include <fstream>
    #include <cmath>
     
    namespace nsimgtk
    {
        template <typename pixelType, Gdiplus::PixelFormat pixelFormat, class FilterMask>
        bool SpatialFilterAlgo(Gdiplus::Bitmap* const p_bitmap, FilterMask filterMask, unsigned int x, unsigned int y,
                                                               unsigned int width, unsigned int height)
        {
                       if (p_bitmap == NULL)
                       {
                                return false;
                       }
     
                       if ((width + x > p_bitmap->GetWidth()) || (height + y >p_bitmap->GetHeight()))
                       {
                                return false;
                       }
     
            Gdiplus::BitmapData bitmapData;
                       Gdiplus::Rect rect(x, y, width,height);
           
            if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixelFormat, &bitmapData) != Gdiplus::Ok)
                {
                                return false;
                       }
     
                       pixelType *pixels = (pixelType*)bitmapData.Scan0;
                      
            const unsigned int m = filterMask.d_m;                                         // mask's width
            const unsigned int n = filterMask.d_n;                                          // mask's height
            std::vector<pixelType> tmpImage((m-1+width)*(n-1+height));   // extend image to use zero-padding
           
            // copy original bitmap to extended image with zero-padding method
            for (unsigned int row=0; row<height; ++row)
                       {
                                for (unsigned int col=0; col<width; ++col)
                                {
                                         tmpImage[(col+m/2)+(row+n/2)*(bitmapData.Stride/sizeof(pixelType)+m-1)] =
                        pixels[col+row*bitmapData.Stride/sizeof(pixelType)];    
                                }
                       }
           
            // process every pixel with filterMask
            for (unsigned int row=0; row<height; ++row)
                       {
                                for (unsigned int col=0; col<width; ++col)
                                {
                    // fill the "m*n" mask with the current pixel's neighborhood
                    for (unsigned int i=0; i<n; ++i)
                    {
                        for (unsigned int j=0; j<m; ++j)
                        {
                            filterMask.d_mask[i*m+j] = tmpImage[(col+j)+(row+i)*(bitmapData.Stride/sizeof(pixelType)+m-1)];
                        }
                    }
                 
                    // replace the current pixel with filter mask's response
                                         pixels[col+row*bitmapData.Stride/sizeof(pixelType)] = filterMask.response();      
                                }
                       }
     
            if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
                       {
                                return false;
                       }
           
                       return true;
             }
    }
     
    #endif
    其中模板参数FilterMask即为滤波掩模算法。通常的滤波算法有均值滤波器,可以模糊化图像,去除图形中的细节部分,使得我们可以关注图像中较为明显的部分,均值滤波器用于周期性噪声。中值滤波器用于图像中存在椒盐噪声也即脉冲噪声的情况下。另外有基于一阶微分的Sobel梯度算子和基于两阶微分的拉普拉斯算子,它们往往被用于边缘检测中。
    下面是一些滤波器算法的具体实现,所以滤波器算法都应该实现pixelType response()函数以及有d_mask,d_m,d_n成员,这可以通过继承__filteMask类获得(不需要付出虚函数代价)。
    #ifndef SPATIALFILTER_H
    #define SPATIALFILTER_H
     
    #include <vector>
    #include <numeric>
    #include <algorithm>
    #include <gdiplus.h>
    #include <fstream>
    #include <cmath>
     
    namespace nsimgtk
    {
        // 滤波器掩模的基类,提供掩模大小d_m,d_n,掩模覆盖下的m*n个像素值d_mask
        // others filterMask should inherit it
        template <typename pixelType>
        struct __filterMask
        {
            const unsigned int d_m;
            const unsigned int d_n;
     
            // image's pixels under the m*n filter mask
            std::vector<pixelType> d_mask;
     
            // filter mask's width and heigh must be a odd, if not, it will plus one for the width or the height
            __filterMask(unsigned int m, unsigned int n)
                : d_m(m%2 ? m:m+1), d_n(n%2 ? n:n+1), d_mask(d_m*d_n)
            {
            }
        };
     
        // 掩模权值为全1的均值滤波器
        template <typename pixelType>
        class averagingFilterMaskSp
            : public __filterMask<pixelType>
        {
        public:
            averagingFilterMaskSp(unsigned int m, unsigned int n)
                : __filterMask<pixelType>(m, n)
            { }
     
            pixelType response()
            {
                return std::accumulate(d_mask.begin(), d_mask.end(), 0) / (d_m * d_n);
            }
        };
     
        // 可自定义掩模权值的均值滤波器
        template <typename pixelType>
        class averagingFilterMask
            : public __filterMask<pixelType>
        {
        private:
            std::vector<pixelType> d_weight;                 // weights' vector(m*n)
            int d_weight_sum;                                        // all weights' sum
     
        public:
            averagingFilterMask(unsigned int m, unsigned int n, const std::vector<pixelType>& weightVec)
                : __filterMask<pixelType>(m, n), d_weight(weightVec)
            {
                if (weightVec.size() != d_mask.size())
                {
                    // if weight's size isn't equal to mask's size, it will change filter mask as a special filter mask
                    d_weight.resize(d_mask.size(), 1);
                }
     
                d_weight_sum = std::accumulate(d_weight.begin(), d_weight.end(), 0);
            }
     
            pixelType response()
            {
                return std::inner_product(d_mask.begin(), d_mask.end(), d_weight.begin(), 0) / d_weight_sum;
            }
        };
     
        // 中值滤波器
        template <typename pixelType>
        class medianFilterMask
            : public __filterMask<pixelType>
        {
        public:
            medianFilterMask(unsigned int m, unsigned int n)
                : __filterMask<pixelType>(m, n)
            { }
     
            pixelType response()
            {
                std::sort(d_mask.begin(), d_mask.end());
                return d_mask[d_mask.size()/2];
            }
        };
     
        // 3*3拉普拉斯滤波器
        // the mask is: [0 1 0           [0 -1 0
        //             1 -5 1     or    -1 5 -1
        //             0 1 0]          0 -1 0]
        // if pixel's brightness is less than min, set it to min
        // if pixel's brightness is larger than max, set it to max
        template <typename pixelType, pixelType min, pixelType max>
        class laplacianFilter
            : public __filterMask<pixelType>
        {
        public:
            laplacianFilter()
                : __filterMask<pixelType>(3, 3)
            { }
     
            pixelType response()
            {
                int ret = (int)(5*(int)d_mask[4]) - ((int)d_mask[5]+d_mask[3]+d_mask[1]+d_mask[7]);
                if (ret < min)
                    ret = min;
                if (ret > max)
                    ret = max;
                return ret;
            }
        };
     
        // 3*3Sobel滤波器
        // the mask is: [-1 -2 -1            [-1 0 1
        //            0 0 0    and       -2 0 2
        //            1 2 1]             -1 0 1]
        // if pixel's brightness is larger than max, set it to max
        template <typename pixelType, pixelType max>
        class sobelFilter
            : public __filterMask<pixelType>
        {
        public:
            sobelFilter()
                : __filterMask<pixelType>(3, 3)
            { }
     
            pixelType response()
            {
                int ret = ::abs(d_mask[6]+2*d_mask[7]+d_mask[8]-d_mask[0]-2*d_mask[1]-d_mask[2])
                    + ::abs(d_mask[2]+2*d_mask[5]+d_mask[8]-d_mask[0]-2*d_mask[3]-d_mask[6]);
               
                if (ret > max)
                    ret = max;
                return ret;
            }
        };
    }
     
    #endif
     
    数字图像处理算法实现
                                     ------------编程心得(1)
    2001414朱伟 20014123
    摘要: 关于空间域图像处理算法框架,直方图处理,空间域滤波器算法框架的编程心得,使用GDI+(C++)
    一,图像文件的读取
        初学数字图像处理时,图像文件的读取往往是一件麻烦的事情,我们要面对各种各样的图像文件格式,如果仅用C++的fstream库那就必须了解各种图像编码格式,这对于初学图像处理是不太现实的,需要一个能帮助轻松读取各类图像文件的库。在Win32平台上GDI+(C++)是不错的选择,不光使用上相对于Win32 GDI要容易得多,而且也容易移植到.Net平台上的GDI+。
        Gdiplus::Bitmap类为我们提供了读取各类图像文件的接口,Bitmap::LockBits方法产生的BitmapData类也为我们提供了高速访问图像文件流的途径。这样我们就可以将精力集中于图像处理算法的实现,而不用关心各种图像编码。具体使用方式请参考MSDN中GDI+文档中关于Bitmap类和BitmapData类的说明。另外GDI+仅在Windows XP/2003上获得直接支持,对于Windows 2000必须安装相关DLL,或者安装有Office 2003,Visual Studio 2003 .Net等软件。
    二,空间域图像处理算法框架
     (1) 在空间域图像处理中,对于一个图像我们往往需要对其逐个像素的进行处理,对每个像素的处理使用相同的算法(或者是图像中的某个矩形部分)。即,对于图像f(x,y),其中0≤x≤M,0≤y≤N,图像为M*N大小,使用算法algo,则f(x,y) = algo(f(x,y))。事先实现一个算法框架,然后再以函数指针或函数对象(functor,即实现operator()的对象)传入算法,可以减轻编程的工作量。
        如下代码便是一例:

    #ifndef PROCESSALGO_H
    #define PROCESSALGO_H
     
    #include <windows.h>
    #include <Gdiplus.h>
     
     
    namespace nsimgtk
    {
             template <typename pixelType, Gdiplus::PixelFormat pixelFormat, class Processor>
        bool ProcessPixelsOneByOne(Gdiplus::Bitmap* const p_bitmap, Processor processor, unsigned int x, unsigned int y,
                                                               unsigned int width, unsigned int height)
        {
                       if (p_bitmap == NULL)
                       {
                                return false;
                       }
     
                       if ((width + x > p_bitmap->GetWidth()) || (height + y >p_bitmap->GetHeight()))
                       {
                                return false;
                       }
     
            Gdiplus::BitmapData bitmapData;
                       Gdiplus::Rect rect(x, y, width,height);
           
            if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixelFormat, &bitmapData) != Gdiplus::Ok)
                {
                                return false;
                       }
     
                       pixelType *pixels = (pixelType*)bitmapData.Scan0;
                      
     
            for (unsigned int row=0; row<height; ++row)
                       {
                                for (unsigned int col=0; col<width; ++col)
                                {
                                         processor(&pixels[col+row*bitmapData.Stride/sizeof(pixelType)]);     
                                }
                       }
     
                       if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
                       {
                                return false;
                       }
           
                       return true;
             }
    }
     
    #endif

    ProcessPixelsOneByOne函数可以对图像中从(x,y)位置起始,width*height大小的区域进行处理。模板参数pixelType用于指定像素大小,例如在Win32平台上传入unsigned char即为8位,用于8阶灰度图。模板参数Processor为图像处理算法实现,可以定义类实现void operator(pixelType *)函数,或者传入同样接口的函数指针。
        如下便是一些算法示例(说明见具体注释):

    #ifndef SPATIALDOMAIN_H
    #define SPATIALDOMAIN_H
    #include <cmath>
    #include <string>
     
    namespace nsimgtk
    {
       // 8阶灰度图的灰度反转算法 
             class NegativeGray8
             {
             public:
                       void operator()(unsigned char *const p_value)
                       {
                                *p_value ^= 0xff;
                       }
             };
       
       // 8阶灰度图的Gamma校正算法
             class GammaCorrectGray8
             {
             private:
                       unsigned char d_s[256];
             public:
                       GammaCorrectGray8::GammaCorrectGray8(double c, double gamma);
     
                       void operator()(unsigned char*const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
     
        // 8阶灰度图的饱和度拉伸算法
             class ContrastStretchingGray8
             {
             private:
                       unsigned char d_s[256];
             public:
                       ContrastStretchingGray8::ContrastStretchingGray8(double a1, double b1, unsigned int x1,
                                double a2, double b2, unsigned int x2, double a3, double b3);
     
                       void operator()(unsigned char*const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
       
        // 8阶灰度图的位平面分割,构造函数指定位平面号
             class BitPlaneSliceGray8
             {
             private:      
                       unsigned char d_s[256];
             public:
                       BitPlaneSliceGray8(unsigned char bitPlaneNum);
     
                       void operator()(unsigned char* const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
    }
     
    #endif
     
    // 上述类中各构造函数的实现代码,应该分在另一个文件中,此处为说明方便,一并列出
    #include "SpatialDomain/spatialDomain.h"
     
    namespace nsimgtk
    {
             GammaCorrectGray8::GammaCorrectGray8(double c, double gamma)
             {
                       double temp;
                       for (unsigned int i=0; i<256; ++i)
                       {
                                temp = ceil(c * 255.0 * pow(double(i)/255.0, gamma));
                                d_s[i] = unsigned char(temp);
                       }
             }
     
             ContrastStretchingGray8::ContrastStretchingGray8(double a1, double b1, unsigned int x1,
                                double a2, double b2, unsigned int x2, double a3, double b3)
             {
                       if (x1 > 255 || x2 > 255 || x1 > x1)
                       {
                                for (unsigned int i=0; i<256; ++i)
                                         d_s[i] = i;
                       }
                       else
                       {
                                double tmp;
                                for (unsigned int i=0; i<x1; ++i)
                                {
                                         tmp = ceil(a1*double(i)+b1);
                                         d_s[i] = (unsigned char)tmp;
                                }
     
                                for (unsigned int i=x1; i<x2; ++i)
                                {
                                         tmp = ceil(a2*double(i)+b2);
                                         d_s[i] = (unsigned char)tmp;
                                }
     
                                for (unsigned int i=x2; i<256; ++i)
                                {
                                         tmp = ceil(a3*double(i)+b3);
                                         d_s[i] = (unsigned char)tmp;
                                }
                       }
             }
     
             BitPlaneSliceGray8::BitPlaneSliceGray8(unsigned char bitPlaneNum)
             {
                      unsigned char bitMaskArray[8] =
                       {
                                0x01, 0x02, 0x04, 0x08,
                                0x10, 0x20, 0x40, 0x80
                       };
     
                       for (unsigned int i=0; i<256; ++i)
                       {
                                unsigned char tmp = i;
                                tmp &= bitMaskArray[bitPlaneNum];
                                tmp = (tmp >> bitPlaneNum) * 255;
                                d_s[i] = tmp;
                      }
             }
    }

    (2) 直方图在GDI+1.0中没有获得支持,我们必须自行实现。直方图相关的处理在数字图像处理中占有重要地位,可以通过它获取图像灰度级的统计信息,且可以通过直方图进行一些重要的图像增强技术,如直方图均衡化,直方图规定化,基本全局门限等。
    下面是获取8阶图像直方图的算法实现:

    namespace nsimgtk
    {
             bool GetHistogramNormalizeGray8(Gdiplus::Bitmap * const p_bitmap, float *histogramArray)
             {
                       if (p_bitmap == NULL || histogramArray == NULL)
                       {
                                return false;
                       }
     
                       Gdiplus::BitmapData bitmapData;
                       Gdiplus::Rect rect(0, 0, p_bitmap->GetWidth(), p_bitmap->GetHeight());
     
                       if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat8bppIndexed, &bitmapData) != Gdiplus::Ok)
                {
                                return false;
                       }
     
                       unsigned char *pixels = (unsigned char*)bitmapData.Scan0;
            unsigned int histogram[256];
                       for (int i=0; i<256; ++i)
                       {
                                histogram[i] = 0;
                       }
     
                       for (unsigned int row=0; row<p_bitmap->GetWidth(); ++row)
                       {
                                for (unsigned int col=0; col<p_bitmap->GetHeight(); ++col)
                                {
                                         ++histogram[pixels[col+row*bitmapData.Stride]];
                                }
                       }
     
                       const unsigned int totalPixels = p_bitmap->GetWidth() * p_bitmap->GetHeight();
                       for (int i=0; i<256; ++i)
                       {
                                histogramArray[i] = float(histogram[i]) / float(totalPixels);
                       }
     
                       if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
                       {
                                return false;
                       }
     
                       return true;
             }
    }

    在获取直方图后(即上面算法的第二个参数),再将其作为参数传入下面的对象的构造函数,然后以该对象为仿函数传入ProcessPixelsOneByOne即可实现8阶图像直方图均衡化:

    #ifndef SPATIALDOMAIN_H
    #define SPATIALDOMAIN_H
     
    #include <cmath>
    #include <string>
     
    namespace nsimgtk
    {
        // 8阶灰度图的直方图均衡化
             class HistogramEqualizationGray8
             {
             private:
                       unsigned char d_s[256];
             public:
                       HistogramEqualizationGray8(const float *const histogramArray);
                      
                       void operator()(unsigned char *const p_value)
                       {
                                *p_value = d_s[*p_value];
                       }
             };
    }
     
    #endif        
     
    //
    #include "SpatialDomain/spatialDomain.h"
     
    namespace nsimgtk
    {
             HistogramEqualizationGray8::HistogramEqualizationGray8(const float *const histogramArray)
             {
                       if (histogramArray != NULL)
                       {
                                float sum = 0.0;
                                for (int i=0; i<256; ++i)
                                {
                                         sum += histogramArray[i];
                                         d_s[i] = unsigned char(sum * 255);
                                }
                       }
             }
    }      

    (3)空间域滤波器,滤波器是一个m*n大小的掩模,其中m,n均为大于1的奇数。滤波器逐像素地通过图像的全部或部分矩形区域,然后逐像素地对掩模覆盖下的像素使用滤波器算法获得响应,将响应赋值于当前像素即掩模中心像素,另外滤波器算法使用中将会涉及到图像边缘的问题,这可以对边缘部分掩模使用补零法补齐掩模下无像素值的区域,或者掩模的移动范围以不越出图像边缘的方式移动,当然这些处理方法都会给图像边缘部分带来不良效果,但是一般情况下,图像边缘部分往往不是我们关注的部分或者没有重要的信息。
    下面的滤波器算法框架SpatialFilterAlgo即以补零法(zero-padding)实现:

    #ifndef SPATIALFILTER_H
    #define SPATIALFILTER_H
     
    #include <vector>
    #include <numeric>
    #include <algorithm>
    #include <gdiplus.h>
    #include <fstream>
    #include <cmath>
     
    namespace nsimgtk
    {
        template <typename pixelType, Gdiplus::PixelFormat pixelFormat, class FilterMask>
        bool SpatialFilterAlgo(Gdiplus::Bitmap* const p_bitmap, FilterMask filterMask, unsigned int x, unsigned int y,
                                                               unsigned int width, unsigned int height)
        {
                       if (p_bitmap == NULL)
                       {
                                return false;
                       }
     
                       if ((width + x > p_bitmap->GetWidth()) || (height + y >p_bitmap->GetHeight()))
                       {
                                return false;
                       }
     
            Gdiplus::BitmapData bitmapData;
                       Gdiplus::Rect rect(x, y, width,height);
           
            if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixelFormat, &bitmapData) != Gdiplus::Ok)
                {
                                return false;
                       }
     
                       pixelType *pixels = (pixelType*)bitmapData.Scan0;
                      
            const unsigned int m = filterMask.d_m;                                         // mask's width
            const unsigned int n = filterMask.d_n;                                          // mask's height
            std::vector<pixelType> tmpImage((m-1+width)*(n-1+height));   // extend image to use zero-padding
           
            // copy original bitmap to extended image with zero-padding method
            for (unsigned int row=0; row<height; ++row)
                       {
                                for (unsigned int col=0; col<width; ++col)
                                {
                                         tmpImage[(col+m/2)+(row+n/2)*(bitmapData.Stride/sizeof(pixelType)+m-1)] =
                        pixels[col+row*bitmapData.Stride/sizeof(pixelType)];    
                                }
                       }
           
            // process every pixel with filterMask
            for (unsigned int row=0; row<height; ++row)
                       {
                                for (unsigned int col=0; col<width; ++col)
                                {
                    // fill the "m*n" mask with the current pixel's neighborhood
                    for (unsigned int i=0; i<n; ++i)
                    {
                        for (unsigned int j=0; j<m; ++j)
                        {
                            filterMask.d_mask[i*m+j] = tmpImage[(col+j)+(row+i)*(bitmapData.Stride/sizeof(pixelType)+m-1)];
                        }
                    }
                 
                    // replace the current pixel with filter mask's response
                                         pixels[col+row*bitmapData.Stride/sizeof(pixelType)] = filterMask.response();      
                                }
                       }
     
            if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
                       {
                                return false;
                       }
           
                       return true;
             }
    }
     
    #endif

    其中模板参数FilterMask即为滤波掩模算法。通常的滤波算法有均值滤波器,可以模糊化图像,去除图形中的细节部分,使得我们可以关注图像中较为明显的部分,均值滤波器用于周期性噪声。中值滤波器用于图像中存在椒盐噪声也即脉冲噪声的情况下。另外有基于一阶微分的Sobel梯度算子和基于两阶微分的拉普拉斯算子,它们往往被用于边缘检测中。
    下面是一些滤波器算法的具体实现,所以滤波器算法都应该实现pixelType response()函数以及有d_mask,d_m,d_n成员,这可以通过继承__filteMask类获得(不需要付出虚函数代价)。

    #ifndef SPATIALFILTER_H
    #define SPATIALFILTER_H
     
    #include <vector>
    #include <numeric>
    #include <algorithm>
    #include <gdiplus.h>
    #include <fstream>
    #include <cmath>
     
    namespace nsimgtk
    {
        // 滤波器掩模的基类,提供掩模大小d_m,d_n,掩模覆盖下的m*n个像素值d_mask
        // others filterMask should inherit it
        template <typename pixelType>
        struct __filterMask
        {
            const unsigned int d_m;
            const unsigned int d_n;
     
            // image's pixels under the m*n filter mask
            std::vector<pixelType> d_mask;
     
            // filter mask's width and heigh must be a odd, if not, it will plus one for the width or the height
            __filterMask(unsigned int m, unsigned int n)
                : d_m(m%2 ? m:m+1), d_n(n%2 ? n:n+1), d_mask(d_m*d_n)
            {
            }
        };
     
        // 掩模权值为全1的均值滤波器
        template <typename pixelType>
        class averagingFilterMaskSp
            : public __filterMask<pixelType>
        {
        public:
            averagingFilterMaskSp(unsigned int m, unsigned int n)
                : __filterMask<pixelType>(m, n)
            { }
     
            pixelType response()
            {
                return std::accumulate(d_mask.begin(), d_mask.end(), 0) / (d_m * d_n);
            }
        };
     
        // 可自定义掩模权值的均值滤波器
        template <typename pixelType>
        class averagingFilterMask
            : public __filterMask<pixelType>
        {
        private:
            std::vector<pixelType> d_weight;                 // weights' vector(m*n)
            int d_weight_sum;                                        // all weights' sum
     
        public:
            averagingFilterMask(unsigned int m, unsigned int n, const std::vector<pixelType>& weightVec)
                : __filterMask<pixelType>(m, n), d_weight(weightVec)
            {
                if (weightVec.size() != d_mask.size())
                {
                    // if weight's size isn't equal to mask's size, it will change filter mask as a special filter mask
                    d_weight.resize(d_mask.size(), 1);
                }
     
                d_weight_sum = std::accumulate(d_weight.begin(), d_weight.end(), 0);
            }
     
            pixelType response()
            {
                return std::inner_product(d_mask.begin(), d_mask.end(), d_weight.begin(), 0) / d_weight_sum;
            }
        };
     
        // 中值滤波器
        template <typename pixelType>
        class medianFilterMask
            : public __filterMask<pixelType>
        {
        public:
            medianFilterMask(unsigned int m, unsigned int n)
                : __filterMask<pixelType>(m, n)
            { }
     
            pixelType response()
            {
                std::sort(d_mask.begin(), d_mask.end());
                return d_mask[d_mask.size()/2];
            }
        };
     
        // 3*3拉普拉斯滤波器
        // the mask is: [0 1 0           [0 -1 0
        //             1 -5 1     or    -1 5 -1
        //             0 1 0]          0 -1 0]
        // if pixel's brightness is less than min, set it to min
        // if pixel's brightness is larger than max, set it to max
        template <typename pixelType, pixelType min, pixelType max>
        class laplacianFilter
            : public __filterMask<pixelType>
        {
        public:
            laplacianFilter()
                : __filterMask<pixelType>(3, 3)
            { }
     
            pixelType response()
            {
                int ret = (int)(5*(int)d_mask[4]) - ((int)d_mask[5]+d_mask[3]+d_mask[1]+d_mask[7]);
                if (ret < min)
                    ret = min;
                if (ret > max)
                    ret = max;
                return ret;
            }
        };
     
        // 3*3Sobel滤波器
        // the mask is: [-1 -2 -1            [-1 0 1
        //            0 0 0    and       -2 0 2
        //            1 2 1]             -1 0 1]
        // if pixel's brightness is larger than max, set it to max
        template <typename pixelType, pixelType max>
        class sobelFilter
            : public __filterMask<pixelType>
        {
        public:
            sobelFilter()
                : __filterMask<pixelType>(3, 3)
            { }
     
            pixelType response()
            {
                int ret = ::abs(d_mask[6]+2*d_mask[7]+d_mask[8]-d_mask[0]-2*d_mask[1]-d_mask[2])
                    + ::abs(d_mask[2]+2*d_mask[5]+d_mask[8]-d_mask[0]-2*d_mask[3]-d_mask[6]);
               
                if (ret > max)
                    ret = max;
                return ret;
            }
        };
    }
     
    #endif

     
     
    展开全文
  • FPGA的图像处理算法

    千次阅读 2019-02-25 15:07:47
    下面简要分析了 FPGA 技术,包括 FPGA 技术原理和技术特点等,随后介绍一下FPGA 的图像处理系统算法实现,包括存储模块、运算单元、控制模块以及数据传输模块等内容。 智能机器人、多媒体已经计算机的诞生都离不...

    下面简要分析了 FPGA 技术,包括 FPGA 技术原理和技术特点等,随后介绍一下FPGA 的图像处理系统算法的实现,包括存储模块、运算单元、控制模块以及数据传输模块等内容。

    智能机器人、多媒体已经计算机的诞生都离不开数字图象处理技术,随着计算机智能化图像处理技术的不断发展,几乎所有领域当中都有数字图象技术的身影。例如军事、公共安全、工业、航天航空、卫星遥感以及生命科学等各种领域。因此对图象处理技术的要求也逐渐提高,需要数字图象设计朝着高效性和时效性的方向发展,FPGA技术下的图像处理系统算法越来越受到重视。

    1、FPGA技术原理

    FPGA通常包括两个部分,分别是储存编程数据的软件SRAM和三项可编程电路,这三种可编程电路分别是互连资源、输入模块、输出模块和可编程逻辑模块。FPGA中主要部分就是可编程逻辑模块,这一模块能够落实逻辑功能,同时还可以参考设计要求,灵活选择设置或是连接,从而实现各种逻辑功能。而输送模块则是芯片与外部环境进行连接的主要通道,能够促进内部逻辑阵列和器件引脚的连接,同时实现各种电气特征下的输送功能要求。芯片四周通常会排列IOB。

    2、FPGA技术特点

    FPGA既包含ASIC中的高度可靠性、高集成度和大规模等优势,同时还包括ASIC设计中灵活性差、投资大、设计时间长等问题,
    除了上述优势外,FPGA还包括下面几项优点,首先是FPGA能够反复进行擦除和编程。在外部电路保持不变的状态下,通过设计不同逻辑可以完成各种电路功能。其次是投资较小,同时设计比较灵活,在发现问题后可以对设计直接进行更改,从而降低了投片风险程度。

    3、FPGA的图象处理系统算法的实现

    图像算法处理系统中的存储模块能够将提前准备好的图象数据进行存储,运算单元负责各项计算任务,促进实现各种图像处理算法,只需要将其中的数值进行更换即可。控制模块负责图像算法处理系统中的各种控制工作,辅助图像算法实施,并进行传输。

    3.1、存储模块

    随着FPGA技术的不断发展,从前众多优秀设计人员留下了大量数字系统成果。为了让其中部分成果能够有效应用于Altera特定设
    备结构中,并进行有效应用,Altera企业根据Altera设备中的结构特征在上述成果的基础上进行了有效的优化,从而形成一种LPM
    函数和可参数化模块,为此设计人员需要参考相应的设计要求,通过硬件或是图形将语言模块中功能板块恰当地表述出来,并设置好一定的参数,尽量贴近系统要求。在这种设计模式下,能够提升设计效率和可靠性。

    3.2、运算单元

    运算单元的工作其实就是输出数据信息、落实数字图像算法和读取ROM数字图象中的灰度信息。当一个是三乘三中值邻域滤波器模板对目标图象进行作用时,首先应该了解这一滤波器中的九个数据信息,随后才能更好地使用中值滤波算法,而ROM中所储存的灰度数据主要可以在Verilog HDL的编程下,将其中的具体数值解读出来,同时FPGA技术下的编程工作中是不存在二维数组理念的,为此主要是通过移位寄存器RAM来储存IP核的,并落实邻域图象处理操作,实现各种数字图像处理算法。在一个全面的系统设计当中,例如设计DSP应用系统,需要通过数据缓冲移位寄存器,以移位寄存器RAM为基础的IP核就是一种高效的处理措施。以移位寄存器RAM为基础的IP核属于一种参数化的移位寄存器,同时TAPS值在一定程度上也影响了系统中移位寄存器在一时间点中的输出数据总路数,这种IP核十分适用于有限冲击响应滤波器和线性反馈寄存器。对于以移位寄存器RAM为基础的IP
    核想要发挥出应有的作用,就应该先为IP核进行适当的参数设置,主要包括所有TAP的对应数据深度、TAP输出路数、shiftout端
    口宽度、shiftin数据宽度、RAM模块类型等。

    3.3、控制模块

    控制模块在整个系统中是一种核心部件,可以辅助系统的运行,同时融入到整个系统内部。主要负责工作包括辅助运算单元在
    ROM中准确读取数据信息,操作运算单元落实图像处理算法,帮助运算单元和数据传输子系统进行信息流通等。

    3.4、数据传输模块

    数据传输模块其中包含两部分内容,分别是串口通信模块和FIFO传输模块。将图像处理子系统中的时钟设置成五十毫赫兹,将串口通信模块设置成九千六百赫兹波特率。为此可以通过异步FIFO促进图像通信模块和子系统串口之间的跨时钟数据传播,联系。为了让图像算法子系统和上位机PC之间的通信过程更加便捷,通常都是通过通信串口进行数据信息交流。

    通过FPGA技术进行图象处理,能够拥有更多的使用优势,比如成本较低、方便落实以及适用范围较广等特点。同时还拥有实时性、集成化、小型化等特点。随着我国微电子技术的发展,图象处理逐渐应用于图象通信以及多媒体等各个领域,而FPGA技术
    可以有效促进硬件对实时图象的有效处理,以FPGA技术为基础的图象处理研究也将成为未来信息领域发展的热点。

     

     

     

     

    展开全文
  • 数字图像处理算法实现 ------------编程心得(1)2001414班 朱伟 20014123摘要: 关于空间域图像处理算法框架,直方图处理,空间域滤波器算法框架的编程心得,使用GDI+(C++)一,图像文件的读取 初学数字图像处理时,...
  • 数字图像处理领域的二十四个典型算法及vc实现、第一章 - 结构之法 算法之道 - 博客频道 - CSDN.NET http://blog.csdn.net/v_july_v/article/details/6210124   数字图像处理领域的二十四个典型算法及vc实现、第...
  • 图像拼接算法及实现

    万次阅读 2014-10-30 18:14:55
     图像拼接(image mosaic)是一个日益流行的研究领域,他已经成为照相绘图学、计算机视觉、图像处理和计算机图形学研究中的热点。图像拼接解决的问题一般式,通过对齐一系列空间重叠的图像,构成一个无缝的、高清晰的...
  • 2015年10月30日09:39:36 从今天开始进行图像去雾、增强、去噪等图像处理算法的GPU实现。 实验室买了一个GPU,GTX970,算比较高端的GPU了,目前CUDA只支持N卡。 加油!
  • 本店绝非中介,本店代码均由本人硕士师弟代写完成,提供有偿Matlab算法代码编程服务,不从事不违反涉及学术原则的事。 另外,本店的所有宝贝都由本人师弟亲自编写,淘宝上其他的卖家大多 是中介,价格贵不说,...
  • 图像处理算法工程师面试题

    万次阅读 2017-07-31 09:09:16
    图像基础知识: 1. 常用的图像空间。 2. 简述你熟悉的聚类算法并说明其优缺点。 3. 请描述以下任一概念:SIFT/SURF LDA/PCA 4. 请说出使用过的分类器和实现原理。 5. Random Forest的随机性表现在哪里。 6. Graph-...
  • 1.深度学习基础模型算法原理及编程实现–01.感知机. 2.深度学习基础模型算法原理及编程实现–02.线性单元 . 3.深度学习基础模型算法原理及编程实现–03.全链接 . 4.深度学习基础模型算法原理及编程实现–04.改进...
  • 主要涉及图形处理,包括形态学、图像质量、相机成像之3A算法、去雾处理、颜色空间转换、滤镜等,主要在安防公司或者机器视觉领域,包括缺陷检测; 二、现代图像算法工程师: 涉及模式识别,主要表现的经验为Adaboost...
  • 【数字图像处理】Canny边缘检测详解及编程实现

    万次阅读 多人点赞 2011-12-09 21:25:26
    下面详细介绍Canny边缘检测算法的原理以及编程实现。 Canny边缘检测基本原理: (1)图象边缘检测必须满足两个条件:一能有效地抑制噪声;二必须尽量精确确定边缘的位置。  (2)根据对信噪比与定位乘积进行测度,...
  • 图像分割基础算法及实现实例

    万次阅读 多人点赞 2016-04-19 17:09:30
    最近的项目涉及到了图像处理领域,小小研究了一番,同时收集资料实现了几个基础功能。 一、图像反转 I=imread('input_image.jpg'); J=double(I); J=-J+(256-1); %图像反转线性变换 H=uint8(J); subplot(3,3,4),...
  • 华为图像处理算法实习生面试记录

    千次阅读 2018-12-24 16:11:53
    岗位:算法工程师实习生(图像处理方向) 面试方式:一面电话面,二面视频面(异地原因) 面试 一面(技术面): 1、从头到尾把简历问了一遍,深剖,重点是自己干的东西 2、算法考试: 给定一个Array,再给定...
  • 1、掌握一阶锐化算法的工作原理和算法实现。 2、掌握二阶锐化算法的工作原理和算法实现。 实验内容 实现拉普拉斯锐化。测试图像:’Grayblur6.png’。 实验代码 im = imread('.\im\Grayblur6.png'); imshow(im); ...
  • 图像处理基本思想和算法研究

    千次阅读 2016-05-09 20:38:07
    意在介绍图像处理中的一些基本算法,后来仔细想想决定不这么写,因为图像处理是一个非常大的概念,图像处理不等于人脸识别,也不等于模式识别,直接介绍诸如图像处理基本算法之类的内容很容易写成空话,没有什么实际...
  • 高级图像信号处理算法工程师

    千次阅读 2014-07-29 14:29:28
    岗位职责:主要负责网络摄像机的ISP图像处理算法研究、优化与开发。 任职要求: 1、计算机、电子工程、自动控制等相关专业,本科以上学历; 2、从事过3A算法(自动曝光、自动对焦、自动白平衡)算法系统设计...
  • 【FPGA笔记】基于FPGA的图像处理

    千次阅读 2018-06-19 14:52:15
    算法开发和FPGA实现分离用软件的图像处理环境可以使用大批量的图像样本进行测试调试算法,再将算法映射到硬件上,这样大大节省了硬件调试周期。2.算法的精度图像处理算法中,大部分需要采用浮点数运算,而...
1 2 3 4 5 ... 20
收藏数 66,761
精华内容 26,704
关键字:

图像处理算法及编程实现