c#中WinForm用OpencvSharp实现ROI区域提取的示例

 更新时间:2022年05月06日 10:11:31   作者:Iawfy_  
已经自学OpencvSharp一段时间了,现在就分享一下我的学习过程,本文主要介绍了c#中WinForm用OpencvSharp实现ROI区域提取的示例,具有一定的参考价值,感兴趣的可以了解一下

已经自学OpencvSharp一段时间了(目前工作用的是C#,就学了Opencvsharp了,vs2015,opencvsharp3),收获也有一些,现在就将我在学习过程中的收获分享出来吧。

图像处理,很常见的问题,但对于大多数时候而言,我们往往不需要去处理整张图片,而是只需要处理一部分,这就涉及到了ROI(Region of interest)的提取了。我目前提取ROI的方法是采用掩膜Mask的方法。具体的思路就是:在图像操作的时候,定义一张同等大小的空的Mask,也就是全部是0,然后将我们想要的ROI轮廓画在Mask上,并填充内部,就会得到新的Mask,这个新的Mask就只有在ROI区域非0,其余地方元素都是0,再把用Cv2.BoundingRect()将包含ROI区域的轮廓的最小矩形找出来,分别将原图与Mask这两幅图像的这个最小矩形部分提出来 ,最后再调用Cv2.BitwiseAnd()这个方法,通常情况而言,一副图像与自己本身进行与运算,输出的还是本身图像,带上掩膜Mask后,就只会输出图像在Mask非0区域部分(也就是我们所需要的ROI)的图像了,这样就实现了我们的ROI提取了。

接下来,就分享几种常见ROI区域提取吧。

部分代码如下:

主要使用的变量

         /// 放在yVars.ImgOptions中 
   public struct ROIMatt   
            {
                public static string Image;//原图  
                public static bool IsSelectRegion = false;
 
                public static int step; //ROI区域移动步长
                public static int angel; // 旋转一次 angel±=step; 旋转角度 
 
                public static yDirections direct = yDirections.NULL;
                public static yROIRegionType ROIType = yROIRegionType.Rectangle;
 
                // 矩形ROI
                // 矩形四个点坐标 都是相对于图像的坐标 而不是相对于picturebox的坐标
                // 矩形四个点相对位置 刚开始确定矩形时就这样 经过旋转后位置变 但相对位置还是这样
                //  1  2      // 按顺时针数的点   1-->2-->4-->3-->1-->2-->4-->3-->1
                //  3  4
                public static OpenCvSharp.Point rectFirstPoint = new OpenCvSharp.Point();
                public static OpenCvSharp.Point rectSecondPoint = new OpenCvSharp.Point();
                public static OpenCvSharp.Point rectThirdPoint = new OpenCvSharp.Point();
                public static OpenCvSharp.Point rectFourthPoint = new OpenCvSharp.Point(); 
                public static double rectWidth = 0;
                public static double rectHeight = 0;
 
                // 圆形ROI
                public static OpenCvSharp.Point cirCenter = new OpenCvSharp.Point(0.0,0.0); // 圆心
                public static int cirRadious = 0; // 半径
                // 椭圆ROI
                public static OpenCvSharp.Point elpCenter = new OpenCvSharp.Point(0.0,0.0); // 椭圆中心点
                public static double elpAngel = 0.0;//椭圆倾斜角度
                public static double elpLongAxis = 0.0; // 长轴
                public static double elpShortAxis = 0.0; // 短轴
            }

我的picturebox的SizeMode是StretchImage的,可能看起来跟想要的结果有点差异,但是实际上是一样的。

首先是最常见的矩形。

对于正矩形而言,我们可以直接定义出图像的ROI区域

public Mat(Mat m, Rect roi);

这样定义的图像就是原图m的指定区域了。但对于倾斜的矩阵,RotatedRect,而言,就得需要使用掩膜了,提取ROI的方法以及结果如下:

        public static void ImgMattingRect()
        {
            Mat pic = new Mat(yVars.ImgOptions.ROIMatt.Image);
            Mat mask = Mat.Zeros(pic.Size(), MatType.CV_8UC1);
            OpenCvSharp.Point2f[] coutours = new OpenCvSharp.Point2f[4];
            coutours[0] = yVars.ImgOptions.ROIMatt.rectFirstPoint;
            coutours[1] = yVars.ImgOptions.ROIMatt.rectSecondPoint;
            coutours[2] = yVars.ImgOptions.ROIMatt.rectFourthPoint;
            coutours[3] = yVars.ImgOptions.ROIMatt.rectThirdPoint;
 
            List<OpenCvSharp.Point> listt = new List<OpenCvSharp.Point>();
            for (int i = 0; i < coutours.Count(); i++)
            {
                listt.Add(new OpenCvSharp.Point(coutours[i].X, coutours[i].Y));
            }
 
            List<List<OpenCvSharp.Point>> pp = new List<List<OpenCvSharp.Point>>() { listt };
 
            Cv2.FillPoly(mask, pp, new Scalar(255, 255, 255)); 
            OpenCvSharp.Rect rect = Cv2.BoundingRect(coutours);
            Mat src = new Mat(pic, rect);
            Mat maskROI = new Mat(mask, rect);
            Mat picOut = new Mat();
            Cv2.BitwiseAnd(src, src, picOut, maskROI);
            Form1.Instance.pbxMattImage.Image = yImgConvert.MatToBitmap(picOut);
 
            yVars.ImgOptions.ROIMatt.rectFirstPoint = new OpenCvSharp.Point(0, 0);
            yVars.ImgOptions.ROIMatt.rectSecondPoint = new OpenCvSharp.Point(0, 0);
            yVars.ImgOptions.ROIMatt.rectThirdPoint = new OpenCvSharp.Point(0, 0);
            yVars.ImgOptions.ROIMatt.rectFourthPoint = new OpenCvSharp.Point(0, 0);
        }

缩放平移和旋转就只要改变矩形的四个顶点坐标就行了。方法都一样就不赘述了。

圆形ROI区域,

方法如下:

        public static void ImgMattingCircle()
        {
            Mat mm = new Mat(yVars.ImgOptions.ROIMatt.Image);
            Mat mask = Mat.Zeros(mm.Size(), MatType.CV_8UC3);
 
            Cv2.Circle(mask, yVars.ImgOptions.ROIMatt.cirCenter, yVars.ImgOptions.ROIMatt.cirRadious, Scalar.Red, 1, LineTypes.AntiAlias);
            Cv2.FloodFill(mask, yVars.ImgOptions.ROIMatt.cirCenter, Scalar.Red);
 
            mask.ConvertTo(mask, MatType.CV_8UC1);
 
            int xx = yVars.ImgOptions.ROIMatt.cirCenter.X - yVars.ImgOptions.ROIMatt.cirRadious;
            int yy = yVars.ImgOptions.ROIMatt.cirCenter.Y - yVars.ImgOptions.ROIMatt.cirRadious;
            int rr = 2 * yVars.ImgOptions.ROIMatt.cirRadious;
            // 圆的外接正方形
            Rect rect = new Rect(new OpenCvSharp.Point(xx, yy), new OpenCvSharp.Size(rr, rr));
 
            Mat src = new Mat(mm, rect);
            Mat maskRoI = new Mat(mask, rect);
 
            Cv2.CvtColor(maskRoI, maskRoI, ColorConversionCodes.BGR2GRAY);
 
            Mat picOut = new Mat();
            Cv2.BitwiseAnd(src, src, picOut, maskRoI);
 
            Form1.Instance.pbxMattImage.Image = yImgConvert.MatToBitmap(picOut);
 
            yVars.ImgOptions.ROIMatt.cirCenter = new OpenCvSharp.Point(0, 0);
            yVars.ImgOptions.ROIMatt.cirRadious = 0;
        }

效果展示:

 圆形ROI的移动时就只有圆心坐标变 半径不变,而缩放时只改变半径,圆心不变,注意移动时别超出图像界限就行。

椭圆ROI

在Opencvsharp中绘制椭圆有两种方式

        //
        // 摘要:
        //     Draws simple or thick elliptic arc or fills ellipse sector
        //
        // 参数:
        //   img:
        //     Image.
        //
        //   box:
        //     The enclosing box of the ellipse drawn
        //
        //   color:
        //     Ellipse color.
        //
        //   thickness:
        //     Thickness of the ellipse boundary. [By default this is 1]
        //
        //   lineType:
        //     Type of the ellipse boundary. [By default this is LineType.Link8]
        public static void Ellipse(InputOutputArray img, RotatedRect box, Scalar color, int thickness = 1, LineTypes lineType = LineTypes.Link8);
        //
        // 摘要:
        //     Draws simple or thick elliptic arc or fills ellipse sector
        //
        // 参数:
        //   img:
        //     Image.
        //
        //   center:
        //     Center of the ellipse.
        //
        //   axes:
        //     Length of the ellipse axes.
        //
        //   angle:
        //     Rotation angle.
        //
        //   startAngle:
        //     Starting angle of the elliptic arc.
        //
        //   endAngle:
        //     Ending angle of the elliptic arc.
        //
        //   color:
        //     Ellipse color.
        //
        //   thickness:
        //     Thickness of the ellipse arc. [By default this is 1]
        //
        //   lineType:
        //     Type of the ellipse boundary. [By default this is LineType.Link8]
        //
        //   shift:
        //     Number of fractional bits in the center coordinates and axes' values. [By default
        //     this is 0]
        public static void Ellipse(InputOutputArray img, Point center, Size axes, double angle, double startAngle, double endAngle, Scalar color, int thickness = 1, LineTypes lineType = LineTypes.Link8, int shift = 0);

我们采用第一种方式,即可以将椭圆转化成一个RotatedRect,只要在画RotatedRect的时候改成画椭圆即可,就可以回到第一种矩形的ROI提取上面了, 代码如下:

        public static void ImgMattingEllipse()
        {
            Mat mm = new Mat(yVars.ImgOptions.ROIMatt.Image);
            Mat mask = Mat.Zeros(mm.Size(), MatType.CV_8UC3);
 
            RotatedRect rorect = new RotatedRect(yVars.ImgOptions.ROIMatt.elpCenter, new Size2f(yVars.ImgOptions.ROIMatt.elpLongAxis, yVars.ImgOptions.ROIMatt.elpShortAxis), (float)yVars.ImgOptions.ROIMatt.elpAngel);
            Cv2.Ellipse(mask, rorect, Scalar.Red);
 
            Mat gray = new Mat();
            Cv2.CvtColor(mask, gray, ColorConversionCodes.BGR2GRAY);
            Cv2.Threshold(gray, gray, 100, 255, ThresholdTypes.Otsu);
 
            OpenCvSharp.Point[][] contours;
            HierarchyIndex[] hierarchly;
            Cv2.FindContours(gray, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));
 
            Rect rect = Cv2.BoundingRect(contours[0]);
 
            Cv2.FloodFill(mask, yVars.ImgOptions.ROIMatt.elpCenter, Scalar.Red);
 
            mask.ConvertTo(mask, MatType.CV_8UC1);
 
            Mat src = new Mat(mm, rect);
            Mat maskRoI = new Mat(mask, rect);
            Cv2.CvtColor(maskRoI, maskRoI, ColorConversionCodes.BGR2GRAY);
            Mat picOut = new Mat();
            Cv2.BitwiseAnd(src, src, picOut, maskRoI);
 
            Form1.Instance.pbxMattImage.Image = yImgConvert.MatToBitmap(picOut);
        }

实验结果如下:

 平移缩放旋转等操作就可以看成对RotatedRect的操作即可。

到此这篇关于c#中WinForm用OpencvSharp实现ROI区域提取的示例的文章就介绍到这了,更多相关c# ROI区域提取内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#中缓存的基本用法总结

    C#中缓存的基本用法总结

    这篇文章主要介绍了C#中缓存的基本用法,对C#初学者来说是很有必要熟练掌握的内容,需要的朋友可以参考下
    2014-08-08
  • C#动态加载dll扩展系统功能的方法

    C#动态加载dll扩展系统功能的方法

    这篇文章主要介绍了C#动态加载dll扩展系统功能的方法,涉及C#动态加载dll扩展的相关技巧,需要的朋友可以参考下
    2015-04-04
  • C#如何删除指定文件或文件夹

    C#如何删除指定文件或文件夹

    这篇文章主要介绍了C#如何删除指定文件或文件夹,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • C# 使用相同权限调用 cmd 传入命令的方法

    C# 使用相同权限调用 cmd 传入命令的方法

    本文告诉大家如何使用相同权限调用cmd并且传入命令,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-07-07
  • AjaxControlToolkit AjaxFileUpload 显示英文改成中文的解决方法

    AjaxControlToolkit AjaxFileUpload 显示英文改成中文的解决方法

    AjaxControlToolkit AjaxFileUpload 显示英文改成中文的解决方法,需要的朋友可以参考一下
    2013-03-03
  • C# Dictionary和SortedDictionary的简介

    C# Dictionary和SortedDictionary的简介

    今天小编就为大家分享一篇关于C# Dictionary和SortedDictionary的简介,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • 改进c# 代码的五个技巧(一)

    改进c# 代码的五个技巧(一)

    这篇文章主要介绍了改进c# 代码的五个技巧(一),帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下
    2021-01-01
  • C#调用Polly库实现捕捉异常处理的操作代码

    C#调用Polly库实现捕捉异常处理的操作代码

    Polly 是一个 .NET 弹性和瞬态故障处理库,允许开发人员以 Fluent 和线程安全的方式来实现重试、断路、超时、隔离和回退策略,本文给大家介绍了C#调用Polly库实现捕捉异常处理操作,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-08-08
  • C#中的委托和事件

    C#中的委托和事件

    这篇文章介绍了C#中的委托和事件,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • 分享用于操作FTP的客户端C#类

    分享用于操作FTP的客户端C#类

    用.net自带的FtpWebRequest做的ftp客户端得程序,有一个功能实现起来会非常苦难,就是移动文件和文件夹的功能。所以后来又找了一个类,用socket实现的,发现比用ftpWebRequest功能要强。基本的ftp客户端得命令都实现了。
    2015-05-05

最新评论