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

devtools/2024/11/15 6:16:27/

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

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 分割得到对象区域和类别


http://www.ppmy.cn/devtools/111952.html

相关文章

Java API 搜索引擎测试报告

一、测试项目介绍 基于SpringBoot开发的 Java API 文档搜索引擎&#xff0c;输入具体的类名或包名就能找到对应相关的搜索结果&#xff0c;点击标题即可跳转到对应官方网页。 二、测试 测试环境&#xff1a;Windows11&#xff0c;Google chrome浏览器 128.0.6613.138 (正式版…

printf和printk

printf 和 printk 都是用于打印信息的函数&#xff0c;但它们应用在不同的编程环境和操作系统层面。 printf printf 是 C 语言标准库中的一个函数&#xff0c;用于在控制台或命令行界面输出格式化的字符串。它属于高级别的输入输出函数&#xff0c;通常用于应用程序级别的编程…

《Docker:轻量级虚拟化解决方案》

《Docker&#xff1a;轻量级虚拟化解决方案》 在当今的软件开发和部署领域&#xff0c;Docker 以其独特的优势成为了众多开发者和运维人员的得力工具。它是一个开源的应用容器引擎&#xff0c;基于 Go 语言并遵从 Apache2.0 协议开源。 一、Docker 的简介与概述 Docker 的主…

MySQL record 02 part

查看已建数据库的基本信息&#xff1a; show CREATE DATABASE mydb; 注意&#xff0c;是DATABASE 不是 DATABASEs&#xff0c; 命令成功执行后&#xff0c;回显的信息有&#xff1a; CREATE DATABASE mydb /*!40100 DEFAULT CHARACTER SET utf8mb3 / /!80016 DEFAULT ENCRYPTIO…

Conmi的正确答案——MySQL的层级递归查询(递归公共表表达式,CTE)

数据库&#xff1a;oceanbase-ce 递归sql主体&#xff1a; WITH RECURSIVE country_area_tree AS (-- 非递归部分&#xff0c;初始化查询SELECT id, area_name, parent_id, 0 AS levelFROM country_areaWHERE id 589004044419077UNION ALL-- 递归部分&#xff0c;找到子节点S…

面试干货|2024软件测试面试题汇总

我把软件测试面试的整个题库都搬来啦&#xff0c;面试能拿下80%&#xff0c;剩下就看你满不满意公司的开价咯。以下答案都是我自己写的&#xff0c;大家根据自己的经历稍作改动&#xff0c;答案仅供参考哦&#xff01;题库持续更新&#xff0c;需要PDF版可以点击文末小卡片领取…

微波无源器件 3 一种用于Ka频带双极化波束形成网络的双模三路功分器

摘要&#xff1a; 本文给出了一种用于Ka频带的双极化工作的双模3路功分器的设计和性能。对有着三个输出端口的平衡地很好的功分的TE10和TE01模式和27.5-30GHz上优于-23dB的输入匹配可以获得相似的性能。与双模定向耦合器相连结&#xff0c;此三路功分器对于双极化波束形成网络具…

linux -L4.linux 暂停和启动进程

接第3课&#xff0c;L3 第3课-查看进程 通过端口号&#xff0c;查看对应的进程 netstat -tulnp | grep :9513暂停这个进程 Kill -STOP 5376重启这个进程 Kill -CONT 5376要查看特定PID对应的端口&#xff0c;你可以使用netstat命令结合grep工具来过滤输出。以下是一个基于L…