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区域提取内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python+OpenCV感兴趣区域ROI提取方法

    方法一:使用轮廓 步骤1 """src为原图""" ROI = np.zeros(src.shape, np.uint8) #感兴趣区域ROI proimage = src.copy() #复制原图 """提取轮廓""" proimage=cv2.cvtColor(proimage,cv2.COLOR_BGR2GRAY) #转换成灰度图 proimage=cv2.adaptiveThre

  • Python+OpenCV数字图像处理之ROI区域的提取

    目录 1.实现原理 2.使用的函数简述 3.代码实现过程 (1)读入原始图像 (2)获取mask (3)获取人物mask (4)获取人物 (5)新建一张与原始图一样大小的蓝色的背景图 (6)得到蓝色背景的mask 4.整体代码  利用mask(掩模)技术提取纯色背景图像ROI区域中的人和物,并将提取出来的人或物添加在其他图像上. 1.实现原理 先通过cv.cvtColor()函数,将原RGB彩色图像转换为hsv色彩空间的图像,然后通过cv.inRange()函数获得ROI区域的Mask,最后利用

  • Python+OpenCV进行不规则多边形ROI区域提取

    多边形ROI,主要利用鼠标交互进行绘制: 1. 单击左键,选择多边形的点: 2. 单击右键,删除最近一次选择的点: 3. 单击中键,确定ROI区域并可视化. 4. 按”S“键,将多边形ROI区域的点保存到本地”config.pkl"文件中. 话不多说,以下是核心代码 import cv2 import numpy as np import joblib pts = [] # 用于存放点 # 统一的:mouse callback function def draw_roi(event, x, y,

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

    已经自学OpencvSharp一段时间了(目前工作用的是C#,就学了Opencvsharp了,vs2015,opencvsharp3),收获也有一些,现在就将我在学习过程中的收获分享出来吧. 图像处理,很常见的问题,但对于大多数时候而言,我们往往不需要去处理整张图片,而是只需要处理一部分,这就涉及到了ROI(Region of interest)的提取了.我目前提取ROI的方法是采用掩膜Mask的方法.具体的思路就是:在图像操作的时候,定义一张同等大小的空的Mask,也就是全部是0,然后将我们想

  • c#中WinForm使用OpencvSharp4实现简易抓边

    环境: VS2019 , OpencvSharp4 4.5.5.20211231 , .NET Framework 4.8 界面设计: 图像显示用的是picturebox 控件都是windows基本控件 效果展示: 图像是自己画图画的 所以抓的效果比较好 .其他图片的话可能需要调整一下相关参数,效果可能达不到这么好 实现原理: 在图像中选择ROI,从原图上把对应ROI部分的图像扣下来,然后对扣下来的图像进行边缘处理等操作,得到边缘和拟合线,最后在原图上将边缘和拟合线画出来即可.注意,得到的边缘是

  • python+opencv图像分割实现分割不规则ROI区域方法汇总

    在图像分割领域,一个重要任务便是分割出感兴趣(ROI)区域.如果是简易的矩形ROI区域其实是非常容易分割的,opencv的官方python教程里也有教到最简易的矩形ROI分割(剪裁),其本质是多维数组(矩阵)的切片.但是现实情况中,ROI是不规则的多边形,也可能是曲线边界,那么该如何分割出来呢?下面总结几种思路. 可能只提供核心部分的代码示例,具体应用要结合你自己的项目来修正. 一.已知边界坐标,直接画出多边形 例:最基础的画个四边形 # 定义四个顶点坐标 pts = np.array([[10

  • Python图像处理之图像融合与ROI区域绘制详解

    目录 一.图像融合 二.图像ROI区域定位 三.图像属性 (1)shape (2)size (3)dtype 四.图像通道分离及合并 (1)split()函数 (2)merge()函数 五.图像类型转换 六.总结 一.图像融合 图像融合通常是指多张图像的信息进行融合,从而获得信息更丰富的结果,能够帮助人们观察或计算机处理.图5-1是将两张不清晰的图像融合得到更清晰的效果图. 图像融合是在图像加法的基础上增加了系数和亮度调节量,它与图像的主要区别如下[1-3]: 图像加法:目标图像 = 图像1 +

  • C#中winform实现自动触发鼠标、键盘事件的方法

    程序触发鼠标.键盘事件是C#程序设计中比较常见的功能,本文实例展示了C#中winform实现自动触发鼠标.键盘事件的方法,有不错的实用价值.具体如下: 要想在C#程序中触发鼠标.键盘事件就必须要调用windows函数. 一.鼠标事件的触发 1.引用windows函数mouse_event /// <summary> /// 鼠标事件 /// </summary> /// <param name="flags">事件类型</param> /

  • C#中winform使用相对路径读取文件的方法

    本文实例讲述了C#中winform使用相对路径读取文件的方法.分享给大家供大家参考.具体分析如下: 目录结构如下图所示:   方法一:由于生成的exe文件在bin\debug目录下,可以使用向上查找目录的方式获取要读取的xml文件 复制代码 代码如下: string haarXmlPath = @"../../haarcascade_frontalface_alt_tree.xml"; FileInfo file = new FileInfo(fileName); string  fu

  • C#中Winform窗体Form的关闭按钮变灰色的方法

    本文实例讲述了C#中Winform窗体Form的关闭按钮变灰色的方法,对C#程序设计有一定的借鉴价值,分享给大家供大家参考之用.具体方法如下: 主要功能代码如下: [ DllImport ( "USER32.DLL" ) ] public static extern int GetSystemMenu(int hwnd, int bRevert); [ DllImport ( "USER32.DLL" ) ] public static extern int Rem

  • C#中WinForm程序退出方法技巧总结

    本文实例总结了C#中WinForm程序退出方法技巧.分享给大家供大家参考.具体分析如下: 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.ExitThread(); System.Environment.Exit(0); 等他们各自的方法不一样,下面我们就来详细介绍一下. 1.this.Close();   只是关闭当前窗口,若不是主窗体的话,是无法退出程序的,另外若有托管线程(非主线程),也无法干净地退

随机推荐