在前面出现的融合方法中,最突出的问题就是每次运算,都需要将整个推断的过程全部操作一遍,这样肯定是费时间的——所以我们需要将能够独立的地方独立出来,但是这个过中非常容易出现溢出的错误——经过一段时间的尝试,终于得到了相对稳定的结果,这里将结果记录下来:

1、原始状态:
    我们已经将算法融合到了MFC中,并且能够发挥作用:
// 用于推断的函数
Mat CGOMfcTemplate2Dlg::IEInfer(Mat m_mainframe)
{
    //初始化IE
    // --------------------------- 1.为IE准备插件-------------------------------------
    InferencePlugin plugin(PluginDispatcher().getSuitablePlugin(TargetDevice::eCPU));
    plugin.AddExtension(std::make_shared<Extensions::Cpu::CpuExtensions>());//Extension,useful
    // --------------------------- 2.读取IR模型(xml和bin)---------------------------------
    CNNNetReader networkReader;
    networkReader.ReadNetwork("./road-segmentation-adas-0001.xml");
    networkReader.ReadWeights("./road-segmentation-adas-0001.bin");
    CNNNetwork network = networkReader.getNetwork();
    // --------------------------- 3. 准备输入输出的------------------------------------------
    InputsDataMap inputInfo(network.getInputsInfo());//获得输入信息
    if (inputInfo.size() != 1) throw std::logic_error("错误,该模型应该为单输入");
    auto lrInputInfoItem = inputInfo["data"]; //开始读入
    int w = static_cast<int>(lrInputInfoItem->getTensorDesc().getDims()[3]); //模型要求的输入大小
    int h = static_cast<int>(lrInputInfoItem->getTensorDesc().getDims()[2]);
    network.setBatchSize(1);//只有1副图片,故BatchSize = 1
   //准备输出数据
    OutputsDataMap outputInfo(network.getOutputsInfo());//获得输出信息                                      
    std::string firstOutputName;
    for (auto &item : outputInfo) {
        if (firstOutputName.empty()) {
            firstOutputName = item.first;
        }
        DataPtr outputData = item.second;
        if (!outputData) {
            throw std::logic_error("错误的格式,请检查!");
        }
        item.second->setPrecision(Precision::FP32);
    }
    // --------------------------- 4. 读取模型 ------------------------------------------(目视第4步骤最消耗时间)
    ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
    // --------------------------- 5. 创建推断 -------------------------------------------------
    infer_request = executableNetwork.CreateInferRequest();
    // --------------------------- 6. 将数据塞入模型 -------------------------------------------------
    Blob::Ptr lrInputBlob = infer_request.GetBlob("data"); //data这个名字是我看出来的,实际上这里可以更统一一些
    matU8ToBlob<float_t>(m_mainframe, lrInputBlob, 0);//重要的转换函数,第3个参数是batchSize,应该是自己+1的
    // --------------------------- 7. 推断结果 -------------------------------------------------
    infer_request.Infer();//多张图片多次推断
    // --------------------------- 8. 处理结果-------------------------------------------------------
    const Blob::Ptr outputBlob = infer_request.GetBlob(firstOutputName);
    const auto outputData = outputBlob->buffer().as<PrecisionTrait<Precision::FP32>::value_type*>();
    size_t numOfImages = outputBlob->getTensorDesc().getDims()[0];
    size_t numOfChannels = outputBlob->getTensorDesc().getDims()[1];
    h = outputBlob->getTensorDesc().getDims()[2];
    w = outputBlob->getTensorDesc().getDims()[3];
    size_t nunOfPixels = w * h; //写在内存里的结果,还是要拼出来的
    std::vector<cv::Mat> imgPlanes{ cv::Mat(h, w, CV_32FC1, &(outputData[0])),
                                   cv::Mat(h, w, CV_32FC1, &(outputData[nunOfPixels])),
                                   cv::Mat(h, w, CV_32FC1, &(outputData[nunOfPixels * 2])) };
    for (auto & img : imgPlanes) //本来是平的
        img.convertTo(img, CV_8UC1, 255);
    cv::Mat resultImg;
    cv::merge(imgPlanes, resultImg);
    return resultImg;
}

    这样一段代码,包含了1-8全部8个步骤,可以在具体的情况下被触发(比如按下某个按键)
    需要注意,运行代码之后再正常退出,会报这样一个错误,可能是和系统某种资源没有销毁相关。
2、初步设想:
    但是这样非常低效,所以要提高效率。经过分析研究,最为消耗时间的一步为
 // --------------------------- 4. 读取模型 ------------------------------------------(目视第4步骤最消耗时间)
    ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
    所以希望能够将这步前调到Oninitdialog中,这样每次运行过程中,针对不同输入,只需要运行
    // --------------------------- 7. 推断结果 -------------------------------------------------

infer_request.Infer();//多张图片多次推断

    然后将后面的结果进行显示就可以了。
3、容易出错:
    
简单的想法是直接将executableNetwork变成全局变量,并且在initdialog中申明完成,以为这样就能够将耗时的操作解决在init阶段。
但是非常常见的方法是这个。
4、解决方法:
       实际上我没有专门想出一个什么方法解决这个问题,我做了较多实验,不断去验证设想,最后发现这个方法能够达到目标。
        将前面的1-4步分解为以下函数(通过这个过程,发现原来代码里面一些不需要的部分):

CNNNetwork CGOMfcTemplate2Dlg::IENetWork(string strXML, string strBIN)
{
    CNNNetReader networkReader;
    networkReader.ReadNetwork(strXML);
    networkReader.ReadWeights(strBIN);
    CNNNetwork network = networkReader.getNetwork();
    return network;
}
string CGOMfcTemplate2Dlg::IENetSetup(CNNNetwork network)
{
    InputsDataMap inputInfo(network.getInputsInfo());//获得输入信息
    BlobMap inputBlobs; //保持所有输入的blob数据
    if (inputInfo.size() != 1) throw std::logic_error("错误,该模型应该为单输入");
    auto lrInputInfoItem = inputInfo["data"]; //开始读入
    int h = static_cast<int>(lrInputInfoItem->getTensorDesc().getDims()[2]);
    int w = static_cast<int>(lrInputInfoItem->getTensorDesc().getDims()[3]); //模型要求的输入大小
    network.setBatchSize(1);//只有1副图片,故BatchSize = 1
    //准备输出数据
    OutputsDataMap outputInfo(network.getOutputsInfo());//获得输出信息                                      
    std::string firstOutputName;
    for (auto &item : outputInfo) {
        if (firstOutputName.empty()) {
            firstOutputName = item.first;
        }
        DataPtr outputData = item.second;
        if (!outputData) {
            throw std::logic_error("错误的格式,请检查!");
        }
        item.second->setPrecision(Precision::FP32);
    }
    return firstOutputName;
}
InferencePlugin CGOMfcTemplate2Dlg::IEplugin(CNNNetwork network)
{
    InferencePlugin plugin(PluginDispatcher().getSuitablePlugin(TargetDevice::eCPU));
    plugin.AddExtension(std::make_shared<Extensions::Cpu::CpuExtensions>());//Extension,useful
    return plugin;
}
ExecutableNetwork CGOMfcTemplate2Dlg::getNetWork(InferencePlugin plugin, CNNNetwork network)
{
    ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
    return executableNetwork;
}

而后分别在oninitdialog和业务代码中这样执行

std::string firstOutputName = IENetSetup(network);
        InferRequest infer_request = executableNetwork.CreateInferRequest();
        Blob::Ptr lrInputBlob = infer_request.GetBlob("data");
        matU8ToBlob<float_t>(m_mainframe, lrInputBlob, 0);//重要的转换函数,第3个参数是batchSize,应该是自己+1的
        // ---------------------------推断结果 -------------------------------------------------
        infer_request.Infer();//多张图片多次推断
        // ---------------------------处理结果-------------------------------------------------------
        const Blob::Ptr outputBlob = infer_request.GetBlob(firstOutputName);
        const auto outputData = outputBlob->buffer().as<PrecisionTrait<Precision::FP32>::value_type*>();
        size_t numOfImages = outputBlob->getTensorDesc().getDims()[0];
        size_t numOfChannels = outputBlob->getTensorDesc().getDims()[1];
        int h = outputBlob->getTensorDesc().getDims()[2];
        int w = outputBlob->getTensorDesc().getDims()[3];
        size_t nunOfPixels = w * h; //写在内存里的结果,还是要拼出来的
        std::vector<cv::Mat> imgPlanes{ cv::Mat(h, w, CV_32FC1, &(outputData[0])),
                                       cv::Mat(h, w, CV_32FC1, &(outputData[nunOfPixels])),
                                       cv::Mat(h, w, CV_32FC1, &(outputData[nunOfPixels * 2])) };
        for (auto & img : imgPlanes) //本来是平的
            img.convertTo(img, CV_8UC1, 255);
        cv::Mat resultImg;
        cv::merge(imgPlanes, resultImg);
        showImage(resultImg, IDC_PIC); //显示原始图像

这个结果,的确是提高了运算的效率。

并且能够直接嵌入摄像头循环:

//摄像头显示循环,所有关于采集的操作是通过主线程传递控制变量到采集线程,而后由采集线程完成的
DWORD WINAPI CaptureThread(LPVOID lpParameter)
{
    CGOMfcTemplate2Dlg* pDlg = (CGOMfcTemplate2Dlg*)lpParameter;
    double t_start = (double)cv::getTickCount(); //开始时间
    Mat tmpPrydown;
    //#pragma omp parallel for
    while (true)
    {
        if (pDlg->b_closeCam)//退出循环
            break;
        double t  = ((double)cv::getTickCount() - t_start) / getTickFrequency();
        if (t <= 0.1)//fps =10,主动降低速度
        {
            Sleep(100);
            continue;
        }
        else
        {
            t_start = (double)cv::getTickCount();
        }
        //从directX中获得当前图像并显示出来
        IplImage* queryframe  = pDlg->cameraDs.QueryFrame();
        //在2.0版本中可以强转,在3.0中需要使用函数
        Mat camframe = cvarrToMat(queryframe);
        pDlg->showImage(camframe, IDC_CAM); //显示原始图像
        ////根据条件,决定是否采用算法
        Mat dst;
        Mat img;
        Mat tmp;
        Mat divideGaussMin;
        Mat divideGaussMiddle;
        Mat divideGaussMax;
        cvtColor(camframe, img, COLOR_BGR2GRAY);
        cvtColor(img, img, COLOR_GRAY2BGR);
        if (pDlg->bMethod) //这里实现的是灰度转彩色
        {
            //算法
            if (img.empty())
            {
                return -1;
            }
            std::string firstOutputName = pDlg->IENetSetup(pDlg->network);
            InferRequest infer_request = pDlg->executableNetwork.CreateInferRequest();
            Blob::Ptr lrInputBlob = infer_request.GetBlob("data");
            matU8ToBlob<float_t>(img, lrInputBlob, 0);//重要的转换函数,第3个参数是batchSize,应该是自己+1的
            // ---------------------------推断结果 -------------------------------------------------
            infer_request.Infer();//多张图片多次推断
            // ---------------------------处理结果-------------------------------------------------------
            const Blob::Ptr outputBlob = infer_request.GetBlob(firstOutputName);
            const auto outputData = outputBlob->buffer().as<PrecisionTrait<Precision::FP32>::value_type*>();
            size_t numOfImages = outputBlob->getTensorDesc().getDims()[0];
            size_t numOfChannels = outputBlob->getTensorDesc().getDims()[1];
            int h = outputBlob->getTensorDesc().getDims()[2];
            int w = outputBlob->getTensorDesc().getDims()[3];
            size_t nunOfPixels = w * h; //写在内存里的结果,还是要拼出来的
            std::vector<cv::Mat> imgPlanes{ cv::Mat(h, w, CV_32FC1, &(outputData[0])),
                                           cv::Mat(h, w, CV_32FC1, &(outputData[nunOfPixels])),
                                           cv::Mat(h, w, CV_32FC1, &(outputData[nunOfPixels * 2])) };
            for (auto & img : imgPlanes) //本来是平的
                img.convertTo(img, CV_8UC1, 255);
            cv::merge(imgPlanes, dst);
        }
        else
        {
            dst = img.clone();
        }
        pDlg->showImage(dst, IDC_PIC); //显示网络处理图像
    }
    return 0;
}

    最后的结果是实时效果。那么这里的东西是可以复用的。
5、小结反思。
    得到最后这个结果比较满意,这也是不断尝试的结果。问题产生的原因可能是多方面的,目前也只是得到了基本的解决方法;更系统的方法应该是类化,这个会在后面处理级联问题的时候遇到;而我这里总结出来的函数化的方法,对于解决单模型简单问题,应该已经是可用的了。
    能够看到这里的,一定是遇到了类似问题的同事,那也是对相关问题有较为深入研究的了。
    感谢阅读至此,希望有所帮助。

附件列表

[E2E_L9]GOMFCTemplate的融合进阶的更多相关文章

  1. [E2E_L8_1]segmentation_demo道路分割例子和GOMFCTemplate的初步融合

    一.来源 模型例子自己带来副图像     二.简化   #include <algorithm> #include <fstream> #include <iomanip ...

  2. (E2E_L2)GOMfcTemplate在vs2017上的运行并融合Dnn模块

    GOMfcTemplate一直运行在VS2012上运行的,并且开发出来了多个产品.在技术不断发展的过程中,出现了一些新的矛盾:1.由于需要使用DNN模块,而这个模块到了4.0以上的OpenCV才支持的 ...

  3. [BZOI2014]大融合——————线段树进阶

    竟然改了不到一小时就改出来了, 可喜可贺 Description Solution 一开始想的是边两侧简单路径之和的乘积,之后发现这是个树形结构,简单路径数就是节点数. 之后的难点就变成了如何求线段树 ...

  4. C#进阶系列——WebApi 接口参数不再困惑:传参详解

    前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路.本 ...

  5. NLP系列(4)_朴素贝叶斯实战与进阶

    作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/50629608 htt ...

  6. Ionic APP-Web SPA开发进阶(一)AngularJS全栈工程狮进阶

    AngularJS全栈工程狮进阶 前言 学习了一段时间AngularJS,开始接触移动端APP开发.为了响应公司开发需求,采用"Hybrid"混血开发方法.采用Ionic前端框架, ...

  7. 【进阶3-3期】深度广度解析 call 和 apply 原理、使用场景及实现(转)

    这是我在公众号(高级前端进阶)看到的文章,现在做笔记  https://github.com/yygmind/blog/issues/22 call() 和 apply() call() 方法调用一个 ...

  8. Apollo 1 融合 Spring 的三个入口

    前言 Spring 作为 Java 世界非官方标准框架,任何一个中间件想要得到良好的发展,必须完美支持 Spring 的各种特性,即:无缝融入 Spring. Apollo 作为分布式配置中心,服务于 ...

  9. Scala进阶之路-为什么要学习Scala以及开发环境搭建

    Scala进阶之路-为什么要学习Scala以及开发环境搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 最近人工智能和大数据那是相当的火呀,人工智能带动了Python的流行,区块 ...

随机推荐

  1. composer的用法笔记

    一.到compose官网下载 composer.exe 的安装的文件,直接打开安装,在安装的目录的要选择到,你的开发环境中的 php.exe 的所在目录里..例如:D:\phpStudy\php\ph ...

  2. SWD烧录/仿真方式

    单片机在烧写/仿真的时候具有一种方式叫做SWD,这种方式只用到两根线SWDIO,SWCLK.一般SWD和JTAG中的JTMS和JTCK共用的.由于线少,所以使用非常方便,但是速率相对较低. 在接线时, ...

  3. 业余时间折腾了个微信小程序版本的街机游戏模拟器(吾爱街机),8090后的童年回忆,欢迎大家体验

    好多年没来博客园了,有段时间想玩街机游戏,发现都需要下载安装,现在小程序这么流行,是不是可以集成到小程序里(无需下载,在线玩),出于这想法,就业余时间折腾了下,分享给大家,偶尔可以回味畅玩下. 中间遇 ...

  4. idea 使用在java 包下的ftl、xml 文件编译问题

    问题 使用ftl 时报错出现ftl 文件找不到,后发现idea未编译java 下的ftl文件 解决方法一 手动编译,复制ftl的文件夹在classes下应该在的地方 解决方法二 pom.xml中加入 ...

  5. Maven模块化搭建总结

    1.Maven插件在eclipse的安装 windows——>preferences——>Maven——>installations——>add——>installati ...

  6. apscheduler 执行报错No handlers could be found for logger "apscheduler.executors.default

    执行报错如下: No handlers could be found for logger "apscheduler.executors.default 解决: 加入日志,查看具体报错,载根 ...

  7. Yii集成PHPWord

    一.安装 1.下载composer curl -sS https://getcomposer.org/installer | php 将composer.phar文件移动到bin目录以便全局使用com ...

  8. 深入理解JVM内存分配和常量池

    一.虚拟机的构成 虚拟结主要由运行时数据区.执行引擎.类加载器三者构成: 而我们所说的JVM内存模型指的就是运行时数据区,下面具体分析一下运行时数据区: 二.运行时数据区组成和各个区域的作用 我们看到 ...

  9. C++中字符数组和字符指针问题

    环境:vs2010 说明:在阅读这部分内容之前应该先明确C++内存分配问题 ,那一篇文章说的比较清楚. 1.字符数组,初始化: char str1[]="abc"; char st ...

  10. Codeforces1114C Trailing Loves (or L'oeufs?)

    链接:http://codeforces.com/problemset/problem/1114/C 题意:给定数字$n$和$b$,问$n!$在$b$进制下有多少后导零. 寒假好像写过这道题当时好像完 ...