OpenCV - approxPolyDP用于边缘图(不是轮廓) [英] OpenCV - approxPolyDP for edge maps (not contours)

查看:6620
本文介绍了OpenCV - approxPolyDP用于边缘图(不是轮廓)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已成功地在轮廓(cv :: findContours)上应用cv :: approxPolyDP方法,以便用更简单的多边形表示轮廓,并隐式地做一些去噪。



我想对从RGBD相机获得的边缘地图(通常很嘈杂)做同样的事情,但到目前为止没有太多成功,我不能在网上找到相关的例子。我需要这个的原因是,通过边缘地图,还可以使用手指之间的边缘,由手指遮挡创建的边缘或在手掌中创建的边缘。



这个方法适用于除轮廓之外的一般边缘地图吗?



有人可以指出我的例子吗?



附加了一些图片:



轮廓成功的例子:



边缘地图问题:



在错误的方式,但绘制只是像素返回的方法显示可能大面积不表示在最终结果(这不会改变很多根据epsilon参数)。



>



我附加一个深度图像,类似于我在上面描述的实验管道中使用的深度图像。这个深度图像不是通过深度相机获取的,而是通过使用OpenGL读取gpu的深度缓冲区而合成生成的。





仅供参考,这也是深度的边缘地图





(手从深度相机中看到,手掌朝上,手指朝向手掌闭合)

解决方案

您对 approxPolyDP 的问题是由于输入格式 approxPolyDP



说明



approxPolyDP 期望其输入是 Point 的向量。这些点定义将由 approxPolyDP 处理的多边形曲线。曲线可以是打开或关闭的,其可以由标志控制。



列表中的点的顺序很重要。正如一个用手描绘多边形一样,向量中的每个后续点必须是多边形的下一个顶点,顺时针或逆时针。



如果列表点按照光栅顺序存储(按Y和X排序),然后 point [k] point [k + 1] 不一定属于同一曲线。这是问题的原因。



此问题的解释在



不幸的是,这不是OpenCV提供的开箱即用功能,因此您可能必须找到






选项#1的示例代码。



  #include< stdint.h> 
#include< iostream>
#include< vector>
#include< opencv2 / opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
Mat matInput = imread(〜/ Data / mA9EE.png,false);

// ----预处理深度图。 (可选。)----

GaussianBlur(matInput,matInput,cv :: Size(9,9),4.0);

// ----这里,我们使用cv :: threshold代替cv :: Canny,如上所述----

Mat matEdge;

// Canny(matInput,matEdge,0.1,1.0);

threshold(matInput,matEdge,192.0,255.0,THRESH_BINARY_INV);

// ----使用findContours找到连续边缘像素的链----

vector< vector< Point> >轮廓;
findContours(matEdge,contour,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);

// ----下面的代码仅用于可视化结果。 ----

Mat matContour(matEdge.size(),CV_8UC1);

for(size_t k = 0; k {
const vector< Point> contour = contoururs [k];
for(size_t k2 = 0; k2 {
const Point& p = contour [k2];
matContour.at< uint8_t>(p)= 255;
}
}

imwrite(〜/ Data / output.png,matContour);
cout<< 完成! << endl;
return 0;
}


I have successfully applied the method cv::approxPolyDP on contours (cv::findContours), in order to represent a contour with a simpler polygon and implicitly do some denoising.

I would like to do the same thing on an edge map acquired from an RGBD camera (which is in general very noisy), but with not much success up to now and I cannot find relative examples online. The reason I need this, is that by means of an edge map one can also use the edges between fingers, edges created by finger occlusion or edges created in the palm.

Is this method applicable to general edge maps, other than contours?

Could someone pinpoint me to an example?

Some images attached:

Successful example for contours:

Problematic case for edge maps:

Most probably I draw things in the wrong way, but drawing just the pixels returned by the method shows that probably large areas are not represented in the end result (and this doesn't change much according to the epsilon-parameter).

I attach also a depth image, similar to the ones I use in the experimental pipeline descibed above. This depth image was not acquired by a depth camera, but was synthetically generated by reading the depth buffer of the gpu, using OpenGL.

Just for reference, this is also the edge map of the depth image acquired straight from the depth camera (using the raw image, no smoothing etc applied)

(hand as viewd from a depth camera, palm facing upwards, fingers "closing" towards the palm)

解决方案

Your issue with approxPolyDP is due to the formatting of the input into approxPolyDP.

Explanation

approxPolyDP expects its input to be a vector of Points. These points define a polygonal curve that will be processed by approxPolyDP. The curve could be open or closed, which can be controlled by a flag.

The ordering of the points in the list is important. Just as one traces out a polygon by hand, each subsequent point in the vector must be the next vertex of the polygon, clockwise or counter-clockwise.

If the list of points is stored in raster order (sorted by Y and then X), then the point[k] and point[k+1] do not necessarily belong to the same curve. This is the cause of the problem.

This issue is explained with illustrations in OpenCV - How to extract edges form result of Canny Function? . Quote from Mikhail: "Canny doesn't connect pixels into chains or segments."


Illustration of "raster order" that is generated by Canny.


Illustration of "contour order" that is expected by approxPolyDP


What is needed

What you need is a list of "chains of edge pixels". Each chain must contain edge pixels that are adjacent to each other, just like someone tracing out an object's outline by a pencil, without the tip of the pencil leaving the paper.

This is not what is returned from edge detection methods, such as Canny. Further processing is needed to convert an edge map into chains of adjacent (continuous) edge pixels.

Suggested solutions

(1) Use binary threshold instead of edge detection as the input to findContours

This would be applicable if there exists a threshold value that separates the hand from the background, and that this value works for the whole hand (not just part of the hand).

(2) Scan the edge map, and build the list of adjacent pixels by examining the neighbors of each edge pixel.

This is similar to the connected-components algorithm, except that instead of finding a blob (where you only need to know each pixel's membership), you try to find chains of pixels such that you can tell the previous and next edge pixels along the chain.

(3) Use an alternative edge detection algorithm, such as Edge Drawing.

Details can be found at http://ceng.anadolu.edu.tr/cv/EdgeDrawing/

Unfortunately, this is not provided out-of-the-box from OpenCV, so you may have to find an implementation elsewhere.


Sample code for option #1.

#include <stdint.h>
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat matInput = imread("~/Data/mA9EE.png", false);

    // ---- Preprocessing of depth map. (Optional.) ----

    GaussianBlur(matInput, matInput, cv::Size(9, 9), 4.0);

    // ---- Here, we use cv::threshold instead of cv::Canny as explained above ----

    Mat matEdge;

    //Canny(matInput, matEdge, 0.1, 1.0);

    threshold(matInput, matEdge, 192.0, 255.0, THRESH_BINARY_INV);

    // ---- Use findContours to find chains of consecutive edge pixels ----

    vector<vector<Point> > contours;
    findContours(matEdge, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    // ---- Code below is only used for visualizing the result. ----

    Mat matContour(matEdge.size(), CV_8UC1);

    for (size_t k = 0; k < contours.size(); ++k)
    {
        const vector<Point>& contour = contours[k];
        for (size_t k2 = 0; k2 < contour.size(); ++k2)
        {
            const Point& p = contour[k2];
            matContour.at<uint8_t>(p) = 255;
        }
    }

    imwrite("~/Data/output.png", matContour);
    cout << "Done!" << endl;
    return 0;
}

这篇关于OpenCV - approxPolyDP用于边缘图(不是轮廓)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆