* -------------------------------------------------------------------------
* This file is part of the Vision SDK project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* Vision SDK is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
* Description: Plugin for vehicle license plate recognition post-processing.
* Author: MindX SDK
* Create: 2020
* History: NA
*/
#include "MxBase/MemoryHelper/MemoryHelper.h"
#include "MxPlugins/ModelPostProcessors/CarPlateRecognitionPostProcessor/CarPlateRecognitionPostProcessor.h"
using namespace MxBase;
using namespace MxTools;
using namespace MxPlugins;
namespace {
const int CAR_PLATE_CHARS_NUM = 65;
const std::string CAR_PLATE_CHARS[CAR_PLATE_CHARS_NUM] = {
"京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "皖",
"闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", "琼", "川", "贵", "云", "藏",
"陕", "甘", "青", "宁", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R",
"S", "T", "U", "V", "W", "X", "Y", "Z"
};
const std::string ATTR_NAME = "carPlate";
}
APP_ERROR CarPlateRecognitionPostProcessor::Init(const std::string &, const std::string &,
MxBase::ModelDesc)
{
LogInfo << "Begin to initialize CarPlateRecognitionPostProcessor.";
LogInfo << "End to initialize CarPlateRecognitionPostProcessor.";
return APP_ERR_OK;
}
APP_ERROR CarPlateRecognitionPostProcessor::DeInit()
{
LogInfo << "Begin to deinitialize CarPlateRecognitionPostProcessor.";
LogInfo << "End to deinitialize CarPlateRecognitionPostProcessor.";
return APP_ERR_OK;
}
APP_ERROR CarPlateRecognitionPostProcessor::Process(std::shared_ptr<void> &metaDataPtr,
MxBase::PostProcessorImageInfo,
std::vector<MxTools::MxpiMetaHeader> &headerVec,
std::vector<std::vector<MxBase::BaseTensor>> &tensors)
{
LogDebug << "Begin to process FeaturePostProcessor.";
if (headerVec.size() != tensors.size()) {
LogError << "Invalid input vectors. size are not equal." << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
if (metaDataPtr == nullptr) {
metaDataPtr = std::static_pointer_cast<void>(MemoryHelper::MakeShared<MxTools::MxpiAttributeList>());
if (metaDataPtr == nullptr) {
LogError << "Fail to allocate memory for new protobuf message." << GetErrorInfo(APP_ERR_COMM_ALLOC_MEM);
return APP_ERR_COMM_ALLOC_MEM;
}
}
const google::protobuf::Descriptor* desc = ((google::protobuf::Message*)metaDataPtr.get())->GetDescriptor();
APP_ERROR ret = MxpiModelPostProcessorBase::IsDescValid(desc, "MxpiAttributeList");
if (ret != APP_ERR_OK) {
return ret;
}
std::shared_ptr<MxTools::MxpiAttributeList> attributeList =
std::static_pointer_cast<MxTools::MxpiAttributeList>(metaDataPtr);
for (size_t i = 0; i < tensors.size(); i++) {
auto featLayerData = std::vector<std::shared_ptr<void>>();
ret = MemoryDataToHost(i, tensors, featLayerData);
if (ret != APP_ERR_OK) {
LogError << "Fail to copy FeaturePostProcessor memory from device to host." << GetErrorInfo(ret);
return APP_ERR_ACL_BAD_COPY;
}
std::string result = GetCarPlateChars(featLayerData);
MxTools::MxpiAttribute* mxpiAttribute = attributeList->add_attributevec();
if (CheckPtrIsNullptr(mxpiAttribute, "mxpiAttribute")) return APP_ERR_COMM_ALLOC_MEM;
mxpiAttribute->set_attrname(ATTR_NAME);
mxpiAttribute->set_attrvalue(result);
mxpiAttribute->set_attrid(0);
mxpiAttribute->set_confidence(-1);
MxTools::MxpiMetaHeader* mxpiMetaHeader = mxpiAttribute->add_headervec();
if (CheckPtrIsNullptr(mxpiMetaHeader, "mxpiMetaHeader")) return APP_ERR_COMM_ALLOC_MEM;
mxpiMetaHeader->set_memberid(headerVec[i].memberid());
mxpiMetaHeader->set_datasource(headerVec[i].datasource());
}
return APP_ERR_OK;
}
std::string CarPlateRecognitionPostProcessor::GetCarPlateChars(std::vector<std::shared_ptr<void>> &featLayerData)
{
std::string result;
for (size_t i = 0; i < featLayerData.size(); ++i) {
auto* output = static_cast<float*>(featLayerData[i].get());
unsigned int maxIndex = std::max_element(output, output + CAR_PLATE_CHARS_NUM) - output;
if (CAR_PLATE_CHARS_NUM <= maxIndex) {
continue;
}
result += CAR_PLATE_CHARS[maxIndex];
}
return result;
}
std::shared_ptr<MxPlugins::MxpiModelPostProcessorBase> GetInstance()
{
LogInfo << "Begin to get PedestrianAttributePostProcessor instance.";
auto instance = MemoryHelper::MakeShared<CarPlateRecognitionPostProcessor>();
if (instance == nullptr) {
LogError << "Fail to allocate memory." << GetErrorInfo(APP_ERR_COMM_ALLOC_MEM);
} else {
LogInfo << "End to get PedestrianAttributePostProcessor instance.";
}
return instance;
}