美文网首页
C#:OpenCvSharp图像校正

C#:OpenCvSharp图像校正

作者: 大龙10 | 来源:发表于2023-12-27 21:29 被阅读0次

一、程序

        private void button2_Click(object sender, EventArgs e)
        {
            Mat src = src_img.Clone();

            //转化为灰度图
            Cv2.CvtColor(src, src, ColorConversionCodes.BGR2GRAY);

            InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
            Cv2.MorphologyEx(src, src, MorphTypes.Close, kernel, new OpenCvSharp.Point(-1, -1), 3);    //
            Cv2.ImShow("MorphologyEx", src);

            /*ksize,高斯内核大小,ksize.width和ksize.height必须是正奇数,两者可以不相同,值越大越模糊
                sigmaX,Y轴方向的标准差,值越大越模糊
                sigmaY,X轴方向的标准差,值越大越模糊   */
            Cv2.GaussianBlur(src, src, new OpenCvSharp.Size(11, 11), 2, 2);
            Cv2.ImShow("Gaussian", src);

            Mat canny_img = new Mat();
            Cv2.Canny(src, canny_img, 18, 3, 3, false);

            OpenCvSharp.Point[][] contours;
            HierarchyIndex[] hierarchly;

            /*
             findContours找到轮廓
            第一个参数:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等
            第二个参数: contours
            第三个参数: hierarchy
            第四个参数:轮廓的检索模式
                取值一:CV_RETR_EXTERNAL 只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
                取值二: CV_RETR_LIST  所有的轮廓,包括内围、外围轮检测廓,但是检测到的轮廓不建立
                取值三: CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,
                取值四: CV_RETR_TREE检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层:内层嵌套;

            第五个参数:轮廓的近似方法
                保存物体边界上所有连续的轮廓点到contours向量内
                取值一: CV_CHAIN_APPROX_NONE
                取值二:CV_CHAIN APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入coni
                取值三和四: CV_CHAIN_APPROX TC89 L1,CV CHAIN APPROX TC89 KCOS使用teh-Chinl cha
            第六个参数:Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的
             
             */
            Cv2.FindContours(canny_img, out contours, out hierarchly, RetrievalModes.External,
                ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));
            if (contours.Length == 0) 
            { 
                MessageBox.Show("边缘检测失败");
                return;
                    }

            Random rnd = new Random();
            Scalar color;
            color = new Scalar(0, 255,0 );
            for (int i = 0; i < contours.Length; i++)
            { 
                color = new Scalar(rnd.Next(0, 255), rnd.Next(8, 255), rnd.Next(8, 255));
                Cv2.DrawContours(src, contours, i, color,2, LineTypes.Link4);
            }
            Cv2.ImShow("contours", src);

            //求出面积最大的轮廓
            double max_area = 0.0;
            double currentArea = 0.0;
            OpenCvSharp.Point[] max_contour = null;
            for (int i = 0; i < contours.Length; i++)
            {
                currentArea = Cv2.ContourArea(contours[i]);
                if (currentArea > max_area)
                {
                    max_area = currentArea; 
                    max_contour = contours[i];
                }
            }
            //多边形拟合凸包的四个顶点
            OpenCvSharp.Point[] hull = Cv2.ConvexHull(max_contour);
            double epsilon = 0.02 * Cv2.ArcLength(max_contour, true);
            OpenCvSharp.Point[] approx = Cv2.ApproxPolyDP(hull, epsilon, true);
            if (approx.Length != 4)
            { 
                MessageBox.Show("拟合凸包的四个顶点失败"); 
                return;
                    }

            Scalar scalar2 = new Scalar(8, 255,255);
            Cv2.Line(src, approx[0], approx[1], scalar2, 1, LineTypes.Link4);
            Cv2.Line(src, approx[1], approx[2], scalar2,1, LineTypes.Link4);
            Cv2.Line(src, approx[2], approx[3], scalar2,1, LineTypes.Link4);
            Cv2.Line(src, approx[3], approx[0], scalar2,1, LineTypes.Link4);

            //排序
            Array.Sort(approx, (cs1, cs2) =>
                {
                    if (cs1 != null && cs1 != null)
                    {
                        if (cs1.Y > cs2.Y)
                            return 1;
                        else if (cs1.Y == cs2.Y)
                        {
                            if (cs1.X < cs2.X)
                                return 1;
                            else return -1;
                        }
                        else
                            return -1;
                    }
                    return 0;
                });

            //算法找出的角点
            OpenCvSharp.Point2f[] srcpt = new OpenCvSharp.Point2f[4];
            srcpt[0] = approx[0]; 
            srcpt[1] = approx[1]; 
            srcpt[2] = approx[3]; 
            srcpt[3] = approx[2];

            //最小外接矩形
            RotatedRect rect = Cv2.MinAreaRect(srcpt); 
            Rect box = rect.BoundingRect();
            OpenCvSharp.Point2f[] dstpt = new OpenCvSharp.Point2f[4];

            dstpt[0].X = box.X; dstpt[0].Y = box.Y;
            dstpt[1].X = box.X + box.Width; dstpt[1].Y = box.Y;
            dstpt[2].X = box.X + box.Width; dstpt[2].Y = box.Y + box.Height;
            dstpt[3].X = box.X; dstpt[3].Y = box.Y + box.Height;

            Mat src2 = src_img.Clone(); 
            Mat final = new Mat();
            Mat warpmatrix = Cv2.GetPerspectiveTransform(srcpt,dstpt); //获得变换矩阵
            Cv2.WarpPerspective(src2,final,warpmatrix,src.Size());//投射变换,将结果赋给final

            Bitmap temp = BitmapConverter.ToBitmap(final);
            pictureBox2.Image = temp;
            DrawLine(srcpt,dstpt);

        }


    void DrawLine(OpenCvSharp.Point2f[] srcpt, OpenCvSharp.Point2f[] dstpt)
    { 
        Bitmap bmp = new Bitmap(image); 
        Graphics g = Graphics.FromImage(bmp);
         Pen pen = new Pen(Color.Red, 3); 
        Pen pen2 = new Pen(Color.Blue, 3);
        g.DrawLine(pen, srcpt[0].X,srcpt[0].Y,srcpt[1].X,srcpt[1].Y);
        g.DrawLine(pen, srcpt[1].X,srcpt[1].Y, srcpt[2].X,srcpt[2].Y);
        g.DrawLine(pen, srcpt[2].X,srcpt[2].Y,srcpt[3].X,srcpt[3].Y);
        g.DrawLine(pen, srcpt[3].X,srcpt[3].Y,srcpt[0].X, srcpt[0].Y);
        g.DrawLine(pen2, dstpt[0].X, dstpt[0].Y, dstpt[1].X,dstpt[1].Y);
        g.DrawLine(pen2,dstpt[1].X, dstpt[1].Y, dstpt[2].X, dstpt[2].Y);
        g.DrawLine(pen2,dstpt[2].X,dstpt[2].Y, dstpt[3].X, dstpt[3].Y);
        g.DrawLine(pen2, dstpt[3].X, dstpt[3].Y, dstpt[0].X, dstpt[0].Y);
        pictureBox1.Image = bmp;
         }
    }

二、运行结果

结果成镜像了

三、资料

[lw112190]的博客:
https://blog.51cto.com/lw112190/6598260?articleABtest=0

相关文章

网友评论

      本文标题:C#:OpenCvSharp图像校正

      本文链接:https://www.haomeiwen.com/subject/gefrndtx.html