zoukankan      html  css  js  c++  java
  • 基于OpenCV的图像处理程序选择什么工具编写界面?—关于QTMFCCSharp的选择以及GOCW的介绍

            基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题。对于c++语系的程序员来说,一般来说有QT/MFC两种考虑。QT的确功能强大,特别是QML编写android界面很有一套(https://www.cnblogs.com/jsxyhelu/p/8286476.html),在树莓派上进行设计也很方便(https://www.cnblogs.com/jsxyhelu/p/7839062.html);但是使用QT的一个现实问题就是和现有平台的结合,比如客户需要将结果导出到excel中,使用QT就比较别扭(当然不是说不可以)。所以现在我一般这样来做:对于Android和PI,或者需要在Linux上运行的项目,使用QT编写界面,调用Opencv函数;对于需要在windows上运行的项目,使用MFC编写界面,直接就可以引用OpenCV。
            有人会吐槽MFC使用起来非常麻烦,这点我非常同意。但MFC经过这么多年的发展,今日仍有活力,并且短时间内不会消失。因为相比较其他一些所见即所得的语言和环境来说(QT/Csharp),mfc的消息映射机制和坐标体系等,的确有它的优势,对于图像处理程序来说尤其如此;加以积累,能够快速做出很多专业的东西;近期出现的ribbon界面也为mfc加分不少(https://www.cnblogs.com/jsxyhelu/p/9209052.html
           选择了MFC这个方向,思考图像处理程序问题,一般来说分为“处理图像”和"处理视频"两类:对于图像处理来说,我提供的GOPaint框架(https://www.cnblogs.com/jsxyhelu/p/6440910.html)能够提供一个基本的静态图像处理框架;而GOMFCTemplate2(https://www.cnblogs.com/jsxyhelu/p/GOMFCTemplate2.html)则适合用来处理视频。这两种都分别成功运用于多种视频处理项目中。
           但是这里我想更进一步:希望能够用Csharp编写界面,因为它更好用;但是又不想引入EmguCV类似的库,因为里面很多东西不是我需要的。那么最直接的方法就是使用Csharp调用基于Opencv编写的类库文件(Dll)的,我取名叫做GreenOpenCsharpWarper(GOCW)
           经过比较长时间的探索研究,目前的GOCW已经可以直接以函数的形式在内存中传递bitmap和Mat对象,达到了函数级别的应用。因为这里涉及到托管代码编写,也就是CLR程序编写,所以有比较复杂的地方;为了展现GOCW的优良特性,我编写实现GOGPY项目,也就是一个"Csharp编写界面,OpenCV实现算法的实时视频处理程序”,相关细节都包含其中。之所以叫“GPY”,是采集硬件这块,我采用了成像质量较好的高拍仪设备(GaoPaiYi)。
           这里简单将最核心内容进行讲解。GOCW的核心问题,无非就是基于CLR之上的两个方向的数据流转换。核心函数为
    Bitmap^  GOClrClass::testMethod(cli::array<unsigned char>^ pCBuf1)
    {
        pin_ptr<System::Byte> p1 = &pCBuf1[0];
        unsigned char* pby1 = p1;
        cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);
        cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);//获得数据到img_object中去
        //////////////////////////////////处理过程///////////////////////////////////////
        cvtColor(img_object,img_object,40);
        
        /////////////////////////////////////////////////////////////////////////////////
        Bitmap^ bb = MatToBitmap(img_object);
        if (!img_object.data)
            return nullptr;
        std::vector<uchar> buf;
        cv::imencode(".jpg", img_object, buf);
        return bb;
    }
    以及
    System::Drawing::Bitmap^ MatToBitmap(const cv::Mat& img)
    {
        if (img.type() != CV_8UC3)
        {
            throw gcnew NotSupportedException("Only images of type CV_8UC3 are supported for conversion to Bitmap");
        }
        //create the bitmap and get the pointer to the data
        PixelFormat fmt(PixelFormat::Format24bppRgb);
        Bitmap ^bmpimg = gcnew Bitmap(img.cols, img.rows, fmt);
        BitmapData ^data = bmpimg->LockBits(System::Drawing::Rectangle(00, img.cols, img.rows), ImageLockMode::WriteOnly, fmt);
        //byte *dstData = reinterpret_cast<byte*>(data->Scan0.ToPointer());
        Byte *dstData = reinterpret_cast<Byte*>(data->Scan0.ToPointer());
        unsigned char *srcData = img.data;
        for (int row = 0; row < data->Height; ++row)
        {
            memcpy(reinterpret_cast<void*>(&dstData[row*data->Stride]), reinterpret_cast<void*>(&srcData[row*img.step]), img.cols*img.channels());
        }
        bmpimg->UnlockBits(data);
        return bmpimg;
    }
     
    而在chsarp中,直接
    Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
    // If the image is upsidedown
    b.RotateFlip(RotateFlipType.RotateNoneFlipY);
    srcImage = b;
    if (picPreview.Image != null)
        picPreview.Image.Dispose();
    //调用clr+opencv图像处理模块
    MemoryStream ms = new MemoryStream();
    b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
    byte[] bytes = ms.GetBuffer();
    Bitmap bitmap = client.testMethod(bytes);
    就可以调用,并且获得结果。
     
    以下内容为2017年更新的内容,适当参考:
    一、CLR编写的DLL部分
    1、按照正常方法引入Opencv;
    2、提供接口函数,进行图像处理(这里只是实现了cvtColor,实际过程中可以用自己编写的复杂函数)
    String^  Class1::Method(cli::array<unsigned char>^ pCBuf1)
    {
         pin_ptr<System::Byte> p1 = &pCBuf1[0];
         unsigned char* pby1 = p1;
         cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);
         cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);
         //////////////////////////////////处理过程/////////
         cvtColor(img_object,img_object,40);
         /////////////////////////////////////////////////////////////////////////////////
         if (!img_object.data)
            return nullptr;
         //获得目录,保存文件
         cv::imwrite("c:/Method.jpg",img_object);
         return "c:/Method.jpg";
    }
     
    String^  Class1::Method2(cli::array<unsigned char>^ pCBuf1)
    {
        pin_ptr<System::Byte> p1 = &pCBuf1[0];
        unsigned char* pby1 = p1;
        cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);
        cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);
        //////////////////////////////////处理过程///////////////////////
        cvtColor(img_object,img_object,6);
     /////////////////////////////////////////////////////////////////////////////////
        if (!img_object.data)
            return nullptr;
        //获得目录,保存文件
        cv::imwrite("c:/Method2.jpg",img_object);
        return "c:/Method2.jpg";
    }
    二、Winform调用接口部分(TIP:不仅可以用Winform调用,asp.net/webservice都是可以调用的)
    1、直接引用clr dll
    2、编写helper文件(应该也可以叫做 warpper),通过外部IO的方法获取clr dll的文件
     class GOCsharpHelper
        {
            Class1 client = new Class1();
            string strResult1 = null;
            string strResult2 = null;
            //输入参数是string或bitmap
            public Bitmap ImageProcess(string ImagePath){
                Image  ImageTemp = Bitmap.FromFile(ImagePath);
                return ImageProcess(ImageTemp);
            }
            //输出结果是bitmap
            public Bitmap ImageProcess(Image image)
            {
                MemoryStream ms = new MemoryStream();
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                byte[] bytes = ms.GetBuffer();
                strResult1 = client.Method(bytes);
                Image ImageResult = Bitmap.FromFile(strResult1);
                return (Bitmap)ImageResult;
            }
            public Bitmap ImageProcess2(string ImagePath)
            {
                Image ImageTemp = Bitmap.FromFile(ImagePath);
                return ImageProcess2(ImageTemp);
            }
            //输出结果是bitmap
            public Bitmap ImageProcess2(Image image)
            {
                MemoryStream ms = new MemoryStream();
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                byte[] bytes = ms.GetBuffer();
                strResult2 = client.Method2(bytes);
                Image ImageResult = Bitmap.FromFile(strResult2);
                return (Bitmap)ImageResult;
            }
            public void Clear()
            {
                if (File.Exists(strResult1))
                    File.Delete(strResult1);
                if (File.Exists(strResult2))
                    File.Delete(strResult2);
            }
        }
    3、使用例子(注意控件的dispose):
     
       private void button2_Click(object sender, EventArgs e)
            {
                if (pictureBox1.Image != null)
                    pictureBox1.Image.Dispose();
                if (pictureBox2.Image != null)
                    pictureBox2.Image.Dispose();
               Image image1 = gocsharphelper.ImageProcess(" E:/sandbox/logo.jpg");
               pictureBox1.Image = image1;
               Image image2 = gocsharphelper.ImageProcess2("E:/sandbox/lena.jpg");
               pictureBox2.Image = image2;
             
            }
     
    三、解释说明 
    使用外部I/O不仅仅是权宜之计,实际上Opencv的Decode使用的就是外部I/O。就目前研究的水平来说,这是最稳定的。
    目前搭建成功的框架已经能够完成“csharp调用opencv的”目标,并且在调试、参数传递方面都很强。
    如果是处理静态图片,已经够用。
    四、杀手程序
    GOImageResearch:
    使用这种方法编写的图像处理预分析程序。
    、程序调试
    在使用这个框架的过程中,有网友反馈
    clr怎么调试啊,在clr工程中相关的数据全是无效的,怎么看呢,不能保证写的图像算法完全正确啊……
    那么clr肯定是可以调试,出现这个问题的原因是没有掌握相关调试技巧。这里是相关解决方法:
     
     
     
     
     
    2019年8月30日22:50:18 更新
    主要是添加了OpenCVDNN模块,将代码升级到2017版本,并解决细节问题,现在应该说处理静态图片,那是相当好的了。
    d
     





    附件列表

  • 相关阅读:
    EF6学习
    jQuery中each的用法之退出循环和结束本次循环
    Convert.ToInt16(s);int.Parse(s);和(int)s的区别
    .net网站部署winserver2008R2 iis浏览只显示目录浏览
    二维数组按某列排序
    XML文件的操作
    .net中 IOC DI
    .net在Oracle数据库中为In条件查询防止sql注入参数化处理
    测试代码耗时的时间段(.net)
    沙箱测试
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/11437489.html
Copyright © 2011-2022 走看看