OpenCVSharp 小练习 最大内接矩形

本文介绍了一种基于OpenCV的内接矩形算法实现,该算法能够在二值化后的图像中找到最大内接矩形,并将其标记出来。通过遍历连通组件,算法以图像中心为起点,向外扩展寻找矩形边界。

参考:

https://blog.youkuaiyun.com/qq_35054151/article/details/88952728

注意:

这个可能不是最大内接矩形。

输入图像 :

输出图像:

 代码:

        public void Main()
        {
            Mat src = Cv2.ImRead(FilePath.Image.Shapes, ImreadModes.AnyColor);
            Mat gray = new Mat();
            Mat binary = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.RGB2GRAY);
            Cv2.Threshold(gray, binary, 10, 255, ThresholdTypes.Binary);
            ConnectedComponents cc = Cv2.ConnectedComponentsEx(binary);
            foreach (var maxBlob in cc.Blobs.Skip(1))
            {
                Mat m = new Mat(binary, maxBlob.Rect);
                Rect rr = InSquare(m, new Point(m.Width / 2, m.Height / 2));
                Cv2.Rectangle(src, new Rect(maxBlob.Left + rr.Left, maxBlob.Top + rr.Top, rr.Width, rr.Height), Scalar.Red);
            }
            
        }

        /// <summary>
        /// 内接矩形
        /// </summary>
        /// <param name="img"></param>
        /// <param name="center"></param>
        /// <returns></returns>
        Rect InSquare(Mat img, Point center)
        {

            int[] edge = new int[4];
            edge[0] = center.Y - 1;//top
            edge[1] = center.X + 1;//right
            edge[2] = center.Y + 1;//bottom
            edge[3] = center.X - 1;//left
 
            bool[] EXPAND = { true, true, true, true };
            int n = 0;
            while (EXPAND[0] || EXPAND[1] || EXPAND[2] || EXPAND[3])
            {
                int edgeID = n % 4;
                EXPAND[edgeID] = ExpandEdge(img, edge, edgeID, EXPAND);
                n++;

            }


            Point tl = new Point(edge[3], edge[0]);
            Point br = new Point(edge[1], edge[2]);
            return new Rect(tl, new Size(br.X - tl.X, br.Y - tl.Y));
        }

        /// <summary>
        /// 扩展边界函数
        /// </summary>
        /// <param name="img"></param>
        /// <param name="edge">边界数组,存放4条边界值</param>
        /// <param name="edgeID">当前边界号</param>
        /// <returns>确定当前边界是否可以扩展</returns>
        bool ExpandEdge(Mat img, int[] edge, int edgeID, bool[] EXPAND)
        {


            int width = img.Width;
            int height = img.Height;

            switch (edgeID)
            {

                //top
                case 0:
                    if (!EXPAND[0]) return false;
                    if (edge[0] <= 1)
                        return false;
                    for (int i = edge[3] + 1; i < edge[1]; ++i) // left - right
                    {
                        if (img.Get<byte>(edge[0], i) == 0)
                        {
                            Console.WriteLine("top");

                            return false;
                        }
                        else
                            img.Set<byte>(edge[0], i, 100);
                    }
                    edge[0]--;
                    return true;
                //right
                case 1:
                    if (!EXPAND[1]) return false;
                    if (edge[1] >= width)
                        return false;
                    for (int i = edge[0] + 1; i < edge[2]; ++i)   // top - bottom
                    {
                        if (img.Get<byte>(i, edge[1]) == 0)
                        {
                            Console.WriteLine("right");
                            return false;
                        }
                        else
                            img.Set<byte>(i, edge[1], 50);
                    }
                    edge[1]++;
                    return true;

                //botton
                case 2:
                    if (!EXPAND[2]) return false;
                    if (edge[2] >= height)
                        return false;
                    for (int i = edge[3] + 1; i < edge[1]; ++i)  // left - right
                    {
                        if (img.Get<byte>(edge[2], i) == 0)
                        {
                            Console.WriteLine("botton");
                            return false;
                        }
                        else
                            img.Set<byte>(edge[2], i, 100);
                    }
                    edge[2]++;
                    return true;

                //left
                case 3:
                    if (!EXPAND[3]) return false;
                    if (edge[3] < 1)
                        return false;
                    for (int i = edge[0] + 1; i < edge[2]; ++i) // top - bottom
                    {
                        if (img.Get<byte>(i, edge[3]) == 0)
                        {
                            Console.WriteLine("left");
                            return false;
                        }
                        else
                            img.Set<byte>(i, edge[3], 50);
                    }
                    edge[3]--;
                    return true;

                default:
                    return false;

            }

        }

 

计算最大矩形的方法有很多种,其中一种较为简单的方法是使用OpenCVSharp库中的函数进行计算。 以下是一个示例代码,可以计算出一个二值化图像中最大矩形的位置和大小: ```csharp using OpenCvSharp; Mat binaryImage = new Mat(); // 读取二值化图像到binaryImage中 // 计算轮廓 Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(binaryImage, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); // 遍历所有轮廓,计算最大矩形 Rect maxInnerRect = new Rect(); double maxArea = 0; foreach (var contour in contours) { RotatedRect rotRect = Cv2.MinAreaRect(contour); Point2f[] vertices = rotRect.Points(); Point[] points = Array.ConvertAll(vertices, v => new Point((int)v.X, (int)v.Y)); double area = Cv2.ContourArea(points); if (area > maxArea) { maxArea = area; maxInnerRect = Cv2.BoundingRect(points); } } // 输出最大矩形的位置和大小 Console.WriteLine(maxInnerRect.X); Console.WriteLine(maxInnerRect.Y); Console.WriteLine(maxInnerRect.Width); Console.WriteLine(maxInnerRect.Height); ``` 该代码首先读取一个二值化图像,并找到所有轮廓。然后遍历所有轮廓,利用 `Cv2.MinAreaRect` 函数计算每个轮廓的最小外矩形,并将其转换为最大矩形。最后,输出最大矩形的位置和大小。 需要注意的是,如果图像中存在多个对象,则该代码只能计算其中一个对象的最大矩形。如果需要计算所有对象的最大矩形,则需要对代码进行相应的修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易极

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值