使用opencvsharp实现对Mask_Rcnn的调用(C#)

版权所有,翻版必究。

运行环境:WIN10,pycharm,相应的CUDA,CUDNN,tensorflow1.15.0,tensorflow-gpu-1.14.0,Anaconda3

https://blog.csdn.net/fightingxyz/article/details/107013155有空的先看看这篇文章,这边文章是在这个文章的基础上来做的。主要是前一篇文章是用来介绍怎么获取.pb文件和.pbtxt文件的。然后此篇博客是对此的改写,将其变成C#下的版本。如果有问题欢迎互相讨论,不惜勿喷!

第一步:获取.pb文件和.pbtxt文件(模型准备!)。详情请参见:https://blog.csdn.net/fightingxyz/article/details/107013155

主要测试的图像是这种类型:

上一篇文章中,有详细说明相关内容。主要是用来预测apple banana orange。我用C#的测试结果为:

第二步:配置C#的调用环境,看下图:

主要依赖库为这些!补充一句,必须要是opencv4.0及其以上才行,因为低版本还没有嵌入调用mask_rcnn的接口。

上面安装库中的TensorFlowSharp可用可不用,因为程序中没用(●'◡'●)

第三步:话不多说,详情看代码!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using TensorFlow;
using System.IO;

namespace test10
{
    class Program
    {
        static void Main(string[] args)
        {
            string textGraph = "mask_rcnn.pbtxt";
            string modelWeights = "frozen_inference_graph.pb";
            string classesFile = "mscoco_labels.names";
            string colorsFile = "colors.txt";

            float confThreshold = 0.9f;  //此处只是设置你的预测框阈值,判断是否显示

            float maskThreshold = 0.3f;


            List<string> classes = new List<string>();   //用来存放类型数据在其中
            List<Scalar> colors = new List<Scalar>();   //用来存放画图的颜色
            Mat blob;
            float m_fWidthScale;
            float m_fHeighScale;

            //下面这段主要是用于读取文件,并将其中内容放置classes中。
            //和上一篇文章中的void LoadLabelAndColor()函数一个意思,不懂可以去看看python版本或者C++版本
            FileStream myfs = new FileStream(classesFile, FileMode.Open);
            StreamReader reader = new StreamReader(myfs);
            string con;
            con = reader.ReadToEnd();
            var a = con.Split(new string[] { "\r\n" }, StringSplitOptions.None);
            

            foreach (var ai in a)
            {
                Console.WriteLine(ai);
                classes.Add(ai);
            }

            //这个地方也是读取文件,但是没用上
            FileStream myfs1 = new FileStream(colorsFile, FileMode.OpenOrCreate);
            StreamReader reader1 = new StreamReader(myfs1);
            string con1;
            con1 = reader1.ReadToEnd();
            var a1 = con1.Split(new string[] { "\r\n" }, StringSplitOptions.None);


            //因为我这里单独拿出来了
            colors.Add(new Scalar(0, 255,0));
            colors.Add(new Scalar(0, 0, 255));
            colors.Add(new Scalar(255, 0, 0));


            OpenCvSharp.Dnn.Net net = OpenCvSharp.Dnn.CvDnn.ReadNetFromTensorflow(modelWeights, textGraph);

            net.SetPreferableBackend(OpenCvSharp.Dnn.Net.Backend.OPENCV);    //opencv是使用intel编译的
            net.SetPreferableTarget(OpenCvSharp.Dnn.Net.Target.CPU);

            int ImgWidth = 224;
            int ImgHight = 224;

            Mat frame = Cv2.ImRead("1.jpg");
           
            Mat m_DstMat = frame.Clone();
            Size s2f = new Size(ImgWidth, ImgHight);
            Cv2.Resize(frame, frame, s2f);

            m_fWidthScale = (float)(m_DstMat.Cols * 1.0 / frame.Cols);
            m_fHeighScale = (float)(m_DstMat.Rows * 1.0 / frame.Rows);

            // Stop the program if reached end of video
            if (frame.Empty())
            {
                return;
            }


            blob = OpenCvSharp.Dnn.CvDnn.BlobFromImage(frame, 1.0, new Size(frame.Cols, frame.Rows), new Scalar(), true, false);

            net.SetInput(blob);

            List<string> outNames = new List<string>(2);
            outNames.Add("detection_out_final");  //此处是预测的边框点
            outNames.Add("detection_masks");  //这些名字设置和模型中的设置有关系,主要也是利用名称取索引相应的结果,此处是预测的掩模图

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


            Mat outDetections;
            Mat outMasks ;

            //预测的图我选择了分开写,调用其他两种出不来,原因还在找,知道的可以交流交流,谢谢。详情可以打开net.ForWard()看一看
            //结果有三种:
            /*public Mat Forward([NullableAttribute(2)] string? outputName = null);
public void Forward(IEnumerable<Mat> outputBlobs, [NullableAttribute(2)] string? outputName = null);
public void Forward(IEnumerable<Mat> outputBlobs, IEnumerable<string> outBlobNames);*/
            outMasks = net.Forward("detection_masks");  
            outDetections = net.Forward("detection_out_final");


            int numDetections = outDetections.Size(2);
            int numClasses = outMasks.Size(1);


            // 预测框结果outDetections   掩膜结果outMasks 
            outDetections = outDetections.Reshape(1, (int)outDetections.Total() / 7);
            for (int i = 0; i < numDetections; ++i)
            {
                float score = outDetections.At<float>(i, 2);
                if (score > confThreshold)
                //if (score > 0.2)
                {
                    // Extract the bounding box
                    int classId = (int)(outDetections.At<float>(i, 1));
                    int left = (int)(frame.Cols * outDetections.At<float>(i, 3));
                    int top = (int)(frame.Rows * outDetections.At<float>(i, 4));
                    int right = (int)(frame.Cols * outDetections.At<float>(i, 5));
                    int bottom = (int)(frame.Rows * outDetections.At<float>(i, 6));

                    left = Math.Max(0, Math.Min(left, frame.Cols - 1));
                    top = Math.Max(0, Math.Min(top, frame.Rows - 1));
                    right = Math.Max(0, Math.Min(right, frame.Cols - 1));
                    bottom = Math.Max(0, Math.Min(bottom, frame.Rows - 1));
                    Rect box = new Rect(left, top, right - left + 1, bottom - top + 1);

                    /************************************************/
                    box.X = (int)Math.Round(box.X * m_fWidthScale);
                    box.Y = (int)Math.Round(box.Y * m_fHeighScale);
                    box.Width = (int)Math.Round(box.Width * m_fWidthScale);
                    box.Height = (int)Math.Round(box.Height * m_fHeighScale);
                    /************************************************/

                    // Extract the mask for the object
                    Mat objectMask = new Mat(outMasks.Size(2), outMasks.Size(3), MatType.CV_32F, outMasks.Ptr(i, classId));
                    // Draw bounding box, colorize and show the mask on the image

                    OpenCvSharp.Scalar s3 = new Scalar(255, 178, 50);

                    //Draw a rectangle displaying the bounding box
                    Cv2.Rectangle(m_DstMat, new Point(box.X, box.Y), new Point(box.X + box.Width, box.Y + box.Height), s3, 3);



                    //Get the label for the class name and its confidence
                    string label1;
                    label1 = score.ToString("F4");
                    string labelasdfa;
                    labelasdfa= classes[classId] + ":" + label1;



                    //Display the label at the top of the bounding box
                    int baseLine;
                    Size labelSize = Cv2.GetTextSize(labelasdfa, 0, 0.5, 1, out baseLine);
                    box.Y = Math.Max(box.Y, labelSize.Height);

                    Cv2.Rectangle(m_DstMat, new Point(box.X, box.Y - Math.Round(1.5 * labelSize.Height)), new Point(box.X + Math.Round(1.5 * labelSize.Width), box.Y + baseLine), new Scalar(255, 255, 255), Cv2.FILLED);

                    Cv2.PutText(m_DstMat, labelasdfa, new Point(box.X, box.Y), 0, 0.75, new Scalar(0, 0, 0), 1);


                    Scalar color = colors[classId % colors.Capacity];  

                    // Resize the mask, threshold, color and apply it on the image
                    Cv2.Resize(objectMask, objectMask, new Size(box.Width, box.Height));


                    Mat mask = objectMask;

                    Mat pos1 = new Mat(m_DstMat, box);
 

                    //Mat coloredRoi = (0.3 * color + 0.7 * m_DstMat(box));


                    Mat coloredRoi = new Mat(m_DstMat, box);
                    coloredRoi.ConvertTo(coloredRoi, MatType.CV_8UC3);



                    mask.ConvertTo(mask, MatType.CV_8U);
                    Cv2.FindContours(mask, out Point[][] contours,out HierarchyIndex[] hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple);

                    Cv2.DrawContours(coloredRoi, contours, -1, color, 5, LineTypes.Link8, hierarchy, 100);

                    Mat pos = new Mat(m_DstMat, box);
                    coloredRoi.CopyTo(pos, mask);


                }
            }


            double[] layersTimes = new double[] { };
            double freq = Cv2.GetTickFrequency() / 1000;
            double t = net.GetPerfProfile(out layersTimes) / freq;
            string label = "Inference time for a frame "+t.ToString("F4")+"ms";

            OpenCvSharp.Scalar s2 = new Scalar(0, 0, 0);
            Point xy = new Point(0, 15);
            Cv2.PutText(m_DstMat, label, xy, 0, 0.5, s2);

            Cv2.ImShow("Result", m_DstMat);
            Cv2.WaitKey(0);


        }



    }
}

至此结束!本来想分分让其更好看一些,太忙了,小伙伴们有空可以封装一下。欢迎互相交流。附送一张图(●'◡'●)!!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
一、主要内容:OpenCV能够实现强大丰富的图像处理,但是它缺少一个能够支持它运行的界面。Csharp经过多年的发展,得益于它的“所见及所得”能力,非常方便编写界面。这两者如果能够“双剑合璧”,将有效帮助实际工作产出。本课着重推荐GOCW采用“Csharp基于CLR直接调用Opencv编写的算法库”方法,能够将最新的OpenCV技术引入进来,同时保证生成程序的最小化。    为了进一步说明Csharp和OpenCV的结合使用,首先一个较为完整的基于winform实现答题卡识别的例子,相比较之前的实现,本次进一步贴近生产实际、内涵丰富,对算法也进行了进一步提炼。同时我们对WPF下对OpenCV函数的调用OpenCV.js的调用进行相关教授。       二、课程结构1、 EmguCV、OpenCVSharp和GOCW之间进行比较(方便代码编写、能够融入最新的算法、速度有保障、方便调试找错、拒绝黑箱化);2、视频采集模块的构建,视频采集和图像处理之间的关系;3、视频采集专用的SDK和“陪练”系统的介绍;4、在视频增强类项目中和图像处理项目中,算法的选择;5、Csharp界面设计、图片的存储和其他构建设计;6、较为完整的答题卡识别例子,兼顾界面设计和算法分析;8、WPF基于GOCW也同样可以基于GOCW实现算法调用;webForm虽然也可以通过类似方法调用,但是OpenCV.JS的方法更现代高效。9、关于软件部署的相关要点和窍门。       三、知识要点:1、基本环境构建和程序框架;2、CLR基本原理和应用方法;3、接入、采集、模拟输入;4、图像处理,通过构建循环采集图片;5、增强和实时处理;6、基于投影等技术的答题卡识别算法;7、存储、转换;8、部署交付。        课程能够帮助你掌握Csharp调用Opencv的基本方法,获得相应框架代码和指导;从而进一步提升实现“基于图像处理”的解决方案能力。  
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值