这几天做了一个指尖检测的测试程序,效果一般,主要是受环境影响比较大。目前我做的将手从复杂环境中提取出来的测试程序效果不是很好,受光影响较大,虽然我已经把RGB颜色空间转换了,将光强和色调隔离开来,但是还是有比较大的影响,后面会优化。
首先用肤色检测将手提取出来,当然更简单的方法就是直接用阈值二值化,在某些简单背景下还行。下面是用肤色检测提取出的手掌图。
我用cvErode(dst,dst,NULL,2)和cvDilate(dst,dst,NULL,1)进行开闭处理,可以去掉一些小孔,然后将上图进行边缘提取cvCanny(dst,thinImage,50,150,3)。提取了边缘后,将每一类边缘用一个数据结构储存起来。我将这些边缘存放在CvSeq* contour中。
边缘提取后的效果图
简单说一下这个数据结构:
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结构中的最多有用元素的个数total,找出total最大的那个序列maxContour,该序列就是手部边缘点集。
找到手部边缘点集后就可以根据指尖处的线条变化情况进行指尖检测了。当然手指间的凹槽也会被检测到,这需要过滤。
红色部分为检测到区域,还没有过滤凹槽:
当然,除了这种方法检测指尖外还有别的方式,比如先将手指细化,然后找端点,这个算法我也在测试,目前效果不怎么样,前期处理不好,检测算法也有些问题。呵呵,反正玩玩嘛。。。
其实这些东西已经用于商业化了,也有人申请了发明专利,这里写出来跟大家一起交流学习。