原文地址http://blog.sina.com.cn/s/blog_684c8d630100turx.html

刚开会每周的例会,最讨厌开会了,不过为了能顺利毕业,只能忍了。闲话不多说了,下面把上周学习的一个简单的算法总结一下,以备后面写毕业论文的时候可以参考一下。
一、Census Transform(CT)算法的学习
    Census Transform 算法是Ramin Zabih 和 John Woodfill 于1994年在他们的论文《Non-parametric LocalTransforms for Computing VisualCorrespondence》中提出的,正如他们在论文中所说,这是一种非参数变换,主要用来表征图像的局部结构特征,能够比较好的检测到图像中的边缘特征和角点特征,从这篇论文的470次的引用次数来看,CT算法用处还是挺广泛的。下面简要介绍一下CT算法的基本思想:用一个3*3或者5*5的滑动窗口遍历整幅图像,对于每次遍历的位置,以3*3为例,假设某个位置如下图所示
123 127 129
126 128 129
127 131 130
然后比较此窗口中每个像素值(中心除外)与中心像素值的大小,如果比中心像素值小,则比较结果为1,否则为0。由此,得到如下结果:

1 1 0
1   0
1 0 0

然后,把此窗口结果组成一个序列:11010100,以此二进制序列表示的值来代替原图像窗口中心点的像素。如此下去,等到窗口滑动完整幅图像,我们就得到原图像做统计变换(CT)之后的图像。

注意:只能作用于灰度图像,对于彩色图像,则需要转换为灰度图之后再操作;为了简单起见,我没有考虑图像的边缘像素值。
   下面给出一种用 matlab 实现的版本:

  1. % *************************************************************************
  2. % Title: Function-Census Transform of a given Image
  3. % Author: Siddhant Ahuja
  4. % Created: May 2008
  5. % Copyright Siddhant Ahuja, 2008
  6. % Inputs: Image (var: inputImage), Window size assuming square window (var:
  7. % windowSize) of 3x3 or 5x5 only.
  8. % Outputs: Census Tranformed Image (var: censusTransformedImage),
  9. % Time taken (var: timeTaken)
  10. % Example Usage of Function: [a,b]=funcCensusOneImage('Img.png', 3)
  11. % *************************************************************************
  12. function [censusTransformedImage, timeTaken] = funcCensusOneImage(inputImage, windowSize)
  13. % Grab the image information (metadata) using the function imfinfo
  14. try
  15. imageInfo = imfinfo(inputImage);
  16. % Since Census Transform is applied on a grayscale image, determine if the
  17. % input image is already in grayscale or color
  18. if(getfield(imageInfo,'ColorType')=='truecolor')
  19. % Read an image using imread function, convert from RGB color space to
  20. % grayscale using rgb2gray function and assign it to variable inputImage
  21. inputImage=rgb2gray(imread(inputImage));
  22. else if(getfield(imageInfo,'ColorType')=='grayscale')
  23. % If the image is already in grayscale, then just read it.
  24. inputImage=imread(inputImage);
  25. else
  26. error('The Color Type of Input Image is not acceptable. Acceptable color types are truecolor or grayscale.');
  27. end
  28. end
  29. catch
  30. inputImage = inputImage;
  31. end
  32. % Find the size (columns and rows) of the image and assign the rows to
  33. % variable nr, and columns to variable nc
  34. [nr,nc] = size(inputImage);
  35. % Check the size of window to see if it is an odd number.
  36. if (mod(windowSize,2)==0)
  37. error('The window size must be an odd number.');
  38. end
  39. if (windowSize==3)
  40. bits=uint8(0);
  41. % Create an image of size nr and nc, fill it with zeros and assign
  42. % it to variable censusTransformedImage of type uint8
  43. censusTransformedImage=uint8(zeros(nr,nc));
  44. else if (windowSize==5)
  45. bits=uint32(0);
  46. % Create an image of size nr and nc, fill it with zeros and assign
  47. % it to variable censusTransformedImage of type uint32
  48. censusTransformedImage=uint32(zeros(nr,nc));
  49. else
  50. error('The size of the window is not acceptable. Just 3x3 and 5x5 windows are acceptable.');
  51. end
  52. end
  53. % Initialize the timer to calculate the time consumed.
  54. tic;
  55. % Find out how many rows and columns are to the left/right/up/down of the
  56. % central pixel
  57. C= (windowSize-1)/2;
  58. for j=C+1:1:nc-C % Go through all the columns in an image (minus C at the borders)
  59. for i=C+1:1:nr-C % Go through all the rows in an image (minus C at the borders)
  60. census = 0; % Initialize default census to 0
  61. for a=-C:1:C % Within the square window, go through all the rows
  62. for b=-C:1:C % Within the square window, go through all the columns
  63. if (~(a==0 && b==0)) % Exclude the centre pixel from the calculation,原来是(C+1),现改为0
  64. census=bitshift(census,1); %Shift the bits to the left  by 1
  65. % If the intensity of the neighboring pixel is less than
  66. % that of the central pixel, then add one to the bit
  67. % string
  68. if (inputImage(i+a,j+b) < inputImage(i,j))
  69. census=census+1;
  70. end
  71. end
  72. end
  73. end
  74. % Assign the census bit string value to the pixel in imgTemp
  75. censusTransformedImage(i,j) = census;
  76. end
  77. end
  78. % Stop the timer to calculate the time consumed.
  79. timeTaken=toc;
   这是我在网上找到的一个实现的版本,注释比较多,除去注释的话,真正代码没有50行,比较简单,相信大家都可以看的懂。
  之前讲了CT算法的实现,下面说一下 MCT 以及 RMCT的实现。

二、Modified Census Transform (MCT)算法
    MCT 算法是 CT 算法的一个修改版本,它是由Bernhard Froba 在做人脸检测的时候提出来的,在他2004年发表的论文《Face Detection with theModified Census Transform》中,Bernhard Froba将 CT算法中“滑动窗口中每个像素值与中心位置像素做比较”改为“滑动窗口中每个像素值与整个窗口中像素的均值做比较”,这样,原有的每个3*3的窗口可能产生256种序列(因为没有算中心像素),现在变为可能产生512种序列(其实全0和全1的序列表示的是同样的信息,可以排除一个),也就是做完MCT之后,图像的每个像素值的范围为0——511,这样就能够比较充分的利用3*3的核(至于为什么这么说,可以看看前面提到的那篇论文)。如此来计算的话,则前面例子产生的结果窗口应该为:

1 1 0
1 0 0
1 0 0

对应的二进制序列为:110100100。然后以此作为中心像素点的像素值,循环完毕之后便得到MCT之后的图像。需要注意的一点是,如果要使变换之后的图像得到显示,应该对像素值做一下归一化,使其在0——255之间。

 
三、Revised Modified Census Transform (RMCT)算法
    RMCT 算法其实又是对 MCT的又一次修改,它与 MCT的不同之处仅仅在于一个微小的△m,即:在滑动窗口像素均值上加上一个微小的变量△m=1或者2。其他都是完全一样的。
 
    下面附上这两种修改版统计变换的 C++代码,代码是我自己编的,是基于VS2008和OpenCV2.0的,仅供参考:
  1. #include "stdafx.h"
  2. #include "MCT.h"
  3. #include "highgui.h"
  4. MCT::MCT()
  5. {
  6. window_size = 0;
  7. }
  8. MCT::~MCT()
  9. {
  10. }
  11. void MCT::ModifiedCensusTransform(IplImage *input_image, IplImage *mct_image, const int window_size, const int delta )
  12. {
  13. CvSize image_size = cvGetSize(input_image);
  14. int image_width = image_size.width;
  15. int image_height = image_size.height;
  16. IplImage *gray_image = cvCreateImage(cvGetSize(input_image), input_image->depth, 1);
  17. cvSetZero(gray_image);
  18. if(input_image->nChannels != 1)
  19. {
  20. cvCvtColor(input_image, gray_image, CV_RGB2GRAY);
  21. }
  22. else
  23. {
  24. cvCopy(input_image, gray_image);
  25. }
  26. IplImage *modified_image = NULL;
  27. switch (window_size)
  28. {
  29. case 3:
  30. modified_image = cvCreateImage(image_size, IPL_DEPTH_16U, 1);
  31. cvSetZero(modified_image);
  32. break;
  33. case 5:
  34. modified_image = cvCreateImage(image_size, IPL_DEPTH_32S, 1);
  35. cvSetZero(modified_image);
  36. break;
  37. default:
  38. printf("window size must be 3 or 5!\n");
  39. exit(EXIT_FAILURE);
  40. }
  41. CvMat window;
  42. for(int i = 0; i < image_height - window_size; i++)
  43. {
  44. for(int j = 0; j < image_width - window_size; j++)
  45. {
  46. unsigned long census = 0;
  47. CvRect roi = cvRect(j, i, window_size, window_size);
  48. cvGetSubRect(gray_image, &window, roi);
  49. CvScalar m = cvAvg(&window, NULL);
  50. for(int w = 0; w < window_size; w++)
  51. {
  52. for(int h = 0; h < window_size; h++)
  53. {
  54. census = census << 1; //左移1位
  55. double tempvalue = cvGetReal2D(&window, w, h);
  56. if(tempvalue < m.val[0] + delta)
  57. census += 1;
  58. }
  59. }
  60. cvSetReal2D(modified_image, i, j, census);
  61. }
  62. }
  63. //cvConvertScaleAbs(modified_image, mct_image, 1, 0);
  64. Normalize(modified_image, mct_image);
  65. cvReleaseImage(&gray_image);
  66. cvReleaseImage(&modified_image);
  67. }
  68. void MCT::Normalize(IplImage *mct_image, IplImage *nor_image)
  69. {
  70. double minv, maxv;
  71. cvMinMaxLoc(mct_image, &minv, &maxv);
  72. for (int i = 0; i < mct_image->height; i++)
  73. {
  74. for (int j = 0; j < mct_image->width; j++)
  75. {
  76. double tempv = cvGetReal2D(mct_image, i, j);
  77. tempv = (tempv - minv) / (maxv - minv) * 255;
  78. cvSetReal2D(nor_image, i, j, tempv);
  79. }
  80. }
  81. }

由于算法比较简单,所以没有写注释,应该比较容易理解。

四、CT/MCT/RMCT的应用
   目前我读到的几篇论文里面,他们主要用于人脸检测或者面部伪装检测,用于做图像的预处理,这可能是因为CT算法对光照不敏感,可以比较好的排除光照对图像的影响。这里给出用到该算法的几篇paper:
1、《Face Detection with the Modified CensusTransform》(前面提到的那篇)
2、《Adaboost Based Disguised Face Discrimination on EmbeddedDevices》
3、《Disguised-Face Discriminator for Embedded Systems》
 
OVER!

关于统计变换(CT/MCT/RMCT)算法的学习和实现的更多相关文章

  1. 肺结节CT影像特征提取(二)——肺结节CT图像特征提取算法描述

    摘自本人毕业论文<肺结节CT影像特征提取算法研究> 医学图像特征提取可以认为是基于图像内容提取必要特征,医学图像中需要什么特征基于研究需要,提取合适的特征.相对来说,医学图像特征提取要求更 ...

  2. NLP之统计句法分析(PCFG+CYK算法)

    一.认识句法分析 首先,了解一下句法分析到底是什么意思?是做什么事情呢?顾名思义,感觉是学习英语时候讲的各种句法语法.没错!这里就是把句法分析过程交给计算机处理,让它分析一个句子的句法组成,然后更好理 ...

  3. 推荐一个算法编程学习中文社区-51NOD【算法分级,支持多语言,可在线编译】

    最近偶尔发现一个算法编程学习的论坛,刚开始有点好奇,也只是注册了一下.最近有时间好好研究了一下,的确非常赞,所以推荐给大家.功能和介绍看下面介绍吧.首页的标题很给劲,很纯粹的Coding社区....虽 ...

  4. 算法导论学习---红黑树具体解释之插入(C语言实现)

    前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜 ...

  5. 【树论 1】 prim算法的学习和使用

    进阶版神犇可以看看本题解的姊妹篇 Kruskal算法的学习和使用 下面的内容是prim算法 但是最小生成树是什么呢? 标准定义如下:在边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值 ...

  6. 毕业设计预习:SM3密码杂凑算法基础学习

    SM3密码杂凑算法基础学习 术语与定义 1 比特串bit string 由0和1组成的二进制数字序列. 2 大端big-endian 数据在内存中的一种表示格式,规定左边为高有效位,右边为低有效位.数 ...

  7. 第八模块:算法&设计模式、企业应用 第1章 常用算法&设计模式学习

    第八模块:算法&设计模式.企业应用 第1章 常用算法&设计模式学习

  8. leetcode 刷500道题,笔试/面试稳过吗?谈一谈这些年来算法的学习

    想要学习算法.应付笔试或者应付面试手撕算法题,相信大部分人都会去刷 Leetcode,有读者问?如果我在 leetcode 坚持刷它个 500 道题,以后笔试/面试稳吗? 这里我说下我的个人看法,我认 ...

  9. 【中国象棋人机对战】引入了AI算法,学习低代码和高代码如何混编并互相调用

    以低代码和高代码(原生JS代码)混编的方式引入了AI算法,学习如何使用表达式调用原生代码的.整个过程在众触低代码应用平台进行,适合高阶学员. AI智能级别演示 AI算法分三个等级,体现出来的智能水平不 ...

随机推荐

  1. ListBox实现拖拽排序功能

    1.拖拽需要实现的事件包括: PreviewMouseLeftButtonDown LBoxSort_OnDrop 具体实现如下: private void LBoxSort_OnPreviewMou ...

  2. MIUI选项框开关样式模拟

    有IOS的开关模拟,当然也有MIUI的开关模拟 看到设置选项里面的开关样式,突发奇想地来试试    最终效果如图: 实现过程 1. 选项框checkbox 模拟开关当然需要一个选项框,这里用到了复选框 ...

  3. 周末web前端练习

    在 CSS 样式定义中,以下哪种 RGB 颜色值是 Web 安全色?   A]#111111B]#222222C]#333333D]#444444 答案:http://hovertree.com/ti ...

  4. 并发式IO的解决方案:多路非阻塞式IO、多路复用、异步IO

    在Linux应用编程中的并发式IO的三种解决方案是: (1) 多路非阻塞式IO (2) 多路复用 (3) 异步IO 以下代码将以操作鼠标和键盘为实例来演示. 1. 多路非阻塞式IO 多路非阻塞式IO访 ...

  5. 泛函编程(21)-泛函数据类型-Monoid

    Monoid是数学范畴理论(category theory)中的一个特殊范畴(category).不过我并没有打算花时间从范畴理论的角度去介绍Monoid,而是希望从一个程序员的角度去分析Monoid ...

  6. NYOJ:题目860 又见01背包

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=860 方法一:不用滚动数组(方法二为用滚动数组,为方法一的简化) 动态规划分析:最少要拿总 ...

  7. oracle sql 语句优化

    (1)选择最有效率的表名顺序(只在基于规则的优化器中有效):Oracle的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理 ...

  8. 终端&作业控制&会话启动过程

    进程组 每个进程除了有个进程id外,还属于一个进程组.进程组是一个或者多个进程的集合.通常他们与同一个作业相关联,可以接受来自同一终端的信号.进程组id等于其进程组长id.进程组的终止与进程组长是否存 ...

  9. playframework文档未提及,但你能做的事

    这里记录一些play!框架的文档未提及,但是可以做的一些事playframe版本1.1 1.application.conf文件可以拆分可以把application.conf文件拆成多个,需要在app ...

  10. Javascript中的Label语句

    在javascript中,我们可能很少会去用到 Label 语句,但是熟练的应用 Label 语句,尤其是在嵌套循环中熟练应用 break, continue 与 Label 可以精确的返回到你想要的 ...