基本思路
使用對象檢測網絡MobileNet SSD V2版本實作車輛與車牌檢測,對得到車輛與車牌ROI對象,分别送到後續的車輛屬性識别網絡與車牌識别網絡中,實作對車輛屬性(顔色與車輛類型)識别輸出與車牌識别輸出。圖示如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICMyYTMvw1dvwlMvwlM3VWaWV2Zh1Wa-cmbw5ybzYjY5kzc6pWdvwlM3EzN1UTMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
其中車輛屬性識别模型輸入大小為72x72,支援的顔色與車輛類别如下:
車牌識别網絡支援中國所有的省市車牌,模型使用1165張中國各個省份資料作為驗證集驗證,準确率高達95%以上,能很好識别旋轉/錯切的車牌。支援輸入車牌HXW=24X94
代碼實作與運作
加載插件
注意可以使用多個插件,對不同的網絡使用不同的插件作為計算背景,OpenVINO是支援這種方式,因為我的機器隻有CPU,是以就加載了CPU插件,代碼如下:
// 建立IE插件
InferenceEnginePluginPtr engine_ptr = PluginDispatcher(dirs).getSuitablePlugin(TargetDevice::eCPU);
InferencePlugin plugin(engine_ptr);
// 加載CPU擴充庫支援
plugin.AddExtension(std::make_shared<Extensions::Cpu::CpuExtensions>());
複制
加載檢測與識别網絡
需要預先加載對象檢測與識别網絡,加載好的網絡資訊,存儲到如下結構體中:
struct MyDetectionNet {
ExecutableNetwork net;
std::string inputName;
std::string sencondOutputName;
std::string outputName;
};
複制
加載網絡的代碼如下:
// 加載車輛與車牌檢測網絡
loadVehiclePlateNetWork(plugin);
// 加載車輛屬性識别網絡
loadVehicleAttributesNetWork(plugin);
// 加載車牌識别網絡
loadVehicleLicenseNetWork(plugin);
複制
輸入圖像資料,開始執行網絡預測推斷,這個部分代碼實作如下:
/** Getting input blob **/
auto input = vehicleplateDetectorinfer.GetBlob(vehicleDetector.inputName);
size_t num_channels = input->getTensorDesc().getDims()[1];
size_t h = input->getTensorDesc().getDims()[2];
size_t w = input->getTensorDesc().getDims()[3];
size_t image_size = h*w;
Mat blob_image;
resize(src, blob_image, Size(h, w));
// NCHW
unsigned char* data = static_cast<unsigned char*>(input->buffer());
for (size_t row = 0; row < h; row++) {
for (size_t col = 0; col < w; col++) {
for (size_t ch = 0; ch < num_channels; ch++) {
data[image_size*ch + row*w + col] = blob_image.at<Vec3b>(row, col)[ch];
}
}
}
// 執行預測
vehicleplateDetectorinfer.Infer();
複制
解析輸出實作車輛屬性識别與車牌識别
車牌識别
Rect roi;
roi.x = rect.x - padding;
roi.y = rect.y - padding;
roi.width = rect.width + padding*2;
roi.height = rect.height + padding*2;
LicensePlateObject lpo;
lpo.location = roi;
fetchLicenseText(src(roi), lpo);
putText(src, lpo.text.c_str(), Point(roi.x-40, roi.y - 10), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 0, 255), 2, 8);
複制
車輛屬性識别
VehicleObject vo;
vo.location = rect;
fetchVehicleAttributes(src(rect), vo);
putText(src, format("vehicle color: %s", vo.color.c_str()), Point(rect.x, rect.y - 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 255), 2, 8);
putText(src, format("vehicle type: %s", vo.type.c_str()), Point(rect.x, rect.y - 40), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 255), 2, 8);
複制
車輛屬性檢測網絡,輸入,推斷與解析輸出的函數實作代碼如下:
// 設定輸入資料
Blob::Ptr inputBlob = vehicleAttrDetectorInfer.GetBlob(attrDetector.inputName);
matU8ToBlob<uint8_t>(blob, inputBlob);
// 執行推斷圖
vehicleAttrDetectorInfer.Infer();
// 擷取輸出結果
auto colorsValues = vehicleAttrDetectorInfer.GetBlob(attrDetector.outputName)->buffer().as<float*>();
auto typesValues = vehicleAttrDetectorInfer.GetBlob(attrDetector.sencondOutputName)->buffer().as<float*>();
// 擷取最大可能行
const auto color_id = max_element(colorsValues, colorsValues + 7) - colorsValues;
const auto type_id = max_element(typesValues, typesValues + 4) - typesValues;
info.color = colors[color_id];
info.type = types[type_id];
複制
車牌識别網絡的輸入,推斷與解析輸出的函數實作代碼如下:
// 執行推斷
plateLicenseRecognizerInfer.Infer();
// 解析輸出結果
const auto data = plateLicenseRecognizerInfer.GetBlob(PLRDetector.outputName)->buffer().as<float*>();
string result;
for (int i = 0; i < maxSequenceSizePerPlate; i++) {
if (data[i] == -1)
break;
result += items[data[i]];
}
info.text = result;
複制
程式執行結果
行駛中抓拍車輛屬性與車牌識别
靜止狀态下車輛屬性與車牌識别
請給我一個【在看】