指尖检测测试(一)

    这几天做了一个指尖检测的测试程序,效果一般,主要是受环境影响比较大。目前我做的将手从复杂环境中提取出来的测试程序效果不是很好,受光影响较大,虽然我已经把RGB颜色空间转换了,将光强和色调隔离开来,但是还是有比较大的影响,后面会优化。

    首先用肤色检测将手提取出来,当然更简单的方法就是直接用阈值二值化,在某些简单背景下还行。下面是用肤色检测提取出的手掌图。

指尖检测测试(一)_第1张图片

    我用cvErode(dst,dst,NULL,2)和cvDilate(dst,dst,NULL,1)进行开闭处理,可以去掉一些小孔,然后将上图进行边缘提取cvCanny(dst,thinImage,50,150,3)。提取了边缘后,将每一类边缘用一个数据结构储存起来。我将这些边缘存放在CvSeq* contour中。

   边缘提取后的效果图

指尖检测测试(一)_第2张图片

简单说一下这个数据结构:

CvSeq* cvCreateSeq(int seq_flags,int header_size,int elem_size,CvMemStorage* storage)

  功能:创建一序列
  说明:CvSeq本身就是一个可增长的序列,不是固定的序列
  参数:seq_flags为序列的符号标志。如果序列不会被传递给任何使用特定序列的函数,那么将它设为0,否则从预定义的序列类型中选择一合适的类型。 Header_size为序列头部的大小;必须大于或等于sizeof(CvSeq)。如果制定了类型或它的扩展名,则此类型必须适合基类的头部大小。 Elem_size为元素的大小,以 字节计。这个大小必须与序列类型(由seq_flags指定)相一致。例如,对于一个点的序列,元素类型 CV_SEQ_ELTYPE_POINT应当被指定,参数elem_size必须等同于sizeof(CvPoint)。Storage为指向前面定义的内存存储器.

CvSeq*概述

  对于CvSeq这一结构体,又称为可动态增长元素序列(OpenCV_1.0已发生改变,详见cxtypes.h) Growable sequence of elements。
  CvSeq定义复杂,首先,定义CV_SEQUENCE_FIELDS()。
  #define CV_SEQUENCE_FIELDS() \
  int flags; /* micsellaneous flags */ 
  int header_size; /* size of sequence header */ 
  struct CvSeq* h_prev; /* previous sequence */ 
  struct CvSeq* h_next; /* next sequence */ 
  struct CvSeq* v_prev; /* 2nd previous sequence */ 
  struct CvSeq* v_next; /* 2nd next sequence */ 
  int total; /* total number of elements */ 
  int elem_size;/* size of sequence element in bytes */ 
  char* block_max;/* maximal bound of the last block */ 
  char* ptr; /* current write pointer */ 
  int delta_elems; /* how many elements allocated when the sequence grows (sequence
  granularity) */ 
  CvMemStorage* storage; /* where the seq is stored */ 
  CvSeqBlock* free_blocks; /* free blocks list */ 
  CvSeqBlock* first; /* pointer to the first sequence block */
  而CvSeq可以表达成:
  typedef struct CvSeq
  {
  CV_SEQUENCE_FIELDS()
  } CvSeq;
 由于在用肤色检测提取手部图像的时候会出现一些我们不需要的部分,在边缘提取时也会被提取出,那么存放在CvSeq结构中的边缘集合就有好几类(除了手以外还有别的物体的边缘),那么对指尖的检测工作会带来很多干扰,那么我们要去除掉这些没用的边缘点集。

   下图就是带有空洞的

指尖检测测试(一)_第3张图片

那么怎么找到哪一个序列是手的点集呢?

    我们需要的一幅手的图上,手部的点最多,那么我们可以首先判断CvSeq结构中的最多有用元素的个数total,找出total最大的那个序列maxContour,该序列就是手部边缘点集。

    找到手部边缘点集后就可以根据指尖处的线条变化情况进行指尖检测了。当然手指间的凹槽也会被检测到,这需要过滤。

红色部分为检测到区域,还没有过滤凹槽:

指尖检测测试(一)_第4张图片


当然,除了这种方法检测指尖外还有别的方式,比如先将手指细化,然后找端点,这个算法我也在测试,目前效果不怎么样,前期处理不好,检测算法也有些问题。呵呵,反正玩玩嘛。。。


其实这些东西已经用于商业化了,也有人申请了发明专利,这里写出来跟大家一起交流学习。

 
 
 

你可能感兴趣的:(图像处理,VC++/C++,OpenCV学习)