首页 > 解决方案 > 使用 EMGU CV 从图像中剪出形状

问题描述

一天中的所有美好时光!

面临以下任务:您需要找到图像中的形状,将它们剪下来并保存为jpg或png。

找到计算出来的形状(附图片),但我如何获得它们的极端坐标?

我用 EMGU CV 找到形状。

我正在从 PictureBox 中取出图像。

// - 就像是想通过Moments找到图形中心到边缘的距离,但不明白它们是如何工作的

Image<Gray, byte> grayImage = inputImage.SmoothMedian(1).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(230), new Gray(255));
 
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
 
Mat hierarchy = new Mat();
 
for (int i = 0; i < contours.Size; i++)
{
    double perimetr = CvInvoke.ArcLength(contours[i], true); 
    
    VectorOfPoint approximation = new VectorOfPoint();
    
    CvInvoke.ApproxPolyDP(contours[i], approximation, 0.04 * perimetr, true); 
 
 
    if (approximation.Size >= 3 && perimetr > 100 && approximation.Size != 5)
    {
        CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2); 
    }
 
                
    Moments moments = CvInvoke.Moments(contours[i]);
 
    int x = (int)(moments.M10 / moments.M00);
    int y = (int)(moments.M01 / moments.M00);
                
    if (perimetr > 100)
    {
        if (approximation.Size == 3)
        {
            CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
            CvInvoke.PutText(inputImage, "Triangle", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
                new MCvScalar(0, 0, 255), 1);
        } 
        if (approximation.Size == 4)
        {
            Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
 
            double aspectRatio = (double)rect.Width / (double)rect.Height;
 
            if (aspectRatio >= 0.95 && aspectRatio <= 1.05)
            {
                CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2); 
                CvInvoke.PutText(inputImage, "Square", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
                    new MCvScalar(0, 0, 255), 1);
            }
            else
            {
                CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
                CvInvoke.PutText(inputImage, "Rectangle", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
                    new MCvScalar(0, 0, 255), 1);
            }
        }
        if (approximation.Size == 5)
        {
            CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2); 
            CvInvoke.PutText(inputImage, "Pentagon", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
                new MCvScalar(0, 0, 255), 1);
        } 
        if (approximation.Size == 6)
        {
            CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
            CvInvoke.PutText(inputImage, "Hexagon", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
                new MCvScalar(0, 0, 255), 1);
        }
        if (approximation.Size > 6)
        {
            var R = (double)perimetr / (3.14 * 2);
            if (R > (Math.Min(inputImage.Width, inputImage.Height) / 3) * 0.1 && R < (Math.Min(inputImage.Width, inputImage.Height) / 2))
            {
                CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2); 
                CvInvoke.PutText(inputImage, "Circle", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
                    new MCvScalar(0, 0, 255), 1);
            }
        } 
    }
}

感谢您的关注。

输入图像

输出图像

标签: c#opencvimage-processingjpegemgucv

解决方案


我找到了我的问题的解决方案。有一种方法可以返回带有点数组的轮廓描述。

Point[] contour = contours[i].ToArray();

推荐阅读