* -------------------------------------------------------------------------
* 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: Analyze and detect the quality of the decoded image.
* Author: MindX SDK
* Create: 2020
* History: NA
*/
#include "MxPlugins/MxpiQualityDetection/MxpiQualityDetection.h"
#include <cmath>
#include <limits>
#include <fstream>
#include "nlohmann/json.hpp"
#include "MxBase/Log/Log.h"
#include "MxBase/GlobalManager/GlobalManager.h"
#include "MxBase/Utils/FileUtils.h"
#include "MxBase/MemoryHelper/MemoryHelper.h"
#include "MxTools/PluginToolkit/MxpiDataTypeWrapper/MxpiDataTypeDeleter.h"
#include "MxPlugins/MxpiPluginsUtils/MxpiPluginsUtils.h"
using namespace MxPlugins;
using namespace MxTools;
using namespace MxBase;
using namespace std;
using namespace cv;
namespace {
const string QUALITY_DETECTION_KEY = "MxpiVisionList";
const int PIXEL_VALUE_NUM = 256;
const float NV12_COEF = 1.5;
const int OCCLUSION_GRAY_THRES = 25;
const int OCCLUSION_LAP_THRES = 10;
const float INT_TO_FLOAT = 1.0;
const int POW_AREA = 2;
const int NUM_2 = 2;
enum class DetectionType {
IMAGE_BRIGHTNESS_DETECTION = 0,
IMAGE_OCCLUSION_DETECTION,
IMAGE_BLUR_DETECTION,
IMAGE_NOISE_DETECTION,
IMAGE_COLOR_CAST_DETECTION,
IMAGE_STRIPE_DETECTION,
BLACK_SCREEN_DETECTION,
SCENE_MUTATION_DETECTION,
PTZ_MOVEMENT_DETECTION,
VIEW_SHAKE_DETECTION,
VIDEO_FREEZE_DETECTION,
};
int AlignToEven(int num)
{
if (num % NUM_2 == 0) {
return num;
}
return num - 1;
}
}
APP_ERROR MxpiQualityDetection::InitParams(void)
{
configData_.GetFileValueWarn<uint32_t>("FRAME_LIST_LEN", frameListMaxLen_);
configData_.GetFileValueWarn<bool>("BRIGHTNESS_SWITCH", switchBrightnessDetection_);
configData_.GetFileValueWarn<uint32_t>("BRIGHTNESS_FRAME_INTERVAL", frameIntervalBrightnessDetection_);
configData_.GetFileValueWarn<float>("BRIGHTNESS_THRESHOLD", thresholdBrightnessFactor_);
configData_.GetFileValueWarn<bool>("OCCLUSION_SWITCH", switchOcclusionDetection_);
configData_.GetFileValueWarn<uint32_t>("OCCLUSION_FRAME_INTERVAL", frameIntervalOcclusionDetection_);
configData_.GetFileValueWarn<float>("OCCLUSION_THRESHOLD", thresholdOcclusion_);
configData_.GetFileValueWarn<bool>("BLUR_SWITCH", switchBlurDetection_);
configData_.GetFileValueWarn<uint32_t>("BLUR_FRAME_INTERVAL", frameIntervalBlurDetection_);
configData_.GetFileValueWarn<float>("BLUR_THRESHOLD", thresholdBlur_);
configData_.GetFileValueWarn<bool>("NOISE_SWITCH", switchNoiseDetection_);
configData_.GetFileValueWarn<uint32_t>("NOISE_FRAME_INTERVAL", frameIntervalNoiseDetection_);
configData_.GetFileValueWarn<float>("NOISE_THRESHOLD", thresholdNoiseRate_);
configData_.GetFileValueWarn<bool>("COLOR_CAST_SWITCH", switchColorCastDetection_);
configData_.GetFileValueWarn<uint32_t>("COLOR_CAST_FRAME_INTERVAL", frameIntervalColorCastDetection_);
configData_.GetFileValueWarn<float>("COLOR_CAST_THRESHOLD", thresholdcolorCastFactor_);
configData_.GetFileValueWarn<bool>("STRIPE_SWITCH", switchStripeDetection_);
configData_.GetFileValueWarn<uint32_t>("STRIPE_FRAME_INTERVAL", frameIntervalStripeDetection_);
configData_.GetFileValueWarn<float>("STRIPE_THRESHOLD", thresholdStripe_);
configData_.GetFileValueWarn<bool>("DARK_SWITCH", switchScreenDetection_);
configData_.GetFileValueWarn<uint32_t>("DARK_FRAME_INTERVAL", frameIntervalScreenDetection_);
configData_.GetFileValueWarn<float>("DARK_THRESHOLD", thresholdDarkProp_);
configData_.GetFileValueWarn<bool>("VIDEO_FREEZE_SWITCH", switchVideoFreezeDetection_);
configData_.GetFileValueWarn<uint32_t>("VIDEO_FREEZE_FRAME_INTERVAL", frameIntervalVideoFreezeDetection_);
configData_.GetFileValueWarn<float>("VIDEO_FREEZE_THRESHOLD", thresholdVideoFreezeDetection_);
configData_.GetFileValueWarn<bool>("VIEW_SHAKE_SWITCH", switchViewShakeDetection_);
configData_.GetFileValueWarn<uint32_t>("VIEW_SHAKE_FRAME_INTERVAL", frameIntervalViewShakeDetection_);
configData_.GetFileValueWarn<float>("VIEW_SHAKE_THRESHOLD", thresholdViewShakeDetection_);
configData_.GetFileValueWarn<bool>("SCENE_MUTATION_SWITCH", switchSceneMutationDetection_);
configData_.GetFileValueWarn<uint32_t>("SCENE_MUTATION_FRAME_INTERVAL", frameIntervalSceneMutationDetection_);
configData_.GetFileValueWarn<float>("SCENE_MUTATION_THRESHOLD", thresholdSceneMutationDetection_);
configData_.GetFileValueWarn<bool>("PTZ_MOVEMENT_SWITCH", switchPTZMovementDetection_);
configData_.GetFileValueWarn<uint32_t>("PTZ_MOVEMENT_FRAME_INTERVAL", frameIntervalPTZMovementDetection_);
configData_.GetFileValueWarn<float>("PTZ_MOVEMENT_THRESHOLD", thresholdPTZMovementDetection_);
return APP_ERR_OK;
}
bool MxpiQualityDetection::IsValidInterval(uint32_t frameInterval)
{
if (frameInterval == 0 || frameInterval >= frameListMaxLen_) {
return false;
}
return true;
}
APP_ERROR MxpiQualityDetection::CheckImageDectParams(void)
{
const uint32_t minFrameListLen = 2;
if (frameListMaxLen_ < minFrameListLen) {
errorInfo_ << "Invalid frame list length, please check it." << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
LogError << errorInfo_.str();
return APP_ERR_COMM_INVALID_PARAM;
}
if (!IsValidInterval(frameIntervalBrightnessDetection_) || !IsValidInterval(frameIntervalOcclusionDetection_) ||
!IsValidInterval(frameIntervalBlurDetection_) || !IsValidInterval(frameIntervalNoiseDetection_) ||
!IsValidInterval(frameIntervalColorCastDetection_) || !IsValidInterval(frameIntervalStripeDetection_) ||
!IsValidInterval(frameIntervalScreenDetection_)) {
errorInfo_ << "Invalid frame interval, please check it." << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
LogError << errorInfo_.str();
return APP_ERR_COMM_INVALID_PARAM;
}
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::CheckVideoDectParams(void)
{
const float thresShakeDetectionMin = 10.0;
const float thresShakeDetectionMax = 100.0;
if (!IsValidInterval(frameIntervalVideoFreezeDetection_) || !IsValidInterval(frameIntervalViewShakeDetection_) ||
!IsValidInterval(frameIntervalSceneMutationDetection_) ||
!IsValidInterval(frameIntervalPTZMovementDetection_)) {
errorInfo_ << "Invalid frame interval, please check it." << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
LogError << errorInfo_.str();
return APP_ERR_COMM_INVALID_PARAM;
}
if (thresholdViewShakeDetection_ < thresShakeDetectionMin ||
thresholdViewShakeDetection_ > thresShakeDetectionMax) {
errorInfo_ << "Invalid threshold of Video Shake Detection, please check it."
<< GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
LogError << errorInfo_.str();
return APP_ERR_COMM_INVALID_PARAM;
}
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::LoadConfig(std::string configPath)
{
nlohmann::json config;
MxBase::ConfigUtil util;
MxBase::ConfigMode configMode;
try {
config = nlohmann::json::parse(configPath);
LogDebug << "Parse config content from content";
configMode = MxBase::CONFIGCONTENT;
} catch (const std::exception &ex) {
LogDebug << "Parse config content from file";
configMode = MxBase::CONFIGFILE;
}
APP_ERROR ret = util.LoadConfiguration(configPath, configData_, configMode);
if (ret != APP_ERR_OK) {
LogError << "Failed to load configuration, config path invalidate." << GetErrorInfo(ret);
return ret;
}
ret = InitParams();
if (ret != APP_ERR_OK) {
LogError << "Failed to initialize the parameters." << GetErrorInfo(ret);
return ret;
}
ret = CheckImageDectParams();
if (ret != APP_ERR_OK) {
return ret;
}
ret = CheckVideoDectParams();
if (ret != APP_ERR_OK) {
return ret;
}
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::Init(std::map<std::string, std::shared_ptr<void>> &configParamMap)
{
LogInfo << "Begin to initialize MxpiQualityDetection(" << elementName_ << ").";
dataSource_ = MxPluginsAutoDataSource(elementName_, 0, "dataSource", dataSource_, dataSourceKeys_);
if (dataSource_.empty()) {
LogError << "Get data source fail." << GetErrorInfo(APP_ERR_COMM_INIT_FAIL);
return APP_ERR_COMM_INIT_FAIL;
}
std::vector<std::string> parameterConfigContentPtr = {"qualityDetectionConfigContent"};
auto ret = CheckConfigParamMapIsValid(parameterConfigContentPtr, configParamMap);
if (ret != APP_ERR_OK) {
LogError << "Config parameter map is invalid." << GetErrorInfo(ret);
return ret;
}
std::string config = *std::static_pointer_cast<std::string>(configParamMap["qualityDetectionConfigContent"]);
if (config == "") {
LogDebug << "element(" << elementName_ <<
") not set property(qualityDetectionConfigContent), try to read content from cfg file.";
std::vector<std::string> parameterConfigPathPtr = {"qualityDetectionConfigPath"};
ret = CheckConfigParamMapIsValid(parameterConfigPathPtr, configParamMap);
if (ret != APP_ERR_OK) {
LogError << "Config parameter map is invalid." << GetErrorInfo(ret);
return ret;
}
config = *std::static_pointer_cast<std::string>(configParamMap["qualityDetectionConfigPath"]);
if (!MxBase::FileUtils::CheckFileExists(config)) {
LogWarn << GetErrorInfo(APP_ERR_COMM_NO_EXIST, elementName_)
<< "The Configuration file of qualityDetection does not exist.";
}
}
ret = LoadConfig(config);
if (ret != APP_ERR_OK) {
LogError << "Failed to load config file." << GetErrorInfo(ret);
return ret;
}
MapKeyToHandle();
LogInfo << "End to initialize MxpiQualityDetection(" << elementName_ << ").";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::DeInit()
{
LogInfo << "Begin to deinitialize MxpiQualityDetection(" << elementName_ << ").";
LogInfo << "End to deinitialize MxpiQualityDetection(" << elementName_ << ").";
return APP_ERR_OK;
}
bool MxpiQualityDetection::FrameSkip(bool switchDetection, uint32_t frameInterval)
{
bool ifSkip = false;
if (!switchDetection) {
LogDebug << "Switch Off, skip frame " << frameIdVdec_ << ", channel " << channelIdVdec_;
ifSkip = true;
} else if (frameIdCur_ % frameInterval != 0) {
LogDebug << "Invalid Frame Id, skip frame " << frameIdVdec_ << ", channel " << channelIdVdec_;
ifSkip = true;
}
return ifSkip;
}
APP_ERROR MxpiQualityDetection::ImageBrightnessDetection(void)
{
LogDebug << "Begin to process ImageBrightnessDetection.";
if (FrameSkip(switchBrightnessDetection_, frameIntervalBrightnessDetection_)) {
return APP_ERR_OK;
}
float diffSum = 0;
float deviation = 0;
const int brightnessMean = 128;
int hist[PIXEL_VALUE_NUM] = { 0 };
Mat imgGray;
Mat imgRgb = frameList_.back().rgbData;
cvtColor(imgRgb, imgGray, COLOR_RGB2GRAY);
for (int i = 0; i < imgGray.rows; i++) {
for (int j = 0; j < imgGray.cols; j++) {
diffSum += float(imgGray.at<uchar>(i, j) - brightnessMean);
hist[imgGray.at<uchar>(i, j)]++;
}
}
if (IsDenominatorZero(float(imgGray.rows * imgGray.cols))) {
LogError << "The multiplication of rows and cols must not equal to 0!"
<< GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
float diffAvg = diffSum / float(imgGray.rows * imgGray.cols);
for (int i = 0; i < PIXEL_VALUE_NUM; i++) {
deviation += abs(i - brightnessMean - diffAvg) * hist[i];
}
deviation /= float((imgGray.rows * imgGray.cols));
if (IsDenominatorZero(deviation)) {
LogError << "The value of deviation must not equal to 0!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
float brightnessFactor = abs(diffAvg / deviation);
if (brightnessFactor > thresholdBrightnessFactor_) {
if (diffAvg > std::numeric_limits<float>::epsilon()) {
LogWarn << "Video Lightness Detection: Too bright, Brightness Rate = " << brightnessFactor <<
", Frame ID = " << frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
} else {
LogWarn << "Video Lightness Detection: Too dark, Brightness Rate = " << brightnessFactor <<
", Frame ID = " << frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
}
} else {
LogDebug << "Video Lightness Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
}
LogDebug << "End to process ImageBrightnessDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ImageOcclusionDetection(void)
{
LogDebug << "Begin to process ImageOcclusionDetection.";
if (FrameSkip(switchOcclusionDetection_, frameIntervalOcclusionDetection_)) {
return APP_ERR_OK;
}
int coverBlock = 0;
const int blockNum = 8;
const int sumBlock = static_cast<int>(pow(blockNum, POW_AREA));
Mat imgGray;
Mat imgLap;
Mat imgRgb = frameList_.back().rgbData;
cvtColor(imgRgb, imgGray, COLOR_RGB2GRAY);
Laplacian(imgGray, imgLap, imgGray.depth());
for (int i = 0; i < imgGray.rows / blockNum * blockNum; i += imgGray.rows / blockNum) {
for (int j = 0; j < imgGray.cols / blockNum * blockNum; j += imgGray.cols / blockNum) {
float sigmaGray = 0;
float sigmaLap = 0;
cv::Rect rec = cv::Rect(j, i, imgGray.cols / blockNum, imgGray.rows / blockNum);
Mat subImgGray = imgGray(rec);
Mat subImgLap = imgLap(rec);
Mat means, stdDevGray, stdDevLap;
meanStdDev(subImgGray, means, stdDevGray);
meanStdDev(subImgLap, means, stdDevLap);
sigmaGray = stdDevGray.at<double>(0);
sigmaLap = stdDevLap.at<double>(0);
if (sigmaGray < OCCLUSION_GRAY_THRES && sigmaLap < OCCLUSION_LAP_THRES)
coverBlock++;
}
}
double coveredRate = 0.0;
if (!IsDenominatorZero(sumBlock)) {
coveredRate = coverBlock * INT_TO_FLOAT / sumBlock;
}
if (coveredRate > thresholdOcclusion_) {
LogWarn << "Image Occlusion Detection: Occlusion, Covered Rate = " << coveredRate << ", Frame ID = " <<
frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "Image Occlusion Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
}
LogDebug << "End to process ImageOcclusionDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ImageBlurDetection(void)
{
LogDebug << "Begin to process ImageBlurDetection.";
if (FrameSkip(switchBlurDetection_, frameIntervalBlurDetection_)) {
return APP_ERR_OK;
}
Mat imgGray;
Mat imgRgb = frameList_.back().rgbData;
cvtColor(imgRgb, imgGray, COLOR_RGB2GRAY);
Mat meansMat, stdDevGrayMat;
double stdDevGray = 0;
int kernelSize = 3;
Laplacian(imgGray, imgGray, imgGray.depth(), kernelSize);
convertScaleAbs(imgGray, imgGray);
meanStdDev(imgGray, meansMat, stdDevGrayMat);
stdDevGray = stdDevGrayMat.at<double>(0, 0);
double var = pow(stdDevGray, POW_AREA);
if (var < thresholdBlur_) {
LogWarn << "Image Blur Detection: Blur, Blur Rate = " << var << ", Frame ID = " << frameIdVdec_ <<
", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "Image Blur Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
}
LogDebug << "End to process ImageBlurDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ImageNoiseDetection(void)
{
LogDebug << "Begin to process ImageNoiseDetection.";
if (FrameSkip(switchNoiseDetection_, frameIntervalNoiseDetection_)) {
return APP_ERR_OK;
}
Mat imgGray;
Mat imgRgb = frameList_.back().rgbData;
cvtColor(imgRgb, imgGray, COLOR_RGB2GRAY);
const int matRowSize = 3;
const int matColSize = 3;
Mat kern1 = (Mat_<char>(matRowSize, matColSize) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
Mat kern2 = (Mat_<char>(matRowSize, matColSize) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
Mat kern3 = (Mat_<char>(matRowSize, matColSize) << 0, 1, 2, -1, 0, 1, -2, -1, 0);
Mat kern4 = (Mat_<char>(matRowSize, matColSize) << -2, -1, 0, -1, 0, 1, 0, 1, 2);
int pixelSum = imgGray.cols * imgGray.rows;
const float thresSpbe = 0.1;
const int maxPixelValue = 255;
const int kernSize = 3;
Mat imgSpbel1, imgSpbel2, imgSpbel3, imgSpbel4, imgMBlur;
filter2D(imgGray, imgSpbel1, imgGray.depth(), kern1);
filter2D(imgGray, imgSpbel2, imgGray.depth(), kern2);
filter2D(imgGray, imgSpbel3, imgGray.depth(), kern3);
filter2D(imgGray, imgSpbel4, imgGray.depth(), kern4);
Mat imgSpbel1Locate = (abs(imgSpbel1) > thresSpbe) / maxPixelValue;
Mat imgSpbel2Locate = (abs(imgSpbel2) > thresSpbe) / maxPixelValue;
Mat imgSpbel3Locate = (abs(imgSpbel3) > thresSpbe) / maxPixelValue;
Mat imgSpbel4Locate = (abs(imgSpbel4) > thresSpbe) / maxPixelValue;
Mat countLocate = imgSpbel1Locate.mul(imgSpbel2Locate).mul(imgSpbel3Locate).mul(imgSpbel4Locate);
medianBlur(imgGray, imgMBlur, kernSize);
Mat reduce = abs(imgMBlur - imgGray).mul(countLocate);
int noiseNum = 0;
const int noiseValue = 20;
for (int i = 0; i < reduce.rows; i++) {
for (int j = 0; j < reduce.cols; j++) {
if (reduce.at<uchar>(i, j) > noiseValue) {
noiseNum++;
}
}
}
APP_ERROR ret = CheckValuePixelSum(pixelSum, noiseNum);
if (ret != APP_ERR_OK) {
LogError << "The value of pixelSum must not equal to 0!" << GetErrorInfo(ret);
return ret;
}
LogDebug << "End to process ImageNoiseDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::CheckValuePixelSum(int pixelSum, int noiseNum)
{
if (IsDenominatorZero(pixelSum)) {
LogError << "The value of pixelSum must not equal to 0!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
float noiseRate = noiseNum * INT_TO_FLOAT / pixelSum;
if (noiseRate > thresholdNoiseRate_) {
LogWarn << "Image Noise Detection: Noise, Noise Rate = " << noiseRate << ", Frame ID = " << frameIdVdec_
<<", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "Image Noise Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
}
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ImageColorCastDetection(void)
{
LogDebug << "Begin to process ImageColorCastDetection.";
if (FrameSkip(switchColorCastDetection_, frameIntervalColorCastDetection_)) {
return APP_ERR_OK;
}
Mat imgRgb = frameList_.back().rgbData;
Mat_<Vec3b>::iterator begin = imgRgb.begin<Vec3b>();
Mat_<Vec3b>::iterator end = imgRgb.end<Vec3b>();
float sumA = 0;
float sumB = 0;
const int idxA = 1;
const int idxB = 2;
for (; begin != end; begin++) {
sumA += (*begin)[idxA];
sumB += (*begin)[idxB];
}
int pixelSum = imgRgb.rows * imgRgb.cols;
const int normValue = 128;
if (IsDenominatorZero(pixelSum - normValue) || IsDenominatorZero(pixelSum)) {
LogError << "The subtraction of pixelSum and normValuevalue or the value of pixelSum must not equal to 0!"
<< GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
double normA = sumA / pixelSum - normValue;
double normB = sumB / pixelSum - normValue;
double chrAvg = sqrt(pow(normA, POW_AREA) + pow(normB, POW_AREA));
begin = imgRgb.begin<Vec3b>();
double centerDisA = 0;
double centerDisB = 0;
for (; begin != end; begin++) {
centerDisA += abs((*begin)[idxA] - normValue - normA);
centerDisB += abs((*begin)[idxB] - normValue - normB);
}
centerDisA = centerDisA / pixelSum;
centerDisB = centerDisB / pixelSum;
double centerDisAvg = sqrt(pow(centerDisA, POW_AREA) + pow(centerDisB, POW_AREA));
float colorCastFactor = static_cast<float>(chrAvg / centerDisAvg);
if (colorCastFactor >= thresholdcolorCastFactor_) {
LogWarn << "Image Color Cast Detection: Color Cast, Cast Rate = " << colorCastFactor << ", Frame ID = " <<
frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "Image Color Cast Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
}
LogDebug << "End to process ImageColorCastDetection.";
return APP_ERR_OK;
}
double MxpiQualityDetection::StripeRateCalculation(const Mat &imgGray)
{
int dftSizeCol = getOptimalDFTSize(imgGray.cols);
int dftSizeRow = getOptimalDFTSize(imgGray.rows);
Mat imgPadded;
copyMakeBorder(imgGray, imgPadded, 0, dftSizeRow - imgGray.rows, 0, dftSizeCol - imgGray.cols, BORDER_CONSTANT,
Scalar::all(0));
Mat plane[] = {Mat_<float>(imgPadded), Mat::zeros(imgPadded.size(), CV_32F)};
Mat complexImg;
size_t count = 2;
merge(plane, count, complexImg);
dft(complexImg, complexImg);
split(complexImg, plane);
magnitude(plane[0], plane[1], plane[0]);
Mat magnitudeImage = plane[0];
magnitudeImage += Scalar::all(1);
log(magnitudeImage, magnitudeImage);
const int coefMagnitude = 20;
const int coefMagnitudeStddev = 3;
const int coefMaxV = 2;
magnitudeImage = magnitudeImage(cv::Rect(0, 0, AlignToEven(magnitudeImage.cols), AlignToEven(magnitudeImage.rows)));
Mat magnitudeSpectrum = coefMagnitude * magnitudeImage;
Mat matMeanMat, matStddevMat;
meanStdDev(magnitudeSpectrum, matMeanMat, matStddevMat);
double matMean = matMeanMat.at<double>(0, 0);
double matStddev = matStddevMat.at<double>(0, 0);
double minV = 0.0;
double maxV = 0.0;
double *minP = &minV;
double *maxP = &maxV;
minMaxIdx(magnitudeSpectrum, minP, maxP);
double threshold = max(matMean + coefMagnitudeStddev * matStddev, maxV / coefMaxV);
int noiseNum = 0;
int magSpecPixelSum = magnitudeSpectrum.rows * magnitudeSpectrum.cols;
for (int i = 0; i < magnitudeSpectrum.rows; i++) {
for (int j = 0; j < magnitudeSpectrum.cols; j++) {
if (magnitudeSpectrum.at<uchar>(i, j) > threshold) {
noiseNum++;
}
}
}
if (IsDenominatorZero(magSpecPixelSum)) {
LogError << "The value of magSpecPixelSum must not equal to 0!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return 0.f;
}
double stripeRate = noiseNum * INT_TO_FLOAT / magSpecPixelSum;
return stripeRate;
}
APP_ERROR MxpiQualityDetection::ImageStripeDetection(void)
{
LogDebug << "Begin to process ImageStripeDetection.";
if (FrameSkip(switchStripeDetection_, frameIntervalStripeDetection_)) {
return APP_ERR_OK;
}
Mat imgGray;
Mat imgRgb = frameList_.back().rgbData;
cvtColor(imgRgb, imgGray, COLOR_RGB2GRAY);
double stripeRate = StripeRateCalculation(imgGray);
Mat meansMat, stdDevGrayMat;
double stdDevGray = 0;
const int kernelSize = 3;
const double varThreshould = 3000;
Laplacian(imgGray, imgGray, imgGray.depth(), kernelSize);
convertScaleAbs(imgGray, imgGray);
meanStdDev(imgGray, meansMat, stdDevGrayMat);
stdDevGray = stdDevGrayMat.at<double>(0, 0);
double var = pow(stdDevGray, POW_AREA);
if (stripeRate > thresholdStripe_ && var > varThreshould) {
LogWarn << "Image Stripe Detection:Stripe Noise, Stripe Rate = " << stripeRate << ", Frame ID = " <<
frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "Image Stripe Detection:Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
}
LogDebug << "End to process ImageStripeDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::BlackScreenDetection(void)
{
LogDebug << "Begin to process BlackScreenDetection.";
if (FrameSkip(switchScreenDetection_, frameIntervalScreenDetection_)) {
return APP_ERR_OK;
}
Mat imgGray;
Mat imgRgb = frameList_.back().rgbData;
cvtColor(imgRgb, imgGray, COLOR_RGB2GRAY);
int pixelSum = imgGray.rows * imgGray.cols;
int darkSum = 0;
const int darknessValue = 20;
for (int i = 0; i < imgGray.rows; i++) {
for (int j = 0; j < imgGray.cols; j++) {
if (imgGray.at<uchar>(i, j) < darknessValue) {
darkSum++;
}
}
}
if (IsDenominatorZero(pixelSum)) {
LogError << "The value of pixelSum must not equal to 0!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
double darkProp = darkSum * INT_TO_FLOAT / pixelSum;
if (darkProp >= thresholdDarkProp_) {
LogWarn << "Black Screen Detection: Black screen, Dark Rate = " << darkProp << ", Frame ID = " <<
frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "Black Screen Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
}
LogDebug << "End to process BlackScreenDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::VideoFreezeDetection(void)
{
LogDebug << "Begin to process VideoFreezeDetection.";
if (FrameSkip(switchVideoFreezeDetection_, frameIntervalVideoFreezeDetection_)) {
return APP_ERR_OK;
}
FrameInfo image1 = frameList_[frameListMaxLen_ - 1 - frameIntervalVideoFreezeDetection_];
FrameInfo image2 = frameList_[frameListMaxLen_ - 1];
cv::Mat image1Gray, image2GRAY;
cvtColor(image1.rgbData, image1Gray, cv::COLOR_RGB2GRAY);
cvtColor(image2.rgbData, image2GRAY, cv::COLOR_RGB2GRAY);
int diffPixelNum = 0;
const int pixelDiffValue = 10;
for (int i = 0; i < image1Gray.rows; i++) {
for (int j = 0; j < image1Gray.cols; j++) {
if (abs(image1Gray.at<uchar>(i, j) - image2GRAY.at<uchar>(i, j)) > pixelDiffValue)
diffPixelNum++;
}
}
auto imageRowsCols = image1Gray.rows * image1Gray.cols;
if (IsDenominatorZero(imageRowsCols)) {
LogError << "The value of imageRowsCols must not equal to 0!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
float freezeFactor = diffPixelNum * INT_TO_FLOAT / (image1Gray.rows * image1Gray.cols);
if (freezeFactor > thresholdVideoFreezeDetection_) {
LogDebug << "Video Freeze Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
} else {
LogWarn << "Video Freeze Detection: Freeze, Freeze Rate = " << freezeFactor << ", Frame ID = " <<
frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
}
LogDebug << "End to process VideoFreezeDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ViewShakeOffsetCal(const Mat &imageGray, vector<int> &sumRowVec, vector<int> &sumColVec)
{
int sumRow, sumCol;
float meanRow, meanCol;
float sumRC = 0;
for (int i = 0; i < imageGray.rows; i++) {
sumRow = 0;
for (int j = 0; j < imageGray.cols; j++) {
sumRow += imageGray.at<uchar>(i, j);
}
sumRC += sumRow;
sumRowVec.push_back(sumRow);
}
for (int i = 0; i < imageGray.cols; i++) {
sumCol = 0;
for (int j = 0; j < imageGray.rows; j++) {
sumCol += imageGray.at<uchar>(j, i);
}
sumColVec.push_back(sumCol);
}
if (IsDenominatorZero(imageGray.rows) || IsDenominatorZero(imageGray.cols)) {
LogError << "ImageGray.rows: " << imageGray.rows << ", imageGray.cols: " << imageGray.cols
<< "must not equal to zero!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
meanRow = sumRC / imageGray.rows;
meanCol = sumRC / imageGray.cols;
for (size_t i = 0; i < sumRowVec.size(); i++) {
sumRowVec[i] = static_cast<int>(sumRowVec[i] - meanRow);
}
for (size_t i = 0; i < sumColVec.size(); i++) {
sumColVec[i] = static_cast<int>(sumColVec[i] - meanCol);
}
return APP_ERR_OK;
}
int MxpiQualityDetection::ViewShakeCalMin(std::vector<int> &sumVecImage1, std::vector<int> &sumVecImage2,
const int searchLen)
{
int minCor;
int idx = 0;
const int offsetProduct = 2;
int doubleLen = offsetProduct * searchLen + 1;
float sumDiff;
float minDiff = numeric_limits<float>::max();
if (static_cast<int>(sumVecImage1.size()) < doubleLen) {
doubleLen = static_cast<int>(sumVecImage1.size());
}
for (int i = 1; i <= doubleLen; i++) {
sumDiff = 0;
for (size_t j = 0; j < sumVecImage1.size() - offsetProduct * searchLen; j++) {
sumDiff += pow((sumVecImage1[i + j - 1] - sumVecImage2[j + searchLen]), POW_AREA);
}
if (sumDiff < minDiff) {
minDiff = sumDiff;
idx = i;
}
}
minCor = searchLen + 1 - idx;
return minCor;
}
APP_ERROR MxpiQualityDetection::ViewShakeDetection(void)
{
LogDebug << "Begin to process ViewShakeDetection.";
if (FrameSkip(switchViewShakeDetection_, frameIntervalViewShakeDetection_)) {
return APP_ERR_OK;
}
FrameInfo image1 = frameList_[frameListMaxLen_ - 1 - frameIntervalViewShakeDetection_];
FrameInfo image2 = frameList_[frameListMaxLen_ - 1];
cv::Mat image1Gray, image2Gray;
cvtColor(image1.rgbData, image1Gray, cv::COLOR_RGB2GRAY);
cvtColor(image2.rgbData, image2Gray, cv::COLOR_RGB2GRAY);
vector<int> sumRowVecImage1, sumColVecImage1, sumRowVecImage2, sumColVecImage2;
APP_ERROR ret = ViewShakeOffsetCal(image1Gray, sumRowVecImage1, sumColVecImage1);
if (ret != APP_ERR_OK) {
LogError << "Failed to executed first function of ViewShakeOffsetCal." << GetErrorInfo(ret);
return ret;
}
ret = ViewShakeOffsetCal(image2Gray, sumRowVecImage2, sumColVecImage2);
if (ret != APP_ERR_OK) {
LogError << "Failed to executed first function of ViewShakeOffsetCal." << GetErrorInfo(ret);
return ret;
}
int searchLen = static_cast<int>(thresholdViewShakeDetection_);
int offsetPixelRow = ViewShakeCalMin(sumRowVecImage1, sumRowVecImage2, searchLen);
int offsetPixelCol = ViewShakeCalMin(sumColVecImage1, sumColVecImage2, searchLen);
if (offsetPixelRow < 0 || offsetPixelRow > thresholdViewShakeDetection_ || offsetPixelCol < 0 ||
offsetPixelCol > thresholdViewShakeDetection_) {
LogWarn << "View Shake Detection: Shake, Row Shake Rate = " << offsetPixelRow << ", Col Shake Rate = " <<
offsetPixelCol << ", Frame ID = " << frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "View Shake Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
}
LogDebug << "End to process ViewShakeDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::SceneMutationDetection(void)
{
LogDebug << "Begin to process SceneMutationDetection.";
if (FrameSkip(switchSceneMutationDetection_, frameIntervalSceneMutationDetection_)) {
return APP_ERR_OK;
}
FrameInfo image1 = frameList_[frameListMaxLen_ - 1 - frameIntervalSceneMutationDetection_];
FrameInfo image2 = frameList_[frameListMaxLen_ - 1];
Mat image1Gray, image2Gray;
cvtColor(image1.rgbData, image1Gray, cv::COLOR_RGB2GRAY);
cvtColor(image2.rgbData, image2Gray, cv::COLOR_RGB2GRAY);
int diffSum = 0;
const int pixelDiffValue = 50;
int totalPixelNum = image1Gray.rows * image1Gray.cols;
for (int i = 0; i < image1Gray.rows; i++) {
for (int j = 0; j < image1Gray.cols; j++) {
if (abs(image1Gray.at<uchar>(i, j) - image2Gray.at<uchar>(i, j)) > pixelDiffValue) {
diffSum++;
}
}
}
if (IsDenominatorZero(totalPixelNum)) {
LogError << "The value of totalPixelNum must not equal to 0!" << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
float diffAvg = diffSum * INT_TO_FLOAT / totalPixelNum;
if (diffAvg < thresholdSceneMutationDetection_) {
LogDebug << "Scene Mutation Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
} else {
LogWarn << "Scene Mutation Detection: Mutation, Mutation Rate = " << diffAvg << ", Frame ID = " <<
frameIdVdec_ << ", Channel ID = " << channelIdVdec_;
}
LogDebug << "End to process SceneMutationDetection.";
return APP_ERR_OK;
}
float MxpiQualityDetection::PTZMovementHistSim(const Mat &imageGrayAvg1, const Mat &imageGrayAvg2)
{
const int histSize = 256;
const float range[] = { 0, 256 };
const float *histRange = { range };
bool uniform = true;
bool accumulate = false;
Mat hist1, hist2;
calcHist(&imageGrayAvg1, 1, 0, Mat(), hist1, 1, &histSize, &histRange, uniform, accumulate);
normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());
calcHist(&imageGrayAvg2, 1, 0, Mat(), hist2, 1, &histSize, &histRange, uniform, accumulate);
normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());
float histSimilarity = compareHist(hist1, hist2, HISTCMP_CORREL);
return histSimilarity;
}
APP_ERROR MxpiQualityDetection::PTZMovementDetection(void)
{
LogDebug << "Begin to process PTZMovementDetection.";
if (FrameSkip(switchPTZMovementDetection_, frameIntervalPTZMovementDetection_)) {
return APP_ERR_OK;
}
FrameInfo image = frameList_[frameListMaxLen_ - 1];
Mat imageGray;
cvtColor(image.rgbData, imageGray, cv::COLOR_RGB2GRAY);
const uint32_t defaultScalarValue = 255;
Mat imageGraySum1(imageGray.rows, imageGray.cols, CV_32FC1, Scalar(defaultScalarValue));
Mat imageGraySum2(imageGray.rows, imageGray.cols, CV_32FC1, Scalar(defaultScalarValue));
const uint32_t medianDivisor = 2;
uint32_t startFrameIdx = frameListMaxLen_ - frameIntervalPTZMovementDetection_ - 1;
uint32_t midFrameIdx = startFrameIdx + (frameIntervalPTZMovementDetection_ / medianDivisor);
for (size_t i = startFrameIdx; i < midFrameIdx; i++) {
cvtColor(frameList_[i].rgbData, imageGray, cv::COLOR_RGB2GRAY);
accumulate(imageGray, imageGraySum1);
}
for (size_t j = midFrameIdx; j < frameListMaxLen_; j++) {
cvtColor(frameList_[j].rgbData, imageGray, cv::COLOR_RGB2GRAY);
accumulate(imageGray, imageGraySum2);
}
auto frameIdxDifference = midFrameIdx - startFrameIdx;
auto listMaxLenIdxDifference = frameListMaxLen_ - midFrameIdx;
if (IsDenominatorZero(frameIdxDifference) || IsDenominatorZero(listMaxLenIdxDifference)) {
LogError << "The value of frameIdxDifference or listMaxLenIdxDifference must not equal to 0!"
<< GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
return APP_ERR_COMM_INVALID_PARAM;
}
imageGraySum1 /= frameIdxDifference;
imageGraySum2 /= listMaxLenIdxDifference;
Mat imageGrayAvg1, imageGrayAvg2;
imageGraySum1.convertTo(imageGrayAvg1, CV_8UC1, 1, 0);
imageGraySum2.convertTo(imageGrayAvg2, CV_8UC1, 1, 0);
float simHist = PTZMovementHistSim(imageGrayAvg1, imageGrayAvg2);
if (simHist > thresholdPTZMovementDetection_) {
LogWarn << "PTZ Movement Detection: Abnormal, Movement Rate = " << simHist << ", Frame ID = " << frameIdVdec_ <<
", Channel ID = " << channelIdVdec_;
} else {
LogDebug << "PTZ Movement Detection: Normal, Frame ID = " << frameIdVdec_ << ", Channel ID = " <<
channelIdVdec_;
}
LogDebug << "End to process PTZMovementDetection.";
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ImageFormatConversion(MxpiVision visionItem)
{
MxpiVisionInfo visionItemInfo = visionItem.visioninfo();
MxpiVisionData visionItemData = visionItem.visiondata();
auto inputData = visionItemData.dataptr();
auto dataSize = (uint32_t)visionItemData.datasize();
uint32_t dstImageWidth = visionItemInfo.widthaligned();
uint32_t dstImageHeigh = visionItemInfo.heightaligned();
uint32_t srcImageWidth = dstImageWidth;
uint32_t srcImageHeigh = static_cast<uint32_t>(dstImageHeigh * NV12_COEF);
MemoryData dataDevice((void *)inputData, dataSize, MxBase::MemoryData::MEMORY_DEVICE);
MemoryData dataHost(dataSize, MxBase::MemoryData::MEMORY_HOST);
APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(dataHost, dataDevice);
if (ret != APP_ERR_OK) {
errorInfo_ << "Failed to create destination memory, type(" << dataHost.type
<< "), size(" << dataHost.size << ")." << GetErrorInfo(ret);
LogError << errorInfo_.str();
return ret;
}
Mat srcNV12Mat(srcImageHeigh, srcImageWidth, CV_8UC1, dataHost.ptrData);
Mat dstRGB888(dstImageHeigh, dstImageWidth, CV_8UC3);
cvtColor(srcNV12Mat, dstRGB888, COLOR_YUV2RGB_NV12);
ret = MxBase::MemoryHelper::MxbsFree(dataHost);
if (ret != APP_ERR_OK) {
errorInfo_ << "Fail to free host memory." << GetErrorInfo(ret);
LogError << errorInfo_.str();
return ret;
}
if (frameList_.size() >= frameListMaxLen_) {
frameList_.pop_front();
}
FrameInfo imageInfo = { frameIdCur_, frameIdVdec_, channelIdVdec_, dstRGB888 };
frameList_.push_back(imageInfo);
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::DetectionProcess(void)
{
if (frameList_.size() < frameListMaxLen_) {
LogInfo << "The list size of frameList_ is less than " << frameListMaxLen_ << ", Channel ID = " <<
channelIdVdec_;
return APP_ERR_OK;
}
DetectionWithKey(static_cast<int>(DetectionType::IMAGE_BRIGHTNESS_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::IMAGE_OCCLUSION_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::IMAGE_BLUR_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::IMAGE_NOISE_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::IMAGE_COLOR_CAST_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::IMAGE_STRIPE_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::BLACK_SCREEN_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::SCENE_MUTATION_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::PTZ_MOVEMENT_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::VIEW_SHAKE_DETECTION));
DetectionWithKey(static_cast<int>(DetectionType::VIDEO_FREEZE_DETECTION));
return APP_ERR_OK;
}
APP_ERROR MxpiQualityDetection::ImageProcessAndDetection(MxpiBuffer &buffer)
{
APP_ERROR ret = APP_ERR_OK;
MxpiMetadataManager mxpiMetadataManager(buffer);
shared_ptr<void> metadata = mxpiMetadataManager.GetMetadata(dataSource_);
if (metadata == nullptr) {
errorInfo_ << "Metadata is null." << GetErrorInfo(APP_ERR_MXPLUGINS_METADATA_IS_NULL);
LogError << errorInfo_.str();
return APP_ERR_MXPLUGINS_METADATA_IS_NULL;
}
auto message = (google::protobuf::Message *)metadata.get();
const google::protobuf::Descriptor *desc = message->GetDescriptor();
if (!desc) {
errorInfo_ << "Get input data's descriptor failed." << GetErrorInfo(APP_ERR_COMM_INVALID_PARAM);
LogError << errorInfo_.str();
return APP_ERR_COMM_INVALID_PARAM;
}
if (desc->name() != QUALITY_DETECTION_KEY) {
errorInfo_ << "Not a MxpiVisionList." << GetErrorInfo(APP_ERR_MXPLUGINS_PROTOBUF_NAME_MISMATCH);
LogError << errorInfo_.str();
return APP_ERR_MXPLUGINS_PROTOBUF_NAME_MISMATCH;
}
shared_ptr<void> metadataFrameInfo = mxpiMetadataManager.GetMetadata("ReservedFrameInfo");
if (metadataFrameInfo == nullptr) {
LogError << "Fail to get meta data." << GetErrorInfo(APP_ERR_COMM_FAILURE);
return APP_ERR_COMM_FAILURE;
}
shared_ptr<MxpiFrameInfo> mxpiFrameInfo = static_pointer_cast<MxpiFrameInfo>(metadataFrameInfo);
frameIdVdec_ = mxpiFrameInfo->frameid();
channelIdVdec_ = mxpiFrameInfo->channelid();
shared_ptr<MxpiVisionList> mxpiVisionList = static_pointer_cast<MxpiVisionList>(metadata);
for (int i = 0; i < mxpiVisionList->visionvec_size(); i++) {
MxpiVision visionItem = mxpiVisionList->visionvec(i);
ret = ImageFormatConversion(visionItem);
if (ret != APP_ERR_OK) {
LogError << errorInfo_.str() << GetErrorInfo(ret);
return ret;
}
ret = DetectionProcess();
if (ret != APP_ERR_OK) {
errorInfo_ << "Failed to finish detection process." << GetErrorInfo(ret);
return APP_ERR_COMM_FAILURE;
}
frameIdCur_++;
}
return ret;
}
APP_ERROR MxpiQualityDetection::Process(std::vector<MxpiBuffer *> &mxpiBuffer)
{
LogDebug << "Begin to process MxpiQualityDetection(" << elementName_ << ").";
auto ret = CheckMxpiBufferIsValid(mxpiBuffer);
if (ret != APP_ERR_OK) {
return ret;
}
MxpiBuffer *buffer = mxpiBuffer[0];
errorInfo_.str("");
ret = ImageProcessAndDetection(*buffer);
if (ret != APP_ERR_OK) {
LogError << errorInfo_.str() << GetErrorInfo(ret);
SendMxpiErrorInfo(*buffer, elementName_, ret, errorInfo_.str());
return ret;
}
SendData(0, *buffer);
LogDebug << "End to process MxpiQualityDetection(" << elementName_ << ").";
return ret;
}
std::vector<std::shared_ptr<void>> MxpiQualityDetection::DefineProperties()
{
std::vector<std::shared_ptr<void>> properties;
auto configContent = std::make_shared<ElementProperty<string>>(ElementProperty<string>{
STRING, "qualityDetectionConfigContent", "config", "config content, its type is [json::object]", "", "", ""});
auto configPath = std::make_shared<ElementProperty<string>>(
ElementProperty<string>{STRING, "qualityDetectionConfigPath", "config", "config path", "", "", ""});
properties.push_back(configContent);
properties.push_back(configPath);
return properties;
}
MxpiPortInfo MxpiQualityDetection::DefineInputPorts()
{
MxpiPortInfo inputPortInfo;
std::vector<std::vector<std::string>> value = { { "image/yuv", "metadata/object" } };
GenerateStaticInputPortsInfo(value, inputPortInfo);
return inputPortInfo;
}
MxpiPortInfo MxpiQualityDetection::DefineOutputPorts()
{
MxpiPortInfo outputPortInfo;
std::vector<std::vector<std::string>> value = { { "ANY" } };
GenerateStaticOutputPortsInfo(value, outputPortInfo);
return outputPortInfo;
}
APP_ERROR MxpiQualityDetection::DetectionWithKey(int detectionType)
{
using detectionMap = map<int, DoDetection>::const_iterator;
detectionMap iter = keyToHandle.find(detectionType);
DoDetection detectionFunc = iter->second;
return (this->*detectionFunc)();
}
void MxpiQualityDetection::MapKeyToHandle(void)
{
keyToHandle[static_cast<int>(DetectionType::IMAGE_BRIGHTNESS_DETECTION)] =
&MxpiQualityDetection::ImageBrightnessDetection;
keyToHandle[static_cast<int>(DetectionType::IMAGE_OCCLUSION_DETECTION)] =
&MxpiQualityDetection::ImageOcclusionDetection;
keyToHandle[static_cast<int>(DetectionType::IMAGE_BLUR_DETECTION)] =
&MxpiQualityDetection::ImageBlurDetection;
keyToHandle[static_cast<int>(DetectionType::IMAGE_NOISE_DETECTION)] =
&MxpiQualityDetection::ImageNoiseDetection;
keyToHandle[static_cast<int>(DetectionType::IMAGE_COLOR_CAST_DETECTION)] =
&MxpiQualityDetection::ImageColorCastDetection;
keyToHandle[static_cast<int>(DetectionType::IMAGE_STRIPE_DETECTION)] =
&MxpiQualityDetection::ImageStripeDetection;
keyToHandle[static_cast<int>(DetectionType::BLACK_SCREEN_DETECTION)] =
&MxpiQualityDetection::BlackScreenDetection;
keyToHandle[static_cast<int>(DetectionType::VIDEO_FREEZE_DETECTION)] =
&MxpiQualityDetection::VideoFreezeDetection;
keyToHandle[static_cast<int>(DetectionType::VIEW_SHAKE_DETECTION)] =
&MxpiQualityDetection::ViewShakeDetection;
keyToHandle[static_cast<int>(DetectionType::SCENE_MUTATION_DETECTION)] =
&MxpiQualityDetection::SceneMutationDetection;
keyToHandle[static_cast<int>(DetectionType::PTZ_MOVEMENT_DETECTION)] =
&MxpiQualityDetection::PTZMovementDetection;
}
MX_PLUGIN_GENERATE(MxpiQualityDetection)