一、多车辆识别可能和车辆车牌分割;

这样一张图,可以识别多车辆和车牌,问题是如何区分并且配对。
 0
 1
 7
 8
是否是车牌可以通过图片的大小进行判断。而配对是前后顺序的。
// --------------------------- 8. 处理结果-------------------------------------------------------
    const float *detections = infer_request.GetBlob(firstOutputName)->buffer().as<float *>();
    int i_car = 0;
    int i_plate = 0;
    for (int i = 0; i < 200; i++)
    {
        float confidence = detections[i * objectSize + 2];
        float x_min = static_cast<int>(detections[i * objectSize + 3] * src.cols);
        float y_min = static_cast<int>(detections[i * objectSize + 4] * src.rows);
        float x_max = static_cast<int>(detections[i * objectSize + 5] * src.cols);
        float y_max = static_cast<int>(detections[i * objectSize + 6] * src.rows);
        Rect rect = cv::Rect(cv::Point(x_min, y_min), cv::Point(x_max, y_max));
        if (confidence > 0.5)
        {
            if (rect.width > 150)//车辆
            {
                char cbuf[255];
                sprintf_s(cbuf, "E:/OpenVINO_modelZoo/car_%d.jpg", i_car);
                Mat roi = src(rect);
                imwrite(cbuf, roi);
                cv::rectangle(src, rect, cv::Scalar(255, 255, 255));
                i_car++;
            }
            else//车牌
            {
                char cbuf[255];
                sprintf_s(cbuf, "E:/OpenVINO_modelZoo/plant_%d.jpg", i_plate);
                Mat roi = src(rect);
                imwrite(cbuf, roi);
                cv::rectangle(src, rect, cv::Scalar(0, 0, 255));
                i_plate++;
            }
        
        }

}

这种处理的方法,后面应该还是要用的
二、函数化封装和合并;
以下是原始代码
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <vector>
#include <string>
#include <chrono>
#include <memory>
#include <utility>

#include <format_reader_ptr.h>
#include <inference_engine.hpp>
#include <ext_list.hpp>

#include <samples/slog.hpp>
#include <samples/ocv_common.hpp>
#include "segmentation_demo.h"

using namespace InferenceEngine;
using namespace std;
using namespace cv;

//从图片中获得车和车牌(这里没有输出模型的定位结果,如果需要可以适当修改)
vector< pair<Mat, Mat> > GetCarAndPlate(Mat src)
{
    vector<pair<Mat, Mat>> resultVector;
    // 模型准备
    InferencePlugin plugin(PluginDispatcher().getSuitablePlugin(TargetDevice::eCPU));
    plugin.AddExtension(std::make_shared<Extensions::Cpu::CpuExtensions>());//Extension,useful
    //读取模型(xml和bin
    CNNNetReader networkReader;
    networkReader.ReadNetwork("E:/OpenVINO_modelZoo/vehicle-license-plate-detection-barrier-0106.xml");
    networkReader.ReadWeights("E:/OpenVINO_modelZoo/vehicle-license-plate-detection-barrier-0106.bin");
    CNNNetwork network = networkReader.getNetwork();
    network.setBatchSize(1);
    // 输入输出准备
    InputsDataMap inputInfo(network.getInputsInfo());//获得输入信息
    if (inputInfo.size() != 1) throw std::logic_error("错误,该模型应该为单输入");
    string inputName = inputInfo.begin()->first;

    OutputsDataMap outputInfo(network.getOutputsInfo());//获得输出信息                                      
    DataPtr& _output = outputInfo.begin()->second;
    const SizeVector outputDims = _output->getTensorDesc().getDims();
    string firstOutputName = outputInfo.begin()->first;
    int maxProposalCount = outputDims[2];
    int objectSize = outputDims[3];
    if (objectSize != 7) {
        throw std::logic_error("Output should have 7 as a last dimension");
    }
    if (outputDims.size() != 4) {
        throw std::logic_error("Incorrect output dimensions for SSD");
    }
    _output->setPrecision(Precision::FP32);
    _output->setLayout(Layout::NCHW);

    // 模型读取和推断
    ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
    InferRequest infer_request = executableNetwork.CreateInferRequest();

    Blob::Ptr lrInputBlob = infer_request.GetBlob(inputName); //data这个名字是我看出来的,实际上这里可以更统一一些
    matU8ToBlob<float_t>(src, lrInputBlob, 0);//重要的转换函数,第3个参数是batchSize,应该是自己+1的

    infer_request.Infer();
    // --------------------------- 8. 处理结果-------------------------------------------------------
    const float *detections = infer_request.GetBlob(firstOutputName)->buffer().as<float *>();
    int i_car = 0;
    int i_plate = 0;
    for (int i = 0; i < 200; i++)
    {
        float confidence = detections[i * objectSize + 2];
        float x_min = static_cast<int>(detections[i * objectSize + 3] * src.cols);
        float y_min = static_cast<int>(detections[i * objectSize + 4] * src.rows);
        float x_max = static_cast<int>(detections[i * objectSize + 5] * src.cols);
        float y_max = static_cast<int>(detections[i * objectSize + 6] * src.rows);
        Rect rect = cv::Rect(cv::Point(x_min, y_min), cv::Point(x_max, y_max));
        if (confidence > 0.5)
        {
            if (rect.width > 150)//车辆
            {
                Mat roi = src(rect);
                pair<Mat, Mat> aPair;
                aPair.first = roi.clone();
                resultVector.push_back(aPair);
                i_car++;
            }
            else//车牌
            {
                Mat roi = src(rect);
                resultVector[i_plate].second = roi.clone();
                i_plate++;
            }

        }
    }
    return resultVector;
}
//从车的图片中识别车型
pair<string,string> GetCarAttributes(Mat src)
{
    pair<string, string> resultPair;
    // --------------------------- 1.为IE准备插件-------------------------------------
    InferencePlugin plugin(PluginDispatcher().getSuitablePlugin(TargetDevice::eCPU));
    printPluginVersion(plugin, std::cout);//正确回显表示成功
    plugin.AddExtension(std::make_shared<Extensions::Cpu::CpuExtensions>());//Extension,useful
    // --------------------------- 2.读取IR模型(xml和bin)---------------------------------
    CNNNetReader networkReader;
    networkReader.ReadNetwork("E:/OpenVINO_modelZoo/vehicle-attributes-recognition-barrier-0039.xml");
    networkReader.ReadWeights("E:/OpenVINO_modelZoo/vehicle-attributes-recognition-barrier-0039.bin");
    CNNNetwork network = networkReader.getNetwork();
    // --------------------------- 3. 准备输入输出的------------------------------------------
    InputsDataMap inputInfo(network.getInputsInfo());//获得输入信息
    BlobMap inputBlobs; //保持所有输入的blob数据
    if (inputInfo.size() != 1) throw std::logic_error("错误,该模型应该为单输入");

    auto lrInputInfoItem = *inputInfo.begin();//开始读入
    int w = static_cast<int>(lrInputInfoItem.second->getTensorDesc().getDims()[3]); //这种写法也是可以的,它的first就是data
    int h = static_cast<int>(lrInputInfoItem.second->getTensorDesc().getDims()[2]);   
    network.setBatchSize(1);//只有1副图片,故BatchSize = 1
    // --------------------------- 4. 读取模型 ------------------------------------------(后面这些操作应该可以合并了)
    ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
    // --------------------------- 5. 创建推断 -------------------------------------------------
    InferRequest infer_request = executableNetwork.CreateInferRequest();
    // --------------------------- 6. 将数据塞入模型 -------------------------------------------------
    Blob::Ptr lrInputBlob = infer_request.GetBlob("input"); //data这个名字是我看出来的,实际上这里可以更统一一些
    matU8ToBlob<float_t>(src, lrInputBlob, 0);//重要的转换函数,第3个参数是batchSize,应该是自己+1的

    // --------------------------- 7. 推断结果 -------------------------------------------------
    infer_request.Infer();//多张图片多次推断

    // --------------------------- 8. 处理结果-------------------------------------------------------
     // 7 possible colors for each vehicle and we should select the one with the maximum probability
    auto colorsValues = infer_request.GetBlob("color")->buffer().as<float*>();
    // 4 possible types for each vehicle and we should select the one with the maximum probability
    auto typesValues = infer_request.GetBlob("type")->buffer().as<float*>();

    const auto color_id = std::max_element(colorsValues, colorsValues + 7) - colorsValues;
    const auto type_id = std::max_element(typesValues, typesValues + 4) - typesValues;

    static const std::string colors[] = {
             "white", "gray", "yellow", "red", "green", "blue", "black"
    };
    static const std::string types[] = {
            "car", "bus", "truck", "van"
    };

    resultPair.first = colors[color_id];
    resultPair.second = types[type_id];

    return resultPair;

}
//识别车牌
string GetPlateNumber(Mat src)
{
    // --------------------------- 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("E:/OpenVINO_modelZoo/license-plate-recognition-barrier-0001.xml");
    networkReader.ReadWeights("E:/OpenVINO_modelZoo/license-plate-recognition-barrier-0001.bin");
    CNNNetwork network = networkReader.getNetwork();
    network.setBatchSize(1);//只有1副图片,故BatchSize = 1
    // --------------------------- 3. 准备输入输出的------------------------------------------
    InputsDataMap inputInfo(network.getInputsInfo());//获得输入信息
    BlobMap inputBlobs; //保持所有输入的blob数据
    string    inputSeqName;

    if (inputInfo.size() == 2) {
        auto sequenceInput = (++inputInfo.begin());
        inputSeqName = sequenceInput->first;
    }
    else if (inputInfo.size() == 1) {
        inputSeqName = "";
    }
    else {
        throw std::logic_error("LPR should have 1 or 2 inputs");
    }

    InputInfo::Ptr& inputInfoFirst = inputInfo.begin()->second;
    inputInfoFirst->setInputPrecision(Precision::U8);
    string inputName = inputInfo.begin()->first;

    //准备输出数据
    OutputsDataMap outputInfo(network.getOutputsInfo());//获得输出信息             
    if (outputInfo.size() != 1) {
        throw std::logic_error("LPR should have 1 output");
    }
    string firstOutputName = outputInfo.begin()->first;

    DataPtr& _output = outputInfo.begin()->second;
    const SizeVector outputDims = _output->getTensorDesc().getDims();

    // --------------------------- 4. 读取模型 ------------------------------------------(后面这些操作应该可以合并了)
    ExecutableNetwork executableNetwork = plugin.LoadNetwork(network, {});
    // --------------------------- 5. 创建推断 -------------------------------------------------
    InferRequest infer_request = executableNetwork.CreateInferRequest();
    // --------------------------- 6. 将数据塞入模型 -------------------------------------------------
    Blob::Ptr lrInputBlob = infer_request.GetBlob(inputName); //data这个名字是我看出来的,实际上这里可以更统一一些
    matU8ToBlob<uint8_t>(src, lrInputBlob, 0);//重要的转换函数,第3个参数是batchSize,应该是自己+1的

    // --------------------------- 7. 推断结果 -------------------------------------------------
    infer_request.Infer();//多张图片多次推断
    // --------------------------- 8. 处理结果-------------------------------------------------------
    static std::vector<std::string> items = {
          "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
          "<Anhui>", "<Beijing>", "<Chongqing>", "<Fujian>",
          "<Gansu>", "<Guangdong>", "<Guangxi>", "<Guizhou>",
          "<Hainan>", "<Hebei>", "<Heilongjiang>", "<Henan>",
          "<HongKong>", "<Hubei>", "<Hunan>", "<InnerMongolia>",
          "<Jiangsu>", "<Jiangxi>", "<Jilin>", "<Liaoning>",
          "<Macau>", "<Ningxia>", "<Qinghai>", "<Shaanxi>",
          "<Shandong>", "<Shanghai>", "<Shanxi>", "<Sichuan>",
          "<Tianjin>", "<Tibet>", "<Xinjiang>", "<Yunnan>",
          "<Zhejiang>", "<police>",
          "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
          "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
          "U", "V", "W", "X", "Y", "Z"
    };

    const auto data = infer_request.GetBlob(firstOutputName)->buffer().as<float*>();
    std::string result;
    for (size_t i = 0; i < 88; i++) {
        if (data[i] == -1)
            break;
        result += items[static_cast<size_t>(data[i])];
    }
    return result;
}

void main()
{
    string imageNames = "E:/OpenVINO_modelZoo/沪A51V39.jpg";
    Mat src = imread(imageNames);
    if (src.empty())
        return;

    vector<pair<Mat, Mat>> CarAndPlateVector = GetCarAndPlate(src);
    for (int i=0;i<CarAndPlateVector.size();i++)
    {
        pair<Mat, Mat> aPair = CarAndPlateVector[i];
        pair<string, string> ColorAndType = GetCarAttributes(aPair.first);
        string PlateNumber = GetPlateNumber(aPair.second);
        cout << ColorAndType.first <<"  "<<ColorAndType.second <<"   "<< PlateNumber << endl;
    }

    cv::waitKey();

}


能够合并到这种程度是很有价值的,下一步可以思考找到更多的数据集进行训练,并且将这个结果进行转换。
从结果上来看,已经实现了级联问题,从这个层面是没有问题的;只有在具体的需求面前才可能看出问题。
我需要拓展一下车牌识别的真实需求,也许这个会成为我真正DL4CV的开始。

三、异步机制探索;
一直以来,我都为视频处理的速度问题所困扰,在“视频流”的处理过程中,必须首先获得一帧的数据,然后才能够处理这一帧的数据,并且得到增强的结果——那么最后处理的速度必然同时受到视频采集和图像处理的限制。
这可能类似于CPU中流的处理,而且据我所知,这方面的研究不仅开始很久,而且效果显著,但是苦于一直没有一个可以参考的实现。现在OpenVINO中对于视频的处理,应该说是解决燃眉之急。
OpenVINO中相关函数
使用StartAsync和Wait来实现异步操作
(Do inference by calling the InferenceEngine::InferRequest::StartAsync and InferenceEngine::InferRequest::Wait methods for asynchronous request):
infer_request->StartAsync();
infer_request.Wait(IInferRequest::WaitMode::RESULT_READY);

或者采用Infer 来实现同步操作(or by calling the InferenceEngine::InferRequest::Infer method for synchronous request):
sync_infer_request->Infer();

在同步模式下推断函数Infer会一直阻塞,直到执行结束;在异步模式下推断调用函数StartAsync会立即返回,通过检查。
对于视频分析、视频中对象检测,OpenVINO官方建议通过异步方式可以实现更快的帧率处理.
异步虽然好,但是如果仅是这样改写
则价值不大,和同步没有区分。必须建立相应的机制:
在例子中,是这样建立的:
首先是创建:
每一个检测,都包含available和pending两个部分,在创建的初期,根据FLAGS_nireq这个参数,来设定开几个available(可以理解开几个线程)
在每一个推断的开始,首先判断available是否还有,如果所有的available都已经被使用,那么就必须要开始运算
其中的
肯定就是在这个地方等待结果的;
如果avaiable还有,直接将推断送到下一个avaiable中去:
并且立刻开始推断。这样的话,就可以实现多个pending都在推断的状况。
在FLAGS_nireq被设置为1的时候
设置为3的时候
有所提高,但是不明显。
做一个4宫格
-nireq 3 -i E:/未来项目/炼数成金/(录制中)端到端/L9/道路监控数据集/1.avi E:/未来项目/炼数成金/(录制中)端到端/L9/道路监控数据集/2.avi E:/未来项目/炼数成金/(录制中)端到端/L9/道路监控数据集/1.avi E:/未来项目/炼数成金/(录制中)端到端/L9/道路监控数据集/2.avi -m  E:/OpenVINO_modelZoo/vehicle-license-plate-detection-barrier-0106.xml -m_va E:/OpenVINO_modelZoo/vehicle-attributes-recognition-barrier-0039.xml -m_lpr E:/OpenVINO_modelZoo/license-plate-recognition-barrier-0001.xml

但是为了进一步研究问题,需要具体做例子来实验。
好吧,还是有所差异的。

四、类的封装其价值
最终该机制的速度不会快于单个推断速度,我们至少可以将整个操作分为”数据准备“”数据推断“和”数据显示“3个部分。
我们需要的是打开VideoCapture的相关代码
VideoCapture capture("E:/未来项目/炼数成金/(录制中)端到端/L9/道路监控数据集/2.avi");
    Mat src;
    while (true)
    {
        if (!capture.read(src))
            break;
……

然后代码必须经过函数化(过程化无法被集成)和结构化(初始化的东西必须被独立出来,甚至可能会导致错误),参考现有例子是最方便的方式。然后对于生成的结果,我们需要做较为精确的测量。

其中有一个非常重要的“保护机制,一定要注意对这个“机制”的理解,否则很容易出现下图问题
相比较之下,正确调用产生的结果
其来源
也就是在我们调用createInferRequest的时候,会首先判断当前detection的enabled,如果这个enabled为false,则直接退出为空。
而这个定义是被写死的
它在当前Detection(比如VehicleDetection)被创建的时候产生。由于原代码中FLAGS_m是作为参数输入的,则会定义;但是我们将代码独立出来,则这个地方是没有定义的,那么久比需将其规避掉。包括,将这个FLAGS_m直接写入
和将模型调用的参数直接写入
现在回顾这里的异步机制,它之所以能够提高速度,本质上还是较好的架构,我们通过画图来说明。
我们将整个处理的时间分为3个部分
是数据采集和输入的时间,我们称之为C;
是数据处理的时间(也是最消耗时间的地方),我们称之为P;
是数据显示的时间(这个基本可以做到旁路),我们称之为S。
其中红、黄、蓝分别代表第1、2、3帧
原机制为


时间为C1+P1+C2+P2+C3+P3
使用机制进行了乱序
消耗时间不会大于(一般认为P>>C),C1+P1+P2+P3。能够将部分时间进行重叠,从而达到提高速度目的。

小结:
1、OpenVINO的推断操作比较快(最终该机制的速度不会快于单个推断速度,它只是将数据准备和数据显示进行重叠);
2、它的原子操作提供了这种“线程独立安全”的运算;
3、只有在满足"原子操作线程独立“的基础上,才能够去做这样的操作。这种方法,将来要积极运用。

附件列表

[E2E_L9]类化和级联化的更多相关文章

  1. C++ 类的动态组件化技术

    序言: N年前,我们曾在软件开发上出现了这样的困惑,用VC开发COM组件过于复杂,用VB开发COM组件发现效率低,而且不能实现面向对象的很多特性,例如,继承,多态等.更况且如何快速封装利用历史遗留的大 ...

  2. 窗口的子类化与超类化——子类化是窗口实例级别的,超类化是在窗口类(WNDCLASS)级别的

    1. 子类化 理论:子类化是这样一种技术,它允许一个应用程序截获发往另一个窗口的消息.一个应用程序通过截获属于另一个窗口的消息,从而实现增加.监视或者修改那个窗口的缺省行为.子类化是用来改变或者扩展一 ...

  3. [Python]ctypes+struct实现类c的结构化数据串行处理

    1. 用C/C++实现的结构化数据处理 在涉及到比较底层的通信协议开发过程中, 往往需要开发语言能够有效的表达和处理所定义的通信协议的数据结构. 在这方面是C/C++语言是具有天然优势的: 通过str ...

  4. 实列+JVM讲解类的实列化顺序

    刨根问底---类的实列化顺序 开篇三问 1什么是类的加载,类的加载和类的实列有什么关系,什么时候类加载 2类加载会调用构造函数吗,什么时候调用构造函数 3什么是实列化对象,实列化的对象有什么东西. 我 ...

  5. I类HDACs是乳酸化修饰“eraser”

    赖氨酸酰化修饰 (lysine acylation) 是一种广泛存在的.进化上高度保守的蛋白质翻译后修饰 (post-translational modifications, PTMs) 类型,通过表 ...

  6. Android组件化和插件化开发

    http://www.cnblogs.com/android-blogs/p/5703355.html 什么是组件化和插件化? 组件化开发就是将一个app分成多个模块,每个模块都是一个组件(Modul ...

  7. C++ 中超类化和子类化常用API

    在windows平台上,使用C++实现子类化和超类化常用的API并不多,由于这些API函数的详解和使用方法,网上一大把.本文仅作为笔记,简单的记录一下. 子类化:SetWindowLong,GetWi ...

  8. C++ 中超类化和子类化

    超类化和子类化没有具体的代码,其实是一种编程技巧,在MFC和WTL中可以有不同的实现方法. 窗口子类化: 原理就是改变一个已创建窗口类的窗口过程函数.通过截获已创建窗口的消息,从而实现监视或修改已创建 ...

  9. 眼见为实(2):介绍Windows的窗口、消息、子类化和超类化

    眼见为实(2):介绍Windows的窗口.消息.子类化和超类化 这篇文章本来只是想介绍一下子类化和超类化这两个比较“生僻”的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进程和 ...

随机推荐

  1. 【RAC】 RAC For W2K8R2 安装--dbca创建数据库(七)

    [RAC] RAC For W2K8R2 安装--dbca创建数据库(七) 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可 ...

  2. 查看Windows系统进程(PID)

    语法:tasklist /svc 作用:打印系统进程,并显示其对应PID,可用来跟踪进程并根据PID来进行关闭.

  3. 【CMDB】API传输验证

    客户端向服务器发送请求时,在请求头添加自定义的字符串 客户端的加密方式 1.对key+time进行md5加密 2.发送的时候的格式为md5_key|time,将时间也发送过去 服务器端验证 1.获取加 ...

  4. Docker(5):Docker镜像基本操作(上)

    1.获取镜像 可以使用docker pull 命令从网络上下载镜像.该命令的格式为docker pull NAME[:TAG].对于Docker镜像来说,如果不显示地指定TAG,则默认会选择lates ...

  5. Python包模块化调用方式详解

    Python包模块化调用方式详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一般来说,编程语言中,库.包.模块是同一种概念,是代码组织方式. Python中只有一种模块对象类型 ...

  6. spring cloud turbine 监控不到其它机器上的hystrix.stream 的解决方法 指定监控ip

    turbine多台机器熔断聚合的时候  turbine控制台一直寻找的是localhost下的监控熔断数据. c.n.t.monitor.instance.InstanceMonitor   : Ur ...

  7. httprunner学习1-环境与登录接口案例

    前言 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试. 具有以下优点: 继承 Requests 的全部特性,轻松实 ...

  8. 案例实战之如何写一个webpack loader

    通过以下几个实例掌握webpack loader的写法 1.写一个多语言替换的loader 在index.js在页面上插入了一个{{title}}文本,我们需要在打包的时候将其替换成对应的多语言 fu ...

  9. C# 获取操作系统空闲时间

    获取系统鼠标和键盘没有任何操作的空闲时间 public class CheckComputerFreeState { /// <summary> /// 创建结构体用于返回捕获时间 /// ...

  10. WinForm利用AForge.NET调用电脑摄像头进行拍照和视频

    当然了,你需要去官网下载类库,http://www.aforgenet.com/ 调用本机摄像头常用的组件: AForge AForge.Controls AForge.Imaging AForge. ...