C++基于opencv4的视频质量检测

C++基于opencv的视频质量检测原理来源

  • 请参考原作者的文章 , 本文引用了实现的思想说明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

你可能感兴趣的:(c++,计算机视觉,opencv,视频质量检测,视频质量)