Emgu CV 3 findContours and hierarchy parameter of type Vec4i equivalent?

家住魔仙堡 提交于 2019-11-27 16:50:55

问题


I'm attempting to translate the following OpenCV C++ code into Emgu CV 3:

std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> v4iHierarchy;

cv::findContours(imgThreshCopy, contours, v4iHierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

I can find some Emgu CV 3 examples that use null for the 3rd parameter to findContours, for example doing it that way here would be a Visual Basic translation:

Dim contours As New VectorOfVectorOfPoint()

CvInvoke.FindContours(imgThreshCopy, contours, Nothing, RetrType.Tree, ChainApproxMethod.ChainApproxSimple)

Which works if the hierarchy parameter is not needed, but what if it is? I can't seem to figure the Emgu CV 3 syntax equivalent for the C++ line

std::vector<cv::Vec4i> v4iHierarchy;

Anybody else gotten this to work? Any help would be appreciated.


回答1:


Pass a default-constructed Mat to get the hierarchy.

var VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
var Mat hierarchy = new Mat();
CvInvoke.FindContours(
    image,
    contours,
    hierarchy,
    RetrType.Ccomp,
    ChainApproxMethod.ChainApproxSimple
    );

Console.WriteLine("contours.Size: " + contours.Size);
Console.WriteLine("hierarchy.Rows: " + hierarchy.Rows);
Console.WriteLine("hierarchy.Cols: " + hierarchy.Cols);
Console.WriteLine("hierarchy.Depth: " + hierarchy.Depth);
Console.WriteLine("hierarchy.NumberOfChannels: " + hierarchy.NumberOfChannels);

// Example Output:
// contours.Size: 4391
// hierarchy.Rows: 1
// hierarchy.Cols: 4391
// hierarchy.Depth: Cv32S
// hierarchy.NumberOfChannels: 4

You can access the hierarchy data using the Mat DataPointer:

    /// <summary>
    /// Get a neighbor index in the heirarchy tree.
    /// </summary>
    /// <returns>
    /// A neighbor index or -1 if the given neighbor does not exist.
    /// </returns>
    public int Get(HierarchyIndex component, int index)
    {
        if (Hierarchy.Depth != Emgu.CV.CvEnum.DepthType.Cv32S)
        {
            throw new ArgumentOutOfRangeException("ContourData must have Cv32S hierarchy element type.");
        }
        if (Hierarchy.Rows != 1)
        {
            throw new ArgumentOutOfRangeException("ContourData must have one hierarchy hierarchy row.");
        }
        if (Hierarchy.NumberOfChannels != 4)
        {
            throw new ArgumentOutOfRangeException("ContourData must have four hierarchy channels.");
        }
        if (Hierarchy.Dims != 2)
        {
            throw new ArgumentOutOfRangeException("ContourData must have two dimensional hierarchy.");
        }
        long elementStride = Hierarchy.ElementSize / sizeof(Int32);
        var offset = (long)component + index * elementStride;
        if (0 <= offset && offset < Hierarchy.Total.ToInt64() * elementStride)
        {
            unsafe
            {
                return *((Int32*)Hierarchy.DataPointer.ToPointer() + offset);
            }
        }
        else
        {
            return -1;
        }
    }

https://gist.github.com/joshuanapoli/8c3f282cece8340a1dd43aa5e80d170b




回答2:


EmguCV started using VectorOfVectorPoint for FindContours, but didn't really update their code to work correctly with it. See below for a working example:

    /// <summary>
    /// Find contours using the specific memory storage
    /// </summary>
    /// <param name="method">The type of approximation method</param>
    /// <param name="type">The retrieval type</param>
    /// <param name="stor">The storage used by the sequences</param>
    /// <returns>
    /// Contour if there is any;
    /// null if no contour is found
    /// </returns>
    public static VectorOfVectorOfPoint FindContours(this Image<Gray, byte> image, ChainApproxMethod method = ChainApproxMethod.ChainApproxSimple,
        Emgu.CV.CvEnum.RetrType type = RetrType.List) {
        //Check that all parameters are valid.
        VectorOfVectorOfPoint result = new VectorOfVectorOfPoint();

        if (method == Emgu.CV.CvEnum.ChainApproxMethod.ChainCode) {
            throw new ColsaNotImplementedException("Chain Code not implemented, sorry try again later");
        }

        CvInvoke.FindContours(image, result, null, type, method);
        return result;
    }

This returns a VectorOfVectorPoint, which implements IInputOutputArray, IOutputArray, IInputArrayOfArrays, and IInputArray. I'm not sure what you need to do with the contours, but here is an example of how to get the bounding boxes for each one. We do some other things, so let me know what you need and I can help you.

        VectorOfVectorOfPoint contours = canvass2.FindContours(ChainApproxMethod.ChainApproxSimple, RetrType.Tree);
        int contCount = contours.Size;
        for (int i = 0; i < contCount; i++) {
            using (VectorOfPoint contour = contours[i]) {
                segmentRectangles.Add(CvInvoke.BoundingRectangle(contour));
                if (debug) {
                    finalCopy.Draw(CvInvoke.BoundingRectangle(contour), new Rgb(255, 0, 0), 5);
                }
            }
        }



回答3:


You can simply create a

Matrix

then copy you Mat object data into that Matrix. See Example below:

  Mat hierarchy = new Mat();
  CvInvoke.FindContours(imgThreshCopy, contours, hierarchy , RetrType.Tree,ChainApproxMethod.ChainApproxSimple);

  Matrix<int> matrix = new Matrix<int>(hierarchy.Rows, hierarchy.Cols,hierarchy.NumberOfChannels);
  hierarchy.CopyTo(matrix);

Data can be accessed in

matrix.Data

Good Luck. H



来源:https://stackoverflow.com/questions/34120260/emgu-cv-3-findcontours-and-hierarchy-parameter-of-type-vec4i-equivalent

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!