C++基于opencv的视频质量检测--图像清晰度检测

文章目录

    • 0.引言
    • [1. 原始算法实现](#1. 原始算法实现)
    • [2. 优化思路](#2. 优化思路)
    • [3. 优化后的代码](#3. 优化后的代码)
    • [4. 代码详细解读](#4. 代码详细解读)

0.引言

视频质量图像清晰度检测已在C++基于opencv4的视频质量检测中有所介绍,本文将详细介绍其优化版本。

1. 原始算法实现

原始代码:

cpp 复制代码
double sharpnessDetect(const cv::Mat& srcImg) {
  const int kGaussianSize = 3;  // 高斯模糊的核大小

  cv::Mat grayImg;
  if (srcImg.channels() != 1) {
    cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);
  } else {
    grayImg = srcImg;
  }

  cv::Mat blurredImg;
  cv::GaussianBlur(grayImg, blurredImg, cv::Size(kGaussianSize, kGaussianSize), 0);

  uint64_t sumFver = 0;
  uint64_t sumFhor = 0;
  uint64_t sumVver = 0;
  uint64_t sumVhor = 0;
  double blurFactor = 0.0;

  for (int r = 0; r < grayImg.rows; ++r) {
    for (int c = 0; c < grayImg.cols; ++c) {
      uint64_t diffFver = 0;
      uint64_t diffFhor = 0;
      uint64_t diffBver = 0;
      uint64_t diffBhor = 0;
      if (r != 0) {
        diffFver = static_cast<uint64_t>(std::abs(grayImg.at<uchar>(r, c) - grayImg.at<uchar>(r - 1, c)));
      }
      if (c != 0) {
        diffFhor = static_cast<uint64_t>(std::abs(grayImg.at<uchar>(r, c) - grayImg.at<uchar>(r, c - 1)));
      }
      if (r != 0) {
        diffBver = static_cast<uint64_t>(std::abs(blurredImg.at<uchar>(r, c) - blurredImg.at<uchar>(r - 1, c)));
      }
      if (c != 0) {
        diffBhor = static_cast<uint64_t>(std::abs(blurredImg.at<uchar>(r, c) - blurredImg.at<uchar>(r, c - 1)));
      }

      uint64_t verDiff = (diffFver > diffBver) ? (diffFver - diffBver) : 0;
      uint64_t horDiff = (diffFhor > diffBhor) ? (diffFhor - diffBhor) : 0;

      sumFver += diffFver;
      sumFhor += diffFhor;
      sumVver += verDiff;
      sumVhor += horDiff;
    }
  }

  double bFver = (static_cast<double>(sumFver - sumVver)) / (static_cast<double>(sumFver) + 1.0);
  double bFhor = (static_cast<double>(sumFhor - sumVhor)) / (static_cast<double>(sumFhor) + 1.0);
  blurFactor = (bFver > bFhor) ? bFver : bFhor;

  return 1.0 - blurFactor;
}

以下是原始代码的主要步骤:

  1. 图像预处理:将输入图像转换为灰度图。
  2. 高斯模糊:对灰度图像进行高斯模糊处理,得到模糊图像。
  3. 梯度计算:通过遍历每个像素,计算原始图像和模糊图像在垂直和水平方向上的梯度差异。
  4. 模糊因子计算:根据梯度差异,计算模糊因子,进而评估图像的清晰度。

存在的问题:

  • 效率低下 :使用嵌套的for循环遍历每个像素,手动计算梯度,处理大尺寸图像时效率较低。

2. 优化思路

为了解决上述问题,我们对原始算法进行了以下优化:

  1. 向量化操作,避免显式循环:利用OpenCV的矩阵运算和函数,对整个图像进行批量处理,提高计算效率。
  2. 使用Sobel算子计算梯度:Sobel算子是常用的梯度计算方法,能够有效地提取图像的边缘信息。

3. 优化后的代码

以下是优化后的sharpnessDetect函数:

cpp 复制代码
double sharpnessDetect(const cv::Mat& srcImg) {
    const int kGaussianSize = 3;  // 高斯模糊的核大小

    cv::Mat grayImg;
    if (srcImg.channels() != 1) {
        cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);
    } else {
        grayImg = srcImg;
    }

    // 对灰度图像进行高斯模糊
    cv::Mat blurredImg;
    cv::GaussianBlur(grayImg, blurredImg, cv::Size(kGaussianSize, kGaussianSize), 0);

    // 计算原始图像和模糊图像的梯度
    cv::Mat gradXOrig, gradYOrig;
    cv::Mat gradXBlur, gradYBlur;

    cv::Sobel(grayImg, gradXOrig, CV_64F, 1, 0, 3);
    cv::Sobel(grayImg, gradYOrig, CV_64F, 0, 1, 3);

    cv::Sobel(blurredImg, gradXBlur, CV_64F, 1, 0, 3);
    cv::Sobel(blurredImg, gradYBlur, CV_64F, 0, 1, 3);

    // 计算梯度的绝对值
    cv::Mat absGradXOrig = cv::abs(gradXOrig);
    cv::Mat absGradYOrig = cv::abs(gradYOrig);

    cv::Mat absGradXBlur = cv::abs(gradXBlur);
    cv::Mat absGradYBlur = cv::abs(gradYBlur);

    // 计算梯度差的正值部分
    cv::Mat diffX = absGradXOrig - absGradXBlur;
    cv::Mat diffY = absGradYOrig - absGradYBlur;

    diffX = cv::max(diffX, 0);
    diffY = cv::max(diffY, 0);

    // 计算梯度的总和
    double sumFhor = cv::sum(absGradXOrig)[0];
    double sumFver = cv::sum(absGradYOrig)[0];

    // 计算梯度差的总和
    double sumVhor = cv::sum(diffX)[0];
    double sumVver = cv::sum(diffY)[0];

    // 计算模糊因子
    double bFver = (sumFver - sumVver) / (sumFver + 1e-6);
    double bFhor = (sumFhor - sumVhor) / (sumFhor + 1e-6);
    double blurFactor = std::max(bFver, bFhor);

    // 返回清晰度得分
    return 1.0 - blurFactor;
}

4. 代码详细解读

否 是 开始 图像是否为灰度图? 转换为灰度图 跳过转换 对灰度图像进行高斯模糊 计算原始图像和模糊图像的梯度 计算梯度的绝对值 计算梯度差的正值部分 计算梯度的总和 计算模糊因子 返回清晰度得分

流程说明:

  • 开始 :函数sharpnessDetect开始执行。
  • 检查图像通道数 :判断输入图像是否为灰度图。
    • 如果不是,转换为灰度图。
    • 如果是,跳过转换。
  • 高斯模糊:对灰度图像进行高斯模糊处理,得到模糊图像。
  • 计算梯度:使用Sobel算子计算原始图像和模糊图像在x和y方向的梯度。
  • 计算梯度的绝对值:对梯度矩阵取绝对值。
  • 计算梯度差的正值部分:计算原始梯度和模糊梯度之间的差异,保留正值部分。
  • 计算梯度的总和:分别计算原始梯度和差异梯度的总和。
  • 计算模糊因子:根据梯度总和计算模糊因子。
  • 返回结果:根据模糊因子计算清晰度得分,返回结果。

优化细节解读

  • 使用Sobel算子计算梯度cv::Sobel函数可以高效地计算图像在x和y方向的梯度,避免了手动计算相邻像素差异的繁琐过程。

  • 向量化操作 :通过cv::abscv::sum等函数,对整个矩阵进行操作,充分利用了底层的优化和并行计算能力。

  • 梯度差的正值部分 :使用cv::max函数,将梯度差中的负值置零,保留正值部分,与原始代码的逻辑一致。

  • 防止除零错误 :在计算模糊因子时,分母加上了一个很小的值1e-6,防止除以零的情况。

  • 数据类型选择 :使用CV_64F(双精度浮点型)确保计算的精度,避免数据溢出和精度损失。

相关推荐
Ritsu栗子28 分钟前
代码随想录算法训练营day35
c++·算法
好一点,更好一点38 分钟前
systemC示例
开发语言·c++·算法
卷卷的小趴菜学编程1 小时前
c++之List容器的模拟实现
服务器·c语言·开发语言·数据结构·c++·算法·list
年轮不改1 小时前
Qt基础项目篇——Qt版Word字处理软件
c++·qt
玉蜉蝣1 小时前
PAT甲级-1014 Waiting in Line
c++·算法·队列·pat甲·银行排队问题
AI视觉网奇2 小时前
python 统计相同像素值个数
python·opencv·计算机视觉
半盏茶香3 小时前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
哎呦,帅小伙哦3 小时前
Effective C++ 规则41:了解隐式接口和编译期多态
c++·effective c++
DARLING Zero two♡4 小时前
【初阶数据结构】逆流的回环链桥:双链表
c语言·数据结构·c++·链表·双链表
9毫米的幻想4 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++