请参考原作者的文章 , 本文引用了实现的思想说明https://www.cnblogs.com/wqvbjhc/tag/%E8%A7%86%E9%A2%91%E8%B4%A8%E9%87%8F%E8%AF%8A%E6%96%AD/
系列文章如下
视频质量诊断----亮度异常检测
视频质量诊断----色度异常检测
视频质量诊断----雪花噪声检测
视频质量诊断----条纹噪声检测
视频质量诊断----模糊检测
视频质量诊断----信号丢失检测
视频质量诊断----遮挡检测
视频质量诊断----画面冻结检测
视频质量诊断----PTZ云台运动检测
视频质量诊断----画面抖动检测
一、遮挡检测一般是摄像头被异物遮挡,呈现出整个场景或某一部分场景看不到的情况。被遮挡住的部分一般都呈偏黑色。
二、原理
把彩色图像二值化,偏黑的部分为前景,其他部分为背景。
对前景进行连通区域检测,求得最大连通区域面积。
该面积整幅图像面积的比较即为遮挡率。
三、C++实现代码
double blockDetect(const cv::Mat &srcImg)
{
cv::Mat img, cont;
cv::cvtColor(srcImg, img, CV_RGB2GRAY);
cv::GaussianBlur(img, img, cv::Size(3, 3), 0, 0);
cv::Canny(img, cont, 0, 0);
std::vector<std::vector<Point>> contours;
std::vector<Vec4i> hierarchy;
// contour
cv::findContours(cont, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
int sum1 = hierarchy.size();
cv::Canny(img, cont, 0, 15);
cv::findContours(cont, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
int sum2 = hierarchy.size();
return (double)1 - (double)sum2 / (sum1 == 0 ? 1 : sum1);
}
一、信号丢失检测也称无信号检测,一般当DVR/NVR某些通道没接上摄像头时,会显示黑屏无信号。而IPC无信号里无法返回任何图像信息,也就无法通过图像算法检测到。
二、原理
把彩色图像二值化,偏黑的部分为前景,其他部分为背景。
对前景进行连通区域检测,求得最大连通区域面积。
该面积整幅图像面积的比较即为信号丢失率。
三、C++实现代码
/**
*@brief 该函数为检测信号函数。
*@return 返回一个double类型的数,数值为0-1之间。返回的数值越接近1,越有可能是无信号时传输过来的图片
*/
double signalDetect(const cv::Mat &srcImg)
{
cv::Mat img;
int width = srcImg.cols;
int height = srcImg.rows;
while (width > 352 && height > 288)
{
width >>= 1;
height >>= 1;
}
cv::resize(srcImg, img, cv::Size(width, height));
cv::cvtColor(img, img, COLOR_RGB2GRAY);
if (img.empty())
{
return 0;
}
//平滑处理
int sizeW = 0.2 * img.cols;
if (sizeW % 2 == 0)
sizeW += 1;
int sizeH = 0.3 * img.rows;
if (sizeH % 2 == 0)
sizeH += 1;
cv::GaussianBlur(img, img, cv::Size(21, 21), 0, 0);
//找出画面轮廓
cv::Canny(img, img, 0, 0);
std::vector<std::vector<Point>> contours;
std::vector<Vec4i> hierarchy;
//查找contour
cv::findContours(img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
int area = 10;
double sum = 0;
for (int i = 0; i < contours.size(); i++)
{
area = fabs(contourArea(contours[i]));
sum++;
}
//扩大差距
double imgArea = img.cols * img.rows;
sum *= sum;
double res = sum / imgArea;
res *= res;
return (double)1 - (res / 100 > 1 ? 1 : res / 100);
}
一、亮度异常检测一般包括偏暗检测和偏亮检测,也有称过暗过亮检测。这算法简单,只需要一帧图像的亮度值作为判断就行。
二、原理
把彩色图像转化为灰度图像
求图像的平均灰度值G(整幅或ROI区域),该值就是图像的亮度值
定义阈值A,B。当G∈[0,A]认为图像偏暗,当G∈[B,255]认为图像偏亮
三、C++实现代码
double brightnessDetect(const cv::Mat &srcImg)
{
cv::Mat img;
cv::cvtColor(srcImg, img, CV_BGR2Lab);
int br;
double bright = 0.0;
auto width = srcImg.cols;
auto height = srcImg.rows;
for (int r = 0; r < height; r++)
{
for (int c = 0; c < width; c++)
{
br = img.at<Vec3b>(r, c)[0];
bright += br / 2.55 / width / height;
}
}
return bright / 100;
}
一、雪花噪声即椒盐噪声,以前黑白电视常见的噪声现象。
二、原理
准备0°,45°,90°,135°4个方向的卷积模板。
用图像先和四个模板做卷积,用四个卷积绝对值最小值Min来检测噪声点。
求灰度图gray与其中值滤波图median。
判断噪声点:fabs(median-gray)>10 && min>0.1。
噪声点占整幅图像的比较即为雪花噪声率。
三、C++代码实现
/**
*@brief 该函数为检测雪花噪点数函数。
*@return 返回一个double类型的数,数值为0-1之间。返回的数值越接近1,说明该图雪花噪点数越多。反之越少。
*/
double snowNoiseDetect(const cv::Mat &srcImg)
{
cv::Mat img;
if (srcImg.empty())
return -1;
if (srcImg.channels() == 1) //转换为单通道图
img = srcImg;
else
cv::cvtColor(srcImg, img, COLOR_BGR2GRAY);
cv::Mat img_m;
int width = img.cols;
int height = img.rows;
//对图像进行均值滤波去噪
// cvSmo oth(img,img_m,CV_MEDIAN,3,img->nChannels);
cv::Mat kernel_gauss = (Mat_<double>(3, 3) << 1, 2, 1,
2, 4, 2,
1, 2, 1);
kernel_gauss /= 16;
filter2D(img, img_m, img.depth(), kernel_gauss, Point(-1, -1));
double psignal, pnoise; //信号功率 噪音功率
int gray_a, gray_b;
double snr; //信噪比
psignal = 0;
pnoise = 0;
for (int r = 0; r < height; r++)
{
for (int c = 0; c < width; c++)
{
gray_a = img_m.at<uchar>(r, c);
gray_b = img.at<uchar>(r, c);
psignal += (double)gray_b * (double)gray_b / 255 / 255; //这里是求噪音所占信号的比例
pnoise += (double)(gray_b - gray_a) * (double)(gray_b - gray_a) / 255 / 255;
}
}
if (psignal < 1)
psignal = 1;
if (pnoise < 1)
pnoise = 1;
snr = 20 * log(((double)psignal) / ((double)pnoise));
return snr; //返回信噪比,即图像质量
}
一、模糊一般是摄像头焦距没调好造成的画面模糊。
二、原理
把图像分割成N*M的区域。
求每个区域的对比度:(max-min)/max.
求总的平均对比度即为模糊率。
三、C++代码实现
/**
*@brief 该函数为检测图片的清晰度度函数。
*@return 返回一个double类型的数,数值为0-1之间。返回的数值越接近1,说明该图越清晰。反之越模糊。
*/
double sharpnessDetect(const cv::Mat &srcImg)
{
//高斯模糊区域大小
int gaussianSize = 3;
cv::Mat img;
if (srcImg.channels() != 1) //如果输入的图像不是单通道灰度图,则转换为灰度图
cv::cvtColor(srcImg, img, COLOR_BGR2GRAY);
else
img = srcImg;
cv::Mat out;
//进行高斯处理,处理的是指针img指向的内存,将处理后的数据交给out指针指向的内存,对每个像素周围gaussianSize*gaussianSize的区域进行高斯平滑处理(其实输入输出图像可以是相同的)
cv::GaussianBlur(img, out, cv::Size(gaussianSize, gaussianSize), 0, 0);
unsigned long d_Fver = 0, d_Fhor = 0, d_Bver = 0, d_Bhor = 0; //水平统计,垂直统计,F是原图,B是模糊图
unsigned long vver = 0, vhor = 0;
unsigned long s_Fver = 0, s_Fhor = 0, s_Vver = 0, s_Vhor = 0;
double b_Fver = 0.0, b_Fhor = 0.0;
double blur_F = 0.0;
for (int r = 0; r < img.rows; r++)
{
for (int c = 0; c < img.cols; c++)
{
//垂直统计
if (r != 0) //如果不是最上侧的点
d_Fver = abs(img.at<uchar>(r, c) - img.at<uchar>(r - 1, c)); //与上侧点的像素值相减
//水平统计
if (c != 0) //如果不是最左侧的点,
d_Fhor = abs(img.at<uchar>(r, c) - img.at<uchar>(r, c - 1));
//垂直统计
if (r != 0) //如果不是最上侧的点
d_Bver = abs(out.at<uchar>(r, c) - out.at<uchar>(r - 1, c));
//水平统计
if (c != 0) //如果不是最左侧的点,
d_Bhor = abs(out.at<uchar>(r, c) - out.at<uchar>(r, c - 1));
vver = (d_Fver - d_Bver > 0) ? (d_Fver - d_Bver) : 0;
vhor = (d_Fhor - d_Bhor > 0) ? (d_Fhor - d_Bhor) : 0;
s_Fver += d_Fver;
s_Fhor += d_Fhor;
s_Vver += vver;
s_Vhor += vhor;
}
}
b_Fver = (s_Fver - s_Vver) / ((double)s_Fver + 1);
b_Fhor = (s_Fhor - s_Vhor) / ((double)s_Fhor + 1);
blur_F = (b_Fver > b_Fhor) ? b_Fver : b_Fhor;
return 1 - blur_F;
}
一、当摄像头立杆不稳或因车辆引起地面振动时,视频画面就会发生抖动。
二、原理
每隔N帧取一帧。
对取到的每帧进行特征点提取。
对检测的相邻2帧进行特征点匹配。
得到匹配矩阵,当匹配矩阵大于A时认为这2帧画面有抖动。
当抖动帧数大于B时认为画面发生抖动。
三、C++实现代码
TODO
一、PTZ云台运动检测是通过配合云台运动的功能检测云台运动是否正常。
二、原理
取云台运动前N帧图像,进行背景建模,得到运动前背景A。
设备发送云台运动指令,让云台进行运动,改变场景。
取云台运动后N帧图像,进行背景建模,得到运动后背景B。
对比A,B颜色直方图的相似度,大于K时认为PTZ云台运动有故障。
三、C++实现代码
TODO
一、PTZ云台运动检测是通过配合云台运动的功能检测云台运动是否正常。
二、原理
取云台运动前N帧图像,进行背景建模,得到运动前背景A。
设备发送云台运动指令,让云台进行运动,改变场景。
取云台运动后N帧图像,进行背景建模,得到运动后背景B。
对比A,B颜色直方图的相似度,大于K时认为PTZ云台运动有故障。
三、C++实现代码
TODO
一、条纹噪声是带条状的噪声。
二、原理
提取彩色图像的色度分量。
对色度分量求DFT频谱图。
计算频谱图的异常亮点数,若大于A则认为发生条纹检测。
三、C++实现代码
TODO
一、色度异常检测一般称为偏色检测。 即图像为某一范围颜色值分布过多而导致图像整体偏色的情况。
二、原理
提取图像的色度分量H
计算色度分量H的直方图
求最方图最大bin占整个直方图的比例,该比例值就为偏色值
三、C++实现代码
TODO