我正在尝试识别Android的 OpenCV 中的手牌位置。我想将检测到的手形缩小为一组简单线(=点序列)。我正在使用细化算法来查找检测到的手形的骨架线。这是一个示例性的结果(左手的图像):
在这张图片中,我想得到骨架线的坐标,即“矢量化”图像。我试过HoughLinesP
,但这只会产生很多非常短的行,这不是我想要的。
我的第二种方法使用 findContours
:
// Get contours
Mat skeletonFrame; //image above
ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(skeletonFrame, contours, new Mat(), Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);
// Find longest contour
double maxLen = 0;
MatOfPoint max = null;
for (MatOfPoint c : contours) {
double len = Imgproc.arcLength(Util.convert(c), true); //Util.convert converts between MatOfPoint and MatOfPoint2f
if (len > maxLen) {
maxLen = len;
max = c;
}
}
// Simplify detected contour
MatOfPoint2f result = new MatOfPoint2f();
Imgproc.approxPolyDP(Util.convert(max), result, 5.0, false);
这基本上有效;但是,findContours
返回的轮廓始终是关闭的,这意味着所有骨架线都被表示为。
示例性结果:(灰线=检测到的轮廓,而不是第一张图像的骨架线)
所以我的问题是:如何避免这些封闭的轮廓,只能获得“单笔画”点序列的集合?
我是否遗漏了OpenCV文档中的内容?我不一定要求代码,我可以自己实现的算法提示也很棒。谢谢!
答案 0 :(得分:2)
我会从真正的手骨架开始作为运动学
解决反向运动学
例如CCD匹配手指端点而不是重叠图像。这样你就可以获得解剖学上正确的答案
为简化起见,您可以像这样使用运动学
由于手指长度不同,您应该以不同的方式处理男/女/儿童(不同的手指长度)或使用某种校准或测量。正如你所看到的那样,我跳过了手/手腕基部骨骼并不重要。可以找到红色轮廓,其中周长较小curve radius。
如何解决当前实施中的问题?
第一种细化方法更好,所以当你获得大量的线条时,在每条线的计算角度之后将它们连接到折线。如果两个连接的线具有相似的角度(达到阈值),那么加入它们应该做你想要的但是不要指望你会得到类似于人骨的线,特别是对于曲线,结果会有很大不同。在线条和形状的计数。
为了获得更好的效果,您需要使用几何细化
但是我不知道是否存在于 OpenCV (我不使用这个lib)的想法是找到周边线并将其向内垂直移动一些类似于{{的小步骤3}}。如果获得所需的宽度,则停止
当移动周边导致太薄的形状停在那里并从前一步骤(黄线)连接到变薄点。这都是在矢量(折线)上完成的,不在图像像素上!宽度可以计算为与任何附近线的最小垂直距离。