自学内容网 自学内容网

EmguCV学习笔记 C# 11.6 图像分割

 版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。

教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客

教程C#版本请访问:EmguCV学习笔记 C# 目录-CSDN博客

笔者的博客网址:https://blog.csdn.net/uruseibest

教程配套文件及相关说明以及如何获得pdf教程和代码,请移步:EmguCV学习笔记

学习VB.Net知识,请移步: vb.net 教程 目录_vb中如何用datagridview-CSDN博客

 学习C#知识,请移步:C# 教程 目录_c#教程目录-CSDN博客

11.6 图像分割

11.6.1 语义分割Fcn

FCN(Fully Convolutional Network)是一种流行的语义分割算法,它通过将传统的卷积神经网络转化为全卷积网络来实现像素级别的语义分割,将输入图像传入网络中,得到每个像素的标签,并根据标签来分割出不同的物体。FCN在语义分割任务中表现优秀,可以实现像素级别的精细分割,被广泛应用于自动驾驶、智能监控等领域。

【代码位置:frmChapter11】Button5_Click、getColorTable、showColorTable

        //语义分割fcn

        private void Button5_Click(object sender, EventArgs e)

        {

            //对象分类,object_detection_classes_pascal_voc.txt文件提供了21类对象(含background

            string[] classnames = System.IO.File.ReadAllLines("C:\\learnEmgucv\\fcn\\object_detection_classes_pascal_voc.txt");

            //获得输出颜色表

            Bgr[] colorTable = getColorTable();

            //显示颜色表及对应对象名称

            showColorTable(classnames, colorTable);

            //需要测试的图像文件

            Mat m = new Mat("C:\\learnEmgucv\\dnntest1.jpg", ImreadModes.Color);

            Single hm = m.Height;

            Single wm = m.Width;

            Net net;

            net = DnnInvoke.ReadNetFromCaffe("C:\\learnEmgucv\\fcn\\fcn8s-heavy-pascal.prototxt",

                                             "C:\\learnEmgucv\\fcn\\fcn8s-heavy-pascal.caffemodel"

                                            );

            Mat mcopy = new Mat();

            CvInvoke.Resize(m, mcopy, new Size(500, 500));

            Mat blob = DnnInvoke.BlobFromImage(mcopy, 1, new Size(500, 500),

                                       new MCvScalar(0,0,0), false, false);

            net.SetInput(blob);

            Mat mout = new Mat();

            mout = net.Forward();

            Single[,,,] fout;

            fout = (Single[,,,])mout.GetData();

            //通道数=21,即21类对象

            int chan = fout.GetLength(1);

            //高度=500

            int row = fout.GetLength(2);

            //宽度=500

            int col = fout.GetLength(3);

            //记录21个通道对应坐标点的最大值

            Matrix<Single> matrMaxValue = new Matrix<Single>(new Size(row, col));

            matrMaxValue.SetZero();

            记录对应通道号

            //Matrix<Single> matrMaxChan = new Matrix<Single>(new Size(row, col));

            //matrMaxChan.SetZero();

            //记录对应颜色

            Image<Bgr, byte> imgOut = new Image<Bgr, byte>(col, row);

            imgOut.SetZero();

            //遍历21个通道

            for (int c = 0; c < chan; c++)

                for (int h = 0; h < row; h++)

                    //遍历高度和宽度,获得对应坐标的值

                    for (int w = 0; w < col; w++)

                        //比较最大值

                        if (fout[0, c, h, w] > matrMaxValue[h, w])

                        {

                            //取得最大值

                            matrMaxValue[h, w] = fout[0, c, h, w];

                            取得通道号

                            //matrMaxChan[h, w] = c;

                            //最重要的是获取通道对应颜色表的值

                            imgOut[h, w] = colorTable[c];

                        }

            //显示输出的图像

            //ImageBox1.Image = imgOut.Mat;

            //设置掩膜

            Mat mask = new Mat();

            mask = imgOut.Mat;

            //掩膜大小必须和源图像一致

            CvInvoke.Resize(mask, mask, m.Size);

            //将上面的输出图像和源图像叠加

            Mat mFinalOut = new Mat();

            CvInvoke.AddWeighted(m, 0.3, mask, 0.7, 0, mFinalOut);

            ImageBox1.Image = mFinalOut;

        }

       //为了更好地观察,这里没有使用随机颜色

        private Bgr[] getColorTable()

        {

            Bgr[] newColors = new Bgr[21];

            newColors[0] = new Bgr(0, 0, 0);        //background

            newColors[1] = new Bgr(128, 0, 0);      //aeroplane

            newColors[2] = new Bgr(0, 128, 0);      //bicycle

            newColors[3] = new Bgr(128, 128, 0);    //bird

            newColors[4] = new Bgr(0, 0, 128);      //boat

            newColors[5] = new Bgr(128, 0, 128);    //bottle

            newColors[6] = new Bgr(0, 128, 128);    //bus

            newColors[7] = new Bgr(128, 128, 128);  //car

            newColors[8] = new Bgr(255, 0, 0);     //cat

            newColors[9] = new Bgr(0, 255, 0);     //chair

            newColors[10] = new Bgr(0, 0, 255);     //cow

            newColors[11] = new Bgr(255, 255, 0);   //diningtable

            newColors[12] = new Bgr(64, 0, 128);    //dog

            newColors[13] = new Bgr(192, 0, 128);   //horse

            newColors[14] = new Bgr(64, 128, 128);  //motorbike

            newColors[15] = new Bgr(192, 128, 128); //person

            newColors[16] = new Bgr(0, 64, 0);     //pottedplant

            newColors[17] = new Bgr(128, 64, 64);   //sheep

            newColors[18] = new Bgr(0, 192, 0);     //sofa

            newColors[19] = new Bgr(128, 192, 0);   //train

            newColors[20] = new Bgr(0, 64, 128);    //tvmonitor

            return newColors;

        }

        //显示颜色表及对象名称

        //参数1:对象名称的字符串数组

        //参数2bgr颜色数组

        private void showColorTable(string[] names, Bgr[] colors)

        {

            List<Mat> lstmoutV = new List<Mat>();

            for (int i = 0; i <= 20; i++)

            {

                Mat moutV = new Mat(40, 200, DepthType.Cv8U, 3);

                moutV.SetTo(new MCvScalar(colors[i].Blue, colors[i].Green, colors[i].Red));

                CvInvoke.PutText(moutV, names[i], new Point(20, 25), FontFace.HersheyTriplex, 0.4, new MCvScalar(255, 255, 255));

                lstmoutV.Add(moutV);

            }

            Mat mout = new Mat();

            //垂直方向拼接

            CvInvoke.VConcat(lstmoutV.ToArray(), mout);

            CvInvoke.Imshow("colortable", mout);

        }

输出结果如下图所示:

 

图11-4 FCN分割获得不同对象区域

11.6.2 实例分割 MASK RCNN

Mask RCNN是一种基于Faster R-CNN的实例分割算法,它是一种联合目标检测和语义分割的方法,能够同时检测图像中的对象并得到每个对象的位置、类别和像素级别的分割结果。Mask RCNN在实例分割任务中表现优秀,是目前最先进的实例分割算法之一,被广泛应用于自动驾驶、智能监控等领域。

【代码位置:frmChapter11】Button6_Click、getRadomColor

        //实例分割 mask rcnn

        private void Button6_Click(object sender, EventArgs e)

        {

            //对象分类,object_detection_classes_coco.txt文件提供了90类对象(含background

            string[] classnames;

            classnames = System.IO.File.ReadAllLines("C:\\learnEmgucv\\maskrcnn\\object_detection_classes_coco.txt");

            //需要测试的图像文件

            Mat m = new Mat("C:\\learnEmgucv\\dnntest.jpg", ImreadModes.Color);

            Single hm = m.Height;

            Single wm = m.Width;

            Net net;

            net = DnnInvoke.ReadNetFromTensorflow("C:\\learnEmgucv\\maskrcnn\\frozen_inference_graph.pb",

                                 "C:\\learnEmgucv\\maskrcnn\\mask_rcnn_inception_v2_coco_2018_01_28.pbtxt"

                                  );

            Mat mcopy = new Mat();

            mcopy = m.Clone();

            Mat blob;

            blob = DnnInvoke.BlobFromImage(mcopy, 1, new Size(500, 500),

                                           new MCvScalar(0, 0, 0), false, false);

            net.SetInput(blob);

            string[] names = new string[2];

            names[0] = "detection_out_final";

            names[1] = "detection_masks";

            //返回的mout包含两个mat

            VectorOfMat mout = new VectorOfMat();

            net.Forward(mout, names);

            //第一个mat标识返回的置信度候选框,是一个四维数组

            Mat moutBox = new Mat();

            moutBox = mout[0];

            //返回维度:

            //1维:1

            //2维:1

            //3维:100100个候选置信矩形框

            //4维:70?;1:对应类别;2:置信度;3-6:候选框位置(源图像百分比)

            Single[,,,] foutBox;

            foutBox = (Single[,,,])moutBox.GetData();

            //第二个mat标识返回的掩膜,是一个四维数组   

            Mat moutMask = new Mat();

            moutMask = mout[1];

            //返回维度:

            //1维:100100个对象对应的100个掩膜

            //2维:90,对象的置信度

            //3维:15,掩膜高度

            //4维:15,掩膜宽度

            Single[,,,] foutMask;

            foutMask = (Single[,,,])moutMask.GetData();

            int maskH = 15;   //foutMask.GetLength(2)

            int maskW = 15;  //foutMask.GetLength(3)

            //新建Mat,用来在这上面绘制掩膜

            Mat mbg = new Mat(new Size(m.Width, m.Height), DepthType.Cv8U, 3);

            mbg.SetTo(new MCvScalar(0, 0, 0));

            for (int i = 0; i < 100; i++)

            {

                //置信度

                Single conf = foutBox[0, 0, i, 2];

                //当置信度满足时

                if (conf > 0.53)

                {

                    //对应检测对象的序号

                    int objID = (int)foutBox[0, 0, i, 1];

                    Single ltX = foutBox[0, 0, i, 3] * wm; //左上角X

                    Single ltY = foutBox[0, 0, i, 4] * hm; //左上角Y

                    Single rbX = foutBox[0, 0, i, 5] * wm; //右下角X

                    Single rbY = foutBox[0, 0, i, 6] * hm; //右下角Y

                    Single w = rbX - ltX; //宽度

                    Single h = rbY - ltY; //高度

                    //绘制包围矩形框

                    CvInvoke.Rectangle(m, new Rectangle((int)ltX, (int)ltY,(int) w, (int)h), new MCvScalar(0, 0, 255), 1);

                    //绘制对象名称

                    CvInvoke.PutText(m, classnames[objID], new Point((int)ltX, (int)ltY - 10), FontFace.HersheyTriplex, 0.3, new MCvScalar(255, 0, 0));

                    //开始处理掩膜

                    Mat mmask = new Mat();

                    //掩膜大小为15*15,对应foutMask最后两个维度

                    Single[,] bmask = new Single[15, 15];

                    for (int j = 0; j < 15; j++)

                        for (int k = 0; k < 15; k++)

                            bmask[j, k] = foutMask[i, objID, j, k];

                    //将数组转为Mat

                    Matrix<Single> matrmask = new Matrix<Single>(bmask);

                    mmask = matrmask.Mat;

                    //大小放大与对应包围矩形框一致

                    CvInvoke.Resize(mmask, mmask, new Size((int)w, (int)h));

                    //二值化

                    CvInvoke.Threshold(mmask, mmask, 0.3, 255, ThresholdType.Binary);

                    //由于本身是CV32F,需要处理为CV8U,才能使用FindContours

                    mmask.ConvertTo(mmask, DepthType.Cv8U);

                    //定义关注区域,当修改关注区域时,也就修改了源图像

                    Mat mRoi = new Mat(mbg, new Rectangle((int)ltX, (int)ltY, (int)w, (int)h));

                    //查找轮廓

                    VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();

                    CvInvoke.FindContours(mmask, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);

                    //填充轮廓

                    CvInvoke.DrawContours(mRoi, contours, -1, getRadomColor(), -1);

                }

            }

            Mat mresult = new Mat();

            //加法

            CvInvoke.AddWeighted(m, 1, mbg, 0.4, 0, mresult);

            ImageBox1.Image = mresult;

        }

        //获得随机颜色

        private MCvScalar getRadomColor()

        {

            Random rd = new Random(DateTime.Now.Millisecond);

            byte r, g, b;

            b = (byte)rd.Next(256);

            g = (byte)rd.Next(256);

            r = (byte)rd.Next(256);

            return new MCvScalar(b, g, r);

        }

输出结果如下图所示:

 

图11-5 Mask RCNN 分割得到对象区域和类别


原文地址:https://blog.csdn.net/UruseiBest/article/details/142190737

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!