[E2E_L9]類化和級聯化

1、多車輛識別可能和車輛車牌分割;
這樣一張圖,能夠識別多車輛和車牌,問題是如何區分而且配對。
 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_miny_min), cv::Point(x_maxy_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(cbufroi);
                cv::rectangle(srcrectcv::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(cbufroi);
                cv::rectangle(srcrectcv::Scalar(0, 0, 255));
                i_plate++;
            }
        
        }
    }
這種處理的方法,後面應該仍是要用的
2、函數化封裝和合並;
如下是原始代碼
# 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的開始。

3、異步機制探索;
一直以來,我都爲視頻處理的速度問題所困擾,在「視頻流」的處理過程當中,必須首先得到一幀的數據,而後纔可以處理這一 幀的數據,而且獲得加強的結果——那麼最後處理的速度必然同時受到視頻採集和圖像處理的限制。
這可能相似於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

可是爲了進一步研究問題,須要具體作例子來實驗。
好吧,仍是有所差別的。
4、類的封裝其價值
最終該機制的速度不會快於單個推斷速度,咱們至少能夠將整個操做分爲」數據準備「」數據推斷「和」數據顯示「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。
其中紅、黃、藍分別表明第一、二、3幀
原機制爲


時間爲C1+P1+C2+P2+C3+P3
使用機制進行了亂序
消耗時間不會大於(通常認爲P>>C),C1+P1+P2+P3。可以將部分時間進行重疊,從而達到提升速度目的。

小結:
一、OpenVINO的推斷操做比較快(最終該機制的速度不會快於單個推斷速度,它只是將數據準備和數據顯示進行重疊);
二、它的原子操做提供了這種「線程獨立安全」的運算;
三、只有在知足" 原子操做線程獨立「的基礎上,纔可以去作這樣的操做。這種方法,未來要積極運用。




附件列表

相關文章
相關標籤/搜索