使用Opencvsharp进行图像旋转矫正截取兴趣区域

这篇文章目的是使用opencvsharp里面的方法对一副比较有明显轮廓的图像进行抠图旋转;

  • 接下来我们会对一副人名币进行旋转矫正,最后得到我们想要获取的特征图像:在这里插入图片描述
    先使用二值化对图像进行处理,然后在寻找轮廓,因为这张图比较简单,所以我们寻找起来也比较方便,二值化的阈值设置为50即可完美扣下图形;
Mat src = new Mat(@"D:\BaiduNetdiskDownload\人名币.png");
//Cv2.ImShow("src", src);
Mat gray = new Mat();
Mat binary=new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
Cv2.Threshold(gray, binary, 50, 255, ThresholdTypes.Binary);//转换为二值图像
//Cv2.ImShow("bin", binary);
//然后寻找轮廓,只需要寻找外围轮廓即可
Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(binary, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);

得到轮廓之后,我们可以使用ApproxPolyDP方法获得凸包(可以省略),再使用MinAreaRect方法获得最小外接矩形,这个时候我们得到的其实就是一个围着这张人民币的一个带角度的矩形,当然可能会有一些噪音信息,我们接下来有办法过滤

RotatedRect[] rotateRect = new RotatedRect[contours.Length];
Point[][] contours_poly = new Point[contours.Length][];
for (int i = 0; i < contours.Length; i++)
	{
		contours_poly[i] = Cv2.ApproxPolyDP(contours[i], 30, true);//返回凸包,单线长大于30过滤
		rotateRect[i] = Cv2.MinAreaRect(contours_poly[i]);//最小外接矩形集合
	}

我们可以在rotateRect[i].Angle中找到每个被检测出来矩形的信息,根据这些信息进行过滤即可

for (int i = 0; i < rotateRect.Length; i++)
{
				float angle = rotateRect[i].Angle;//矩形角度
                pot = rotateRect[i].Points();//矩形的4个角
                double line1 = Math.Sqrt((pot[0].X - pot[1].X) * (pot[0].X - pot[1].X) + (pot[0].Y - pot[1].Y) * (pot[0].Y - pot[1].Y));
                double line2= Math.Sqrt((pot[0].X - pot[3].X) * (pot[0].X - pot[3].X) + (pot[0].Y - pot[3].Y) * (pot[0].Y - pot[3].Y));
                if (line1 * line2 < 1000)//过滤,太小的矩形直接pass
                {
                    continue;
                }
                if (line1>line2)//依据实际情况进行判断
                {
                    angle += 90;
                }
}

接下来通过WarpAffine函数旋转,将得到的图扣下来放正即可,旋转角度已经在上面代码通过 rotateRect[i].Angle得到

				Mat Roi = new Mat(src.Size(), MatType.CV_8UC3);
                Roi.SetTo(0);//全黑
                Cv2.DrawContours(binary, contours,-1, Scalar.White, -1);//在二值图像中圈出轮廓区域并染白
                Cv2.ImShow("bin", binary);
                //这里可以对binary做一些开操作过滤噪声,这里就不演示了
                src.CopyTo(Roi, binary);//将原图通过mask抠图到Roi
                Cv2.ImShow("Roi", Roi);
                Mat afterRotato = new Mat(src.Size(), MatType.CV_8UC3);
                afterRotato.SetTo(0);
                Point2f center = rotateRect[i].Center;
                Mat M = Cv2.GetRotationMatrix2D(center, angle, 1);//计算变换矩阵
                Cv2.WarpAffine(Roi, afterRotato, M, Roi.Size(), InterpolationFlags.Linear, BorderTypes.Constant);//得到变换后的图像,滤除其他信息
                Cv2.ImShow("旋转后", afterRotato);

在这里插入图片描述
在这里插入图片描述
这里因为binary没做开操作导致有些白线,但是不影响我们接下来的操作,接下来再重新寻找旋转后的轮廓和抠图就能得到我们想要的结果了
在这里插入图片描述
下面贴附我调试过程的原码:

			Mat src = new Mat(@"D:\BaiduNetdiskDownload\人名币.png");
            Cv2.ImShow("src", src);
            #region
            //Mat rotateImage = new Mat(src.Rows, src.Cols, MatType.CV_8UC3);
            //rotateImage.SetTo(0);
            //Mat M= Cv2.GetRotationMatrix2D(new Point2f(300, 300), 30, 0.5);
            //Cv2.WarpAffine(src, rotateImage, M, src.Size(), InterpolationFlags.WarpInverseMap);//flags: 插值算法标识符,有默认值INTER_LINEAR
            //Cv2.ImShow("11", rotateImage);
            //Cv2.WaitKey();
            #endregion
            Mat gray = new Mat();
            Mat binary=new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
            Cv2.Threshold(gray, binary, 50, 255, ThresholdTypes.Binary);//转换为二值图像
            Cv2.ImShow("bin", binary);
            //Cv2.WaitKey();
            //建立轮廓接受数组
            Point[][] contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(binary, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
            //最小外接矩形接收数组
            RotatedRect[] rotateRect = new RotatedRect[contours.Length];
            Point[][] contours_poly = new Point[contours.Length][];
            for (int i = 0; i < contours.Length; i++)
            {
                contours_poly[i] = Cv2.ApproxPolyDP(contours[i], 30, true);//返回凸包,单线长大于30过滤
                
                    rotateRect[i] = Cv2.MinAreaRect(contours_poly[i]);//最小外接矩形集合
            //}
            Console.WriteLine(rotateRect.Length);
            Point2f[] pot = new Point2f[4];//新建点集合接收点集合

                //for (int i = 0; i < rotateRect.Length; i++)
                //{
                float angle = rotateRect[i].Angle;//矩形角度
                pot = rotateRect[i].Points();//矩形的4个角
                double line1 = Math.Sqrt((pot[0].X - pot[1].X) * (pot[0].X - pot[1].X) + (pot[0].Y - pot[1].Y) * (pot[0].Y - pot[1].Y));
                double line2= Math.Sqrt((pot[0].X - pot[3].X) * (pot[0].X - pot[3].X) + (pot[0].Y - pot[3].Y) * (pot[0].Y - pot[3].Y));
                if (line1 * line2 < 1000)//过滤,太小的矩形直接pass
                {
                    continue;
                }
                if (line1>line2)//依据实际情况进行判断
                {
                    angle += 90;
                }
                
                Console.WriteLine(line1 );
                Console.WriteLine( line2);
                Mat Roi = new Mat(src.Size(), MatType.CV_8UC3);
                Roi.SetTo(0);//全黑
                Cv2.DrawContours(binary, contours,-1, Scalar.White, -1);//在二值图像中圈出轮廓区域并染白
                Cv2.ImShow("bin", binary);
                src.CopyTo(Roi, binary);//将原图通过mask抠图到Roi
                Cv2.ImShow("Roi", Roi);
                Mat afterRotato = new Mat(src.Size(), MatType.CV_8UC3);
                afterRotato.SetTo(0);
                Point2f center = rotateRect[i].Center;
                Mat M = Cv2.GetRotationMatrix2D(center, angle, 1);//计算变换矩阵
                Cv2.WarpAffine(Roi, afterRotato, M, Roi.Size(), InterpolationFlags.Linear, BorderTypes.Constant);//得到变换后的图像,滤除其他信息
                Cv2.ImShow("旋转后", afterRotato);
                Mat bin2 = new Mat();
                Cv2.ImShow("after", afterRotato);
                Cv2.CvtColor(afterRotato, bin2, ColorConversionCodes.BGR2GRAY);
                Cv2.Threshold(bin2, bin2, 20, 255, ThresholdTypes.Binary);
                Point[][] con;
                HierarchyIndex[] temp;//接收矫正后的轮廓信息
                Cv2.FindContours(bin2, out con,out temp, RetrievalModes.External, ContourApproximationModes.ApproxNone);
                for (int j = 0; j < con.Length; j++)
                {
                    Rect rect = Cv2.BoundingRect(con[j]);//直接使用矫正矩形,因为矫正后不需要再旋转
                    if (rect.Height*rect.Width<8000)//过滤干扰信息
                    {
                        continue;
                    }
                    Mat dstImg =new Mat(afterRotato,rect);
                    //string name = "dst" + i;//主要看调试的时候有几个结果
                    Cv2.ImShow("dst", dstImg);
                }
            }
            Cv2.WaitKey();
            Console.ReadLine();
  • 17
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: OpenCVSharp是一款开源的计算机视觉库,它提供了各种图像处理算法和工具,可以实现图像矫正的功能。图像矫正是指将图像变形成另一种形状或方向,以便更好地展示或处理。 在OpenCVSharp中,实现图像矫正的方法有很多种,比如基于图像的角点特征、基于相机的内部参数和误差、基于灰度图像的直线拟合等。这些方法都可以根据不同的场景和需求,选择最适合的方法来实现图像矫正。 例如,如果需要将一组拍摄于不同角度的图像矫正成同一角度和比例,可以先使用基于角点特征的方法来检测每幅图像的四个角点,然后使用仿射变换或透视变换来求得变换矩阵,最后应用该矩阵到每幅图像上实现矫正。 总之,在OpenCVSharp中实现图像矫正的方法是十分灵活和丰富的,需要根据不同场景和需求选择不同的方法,才能得到最优的矫正效果。 ### 回答2: OpenCVSharp是一款基于C#的OpenCV图像处理库,可以实现很多常见的图像处理和计算机视觉任务。在OpenCVSharp中,图像矫正是一项常见的任务,它可以将图像对齐到某个特定的角度,使得图像更加清晰、可读性更高,减少图像畸变。 图像矫正可以通过旋转和平移来实现。在OpenCVSharp中,可以使用函数cv2.warpAffine()来实现这个功能。该函数需要输入源图像、矩阵M和输出图像的大小,其中矩阵M可以使用cv2.getRotationMatrix2D()函数获得,该函数可以指定旋转角度和缩放比例。 此外,如果图像存在扭曲或透视变形,可以使用cv2.getPerspectiveTransform()函数来获得透视转换矩阵,并将其传递给cv2.warpPerspective()函数来实现透视校正。 总之,OpenCVSharp提供了许多方便的功能来进行图像处理和计算机视觉任务,包括图像矫正。开发者可以根据实际需求选择合适的函数和参数来进行操作,以获得最佳效果。 ### 回答3: 在使用OpenCVSharp进行图像矫正之前,需要明确矫正的对象是哪一部分图像。通常情况下,矫正的对象是图像中的文字或者图形,通过对其进行旋转或者倾斜校正来使其更加垂直或者水平。 首先,需要确定用于矫正的参考线。这可以是一条已知方向的线条(比如水平或者竖直方向的线条),或者通过计算来得到参考线(比如基于文本行的朝向来确定参考线)。然后,根据参考线的方向来旋转或者倾斜整个图像,使矫正后的对象与参考线对齐。 在OpenCVSharp中,可以使用getRotationMatrix2D函数来获得旋转矩阵,并使用warpAffine函数来执行旋转操作。如果需要进行倾斜矫正,可以使用getAffineTransform函数获得仿射变换矩阵,并使用warpAffine函数执行倾斜变换。 需要注意的是,在进行图像矫正之前,需要对图像进行预处理,例如去噪、二值化、降噪去毛刺等等,以提高矫正的效果。同时,由于图像矫正可能会导致图像的内容被裁剪或者留空,因此需要根据具体情况设置合适的参数,使得矫正后的图像不会损失重要信息。 总的来说,图像矫正图像处理中非常常见的一个操作,使用OpenCVSharp可以方便地实现矫正的功能,同时需要根据具体情况选择适当的处理方法和参数,以达到最佳的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值