c# - emgucv:C#中的Pan Card不当偏斜检测

标签 c# opencv ocr emgucv pan

我正在使用pangu的三个图像来使用emgucv和C#测试图像的倾斜度。
位于顶部的第一张图像检测到180度正常工作。
中间检测到的90度第二张图像应检测为180度。
检测到的第三个图像180度应检测为90度。
Detected 180 degree working properly
Detected 90 should detected as 180
Detected 180 should detected as 90
我想在这里分享的一个观察结果是,当我使用画笔从潘卡的上下两边裁剪掉不需要的图像部分时,使用下面提到的代码可以给我预期的结果。
现在,我想了解如何使用编程来删除不需要的部分。
我玩过轮廓和roi,但我不知道该如何拟合。我无法理解emgucv本身是选择轮廓还是必须做一些事情。
请提出任何合适的代码示例。
请检查以下代码以进行 Angular 检测,并请帮助我。提前致谢。

imgInput = new Image<Bgr, byte>(impath);
          Image<Gray, Byte> img2 = imgInput.Convert<Gray, Byte>();
          Bitmap imgs;
          Image<Gray, byte> imgout = imgInput.Convert<Gray, byte>().Not().ThresholdBinary(new Gray(50), new Gray(125));
          VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
          Emgu.CV.Mat hier = new Emgu.CV.Mat();
          var blurredImage = imgInput.SmoothGaussian(5, 5, 0 , 0);
          CvInvoke.AdaptiveThreshold(imgout, imgout, 255, Emgu.CV.CvEnum.AdaptiveThresholdType.GaussianC, Emgu.CV.CvEnum.ThresholdType.Binary, 5, 45);

          CvInvoke.FindContours(imgout, contours, hier, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
          if (contours.Size >= 1)
          {
              for (int i = 0; i <= contours.Size; i++)
              {

                  Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
                  RotatedRect box = CvInvoke.MinAreaRect(contours[i]);
                  PointF[] Vertices = box.GetVertices();
                  PointF point = box.Center;
                  PointF edge1 = new PointF(Vertices[1].X - Vertices[0].X, Vertices[1].Y - Vertices[0].Y);
                  PointF edge2 = new PointF(Vertices[2].X - Vertices[1].X, Vertices[2].Y - Vertices[1].Y);
                  double r = edge1.X + edge1.Y;
                  double edge1Magnitude = Math.Sqrt(Math.Pow(edge1.X, 2) + Math.Pow(edge1.Y, 2));
                  double edge2Magnitude = Math.Sqrt(Math.Pow(edge2.X, 2) + Math.Pow(edge2.Y, 2));
                  PointF primaryEdge = edge1Magnitude > edge2Magnitude ? edge1 : edge2;
                  double primaryMagnitude = edge1Magnitude > edge2Magnitude ? edge1Magnitude : edge2Magnitude;
                  PointF reference = new PointF(1, 0);
                  double refMagnitude = 1;
                  double thetaRads = Math.Acos(((primaryEdge.X * reference.X) + (primaryEdge.Y * reference.Y)) / (primaryMagnitude * refMagnitude));
                  double thetaDeg = thetaRads * 180 / Math.PI;
                  imgInput = imgInput.Rotate(thetaDeg, new Bgr());
                  imgout = imgout.Rotate(box.Angle, new Gray());
                  Bitmap bmp = imgout.Bitmap;
                  break;
              }

          }

最佳答案

问题
让我们从解决方案之前的问题开始:
您的密码
当您提交代码时,寻求帮助,至少需要付出一些努力来“清理”它。帮助人们帮助您!这里有太多的代码行什么都不做。您声明从未使用过的变量。添加一些注释,使人们知道您认为代码应该执行的操作。

Bitmap imgs;
var blurredImage = imgInput.SmoothGaussian(5, 5, 0, 0);
Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
PointF point = box.Center;
double r = edge1.X + edge1.Y;
// Etc
自适应阈值
以下代码行产生以下图像:
 CvInvoke.AdaptiveThreshold(imgout, imgout, 255, Emgu.CV.CvEnum.AdaptiveThresholdType.GaussianC, Emgu.CV.CvEnum.ThresholdType.Binary, 5, 45);
图片1
Image1
图片2
Image2
图片3
Image3
显然,这不是您要的目标,因为主要轮廓(卡片边缘)已完全丢失。作为提示,您始终可以使用以下代码在运行时显示图像,以帮助您进行调试。
CvInvoke.NamedWindow("Output");
CvInvoke.Imshow("Output", imgout);
CvInvoke.WaitKey();
tu
由于您的示例图像中的卡片主要是与背景(在HSV意义上)相似的值。在这种情况下,我认为简单的灰度阈值化不是正确的方法。我的目的是:
算法
  • 使用Canny Edge Detection提取图像中的边缘。
    EdgesImage
  • 扩展边缘,以便合并卡片内容。
    DilatedImage
  • 使用轮廓检测​​来筛选边界最大的组合边缘。
    PrimaryContour
  • 使此主要轮廓与旋转的矩形匹配,以提取角点。
  • 使用角点来定义要使用WarpAffine应用的转换矩阵。
    MetaImage
  • 变形并裁剪图像。
    OutputImage

  • 编码
    您可能希望尝试使用Canny Detection and Dilation参数。
    // Working Images
    Image<Bgr, byte> imgInput = new Image<Bgr, byte>("Test1.jpg");
    Image<Gray, byte> imgEdges = new Image<Gray, byte>(imgInput.Size);
    Image<Gray, byte> imgDilatedEdges = new Image<Gray, byte>(imgInput.Size);
    Image<Bgr, byte> imgOutput;
    
    // 1. Edge Detection
    CvInvoke.Canny(imgInput, imgEdges, 25, 80);
    
    // 2. Dilation
    CvInvoke.Dilate(
        imgEdges,
        imgDilatedEdges,
        CvInvoke.GetStructuringElement(
            ElementShape.Rectangle,
            new Size(3, 3),
            new Point(-1, -1)),
        new Point(-1, -1),
        5,
        BorderType.Default,
        new MCvScalar(0));
    
    // 3. Contours Detection
    VectorOfVectorOfPoint inputContours = new VectorOfVectorOfPoint();
    Mat hierarchy = new Mat();
    CvInvoke.FindContours(
        imgDilatedEdges,
        inputContours,
        hierarchy,
        RetrType.External,
        ChainApproxMethod.ChainApproxSimple);
    VectorOfPoint primaryContour = (from contour in inputContours.ToList()
                                    orderby contour.GetArea() descending
                                    select contour).FirstOrDefault();
    
    // 4. Corner Point Extraction
    RotatedRect bounding = CvInvoke.MinAreaRect(primaryContour);
    PointF topLeft = (from point in bounding.GetVertices()
                      orderby Math.Sqrt(Math.Pow(point.X, 2) + Math.Pow(point.Y, 2))
                      select point).FirstOrDefault();
    PointF topRight = (from point in bounding.GetVertices()
                      orderby Math.Sqrt(Math.Pow(imgInput.Width - point.X, 2) + Math.Pow(point.Y, 2))
                      select point).FirstOrDefault();
    PointF botLeft = (from point in bounding.GetVertices()
                      orderby Math.Sqrt(Math.Pow(point.X, 2) + Math.Pow(imgInput.Height - point.Y, 2))
                      select point).FirstOrDefault();
    PointF botRight = (from point in bounding.GetVertices()
                       orderby Math.Sqrt(Math.Pow(imgInput.Width - point.X, 2) + Math.Pow(imgInput.Height - point.Y, 2))
                       select point).FirstOrDefault();
    double boundingWidth = Math.Sqrt(Math.Pow(topRight.X - topLeft.X, 2) + Math.Pow(topRight.Y - topLeft.Y, 2));
    double boundingHeight = Math.Sqrt(Math.Pow(botLeft.X - topLeft.X, 2) + Math.Pow(botLeft.Y - topLeft.Y, 2));
    bool isLandscape = boundingWidth > boundingHeight;
    
    // 5. Define warp crieria as triangles              
    PointF[] srcTriangle = new PointF[3];
    PointF[] dstTriangle = new PointF[3];
    Rectangle ROI;
    if (isLandscape)
    {
        srcTriangle[0] = botLeft;
        srcTriangle[1] = topLeft;
        srcTriangle[2] = topRight;
        dstTriangle[0] = new PointF(0, (float)boundingHeight);
        dstTriangle[1] = new PointF(0, 0);
        dstTriangle[2] = new PointF((float)boundingWidth, 0);
        ROI = new Rectangle(0, 0, (int)boundingWidth, (int)boundingHeight);
    }
    else
    {
        srcTriangle[0] = topLeft;
        srcTriangle[1] = topRight;
        srcTriangle[2] = botRight;
        dstTriangle[0] = new PointF(0, (float)boundingWidth);
        dstTriangle[1] = new PointF(0, 0);
        dstTriangle[2] = new PointF((float)boundingHeight, 0);
        ROI = new Rectangle(0, 0, (int)boundingHeight, (int)boundingWidth);
    }
    Mat warpMat = new Mat(2, 3, DepthType.Cv32F, 1);
    warpMat = CvInvoke.GetAffineTransform(srcTriangle, dstTriangle);
    
    // 6. Apply the warp and crop
    CvInvoke.WarpAffine(imgInput, imgInput, warpMat, imgInput.Size);
    imgOutput = imgInput.Copy(ROI);
    imgOutput.Save("Output1.bmp");
    
    使用了两种扩展方法:
    static List<VectorOfPoint> ToList(this VectorOfVectorOfPoint vectorOfVectorOfPoint)
    {
        List<VectorOfPoint> result = new List<VectorOfPoint>();
        for (int contour = 0; contour < vectorOfVectorOfPoint.Size; contour++)
        {
            result.Add(vectorOfVectorOfPoint[contour]);
        }
        return result;
    }
    
    static double GetArea(this VectorOfPoint contour)
    {
        RotatedRect bounding = CvInvoke.MinAreaRect(contour);
        return bounding.Size.Width * bounding.Size.Height;
    }
    
    产出
    OutputImage1
    OutputImage2
    OutputImage3
    元示例
    MetaImage

    关于c# - emgucv:C#中的Pan Card不当偏斜检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62550517/

    相关文章:

    c# - C# 控制台应用程序中的 SQL 更新错误

    c# - NUnit 中的静态或非静态测试夹具?

    python - 将纬度、经度和高度转换为平面 3D 空间中的点

    c# - Unity CanvasRenderer 需要具有 16 位索引的网格来绘制图表

    c++ - goodFeaturesToTrack OpenCV 2.4 与 Opencv1 相比极慢

    opencv - 图像特征检测

    iphone - 如何从 iPhone 中的图像中读取文本

    python - 如何绘制包含文本的图像的垂直直方图 - python

    windows - 如何从屏幕上获取文本

    c# - ServiceStack V4 API 文档缺少响应类型(在列表中)