上次我们成功训练了手掌识别器 http://www.cnblogs.com/take-fetter/p/8438747.html, 可以成功得到识别的结果如图
接下来需要使用 opencv 来获取手掌, 去除背景部分, 这里就需要用到掩膜 (mask)ROI(region of interest) 等相关知识, 具体的概念还是不讲了, 网上很多
首先从图中根据上次的程序画框部分提取手掌 (当然自己截图再保存也可以 -.-) 如下
接下来讲解一下提取手掌的方法
将图片 copy, 并将图片转换为 ycrcb 模式, 根据 ycrcb 中的肤色获取和手掌颜色相近的部分, 生成黑白图片
使用黑白图片获得最大的轮廓并生成轮廓图片并得到一个近似的椭圆
根据椭圆角度进行旋转 (原图片和黑白图片及轮廓图片同时旋转) 以尽可能的将手掌放为竖直
根据原图片和黑白图片, 利用黑白图片作为掩膜, 得到的原图片如下:
提取手掌中心:
算法思想: 根据黑白图片, 基于距离变换得到手掌中心, 并根据最大半径画出手掌的内切圆如图
代码如下
- distance = cv2.distanceTransform(black_and_white, cv2.DIST_L2, 5, cv2.CV_32F)
- # Calculates the distance to the closest zero pixel for each pixel of the source image.
- maxdist = 0
- # rows,cols = img.shape
- for i in range(distance.shape[0]):
- for j in range(distance.shape[1]):
- dist = distance[i][j]
- if maxdist < dist:
- x = j
- y = i
- maxdist = dist
- cv2.circle(original, (x, y), maxdist, (255, 100, 255), 1, 8, 0)
提取掌纹
现在我们已知了圆的半径和圆心坐标, 因此可以根据 ROI 提取出内切正方形(虽然内切正方形会损失很多的信息, 但是目前我还没有想到其他的更好的办法), 作出正方形如下
作正方形并提取的代码如下
- final_img = original.copy()
- #cv2.circle() this line
- half_slide = maxdist * math.cos(math.pi / 4)
- (left, right, top, bottom) = ((x - half_slide), (x + half_slide), (y - half_slide), (y + half_slide))
- p1 = (int(left), int(top))
- p2 = (int(right), int(bottom))
- cv2.rectangle(original, p1, p2, (77, 255, 9), 1, 1)
- final_img = final_img[int(top):int(bottom),int(left):int(right)]
运行截图
可以看到出现了灰色部分, 按理说是不会存在的, 使用 cv2.imwrite 发现没有出现任何问题, 如图
感觉是 cv2.imshow 对于输出图片的像素大小有一定限制, 进行了自动填充或者是默认有灰色作为背景色且比在这里我们提取出的图片要大
代码地址: https://github.com/takefetter/Get_PalmPrint/blob/master/process_palm.py
感谢:
1.https://github.com/dev-td7/Automatic-Hand-Detection-using-Wrist-localisation 这位老哥的 repo, 基于肤色的提取和形成近似椭圆给我的启发很大(虽然后半部分完全没有用.....)
2.http://answers.opencv.org/question/180668/how-to-find-the-center-of-one-palm-in-the-picture/ 虽然基于距离变化参考至这里的回答, 不过也算是完成了提问者的需求
来源: https://www.cnblogs.com/take-fetter/p/8453589.html