您的位置:首页 > 财经 > 产业 > 北京商场租金_天津网站建设工作室_百度在线咨询_怎么交换友情链接

北京商场租金_天津网站建设工作室_百度在线咨询_怎么交换友情链接

2024/11/16 5:57:30 来源:https://blog.csdn.net/stallion5632/article/details/143278999  浏览:    关键词:北京商场租金_天津网站建设工作室_百度在线咨询_怎么交换友情链接
北京商场租金_天津网站建设工作室_百度在线咨询_怎么交换友情链接

文章目录

    • 0.引言
    • 1. 原始代码分析
    • 2. 优化方案
    • 3. 优化后的代码
    • 4. 代码详细解读

0.引言

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

1. 原始代码分析

首先,我们来看图像抖动检测的原始代码:

#include <algorithm>
#include <cmath>
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <vector>namespace {
constexpr int kMinHessian = 400;
constexpr int kMinKeypoints = 20;
constexpr double kScaleWidth = 800.0;
constexpr double kInvalidReturn = -1.0;
constexpr double kDefaultMinDist = 100.0;
constexpr int kRoiYOffset = 5;
constexpr int kRoiHeightFactor = 3;
constexpr int kGoodMatchesCount = 50;
constexpr int kFilterThresholdFactor = 4;
constexpr int kFilterEndFactor = 3;
}  // namespace/*** @brief 检测图像抖动的函数。* @param [in] srcImg 待检测的图像* @param [in] refImg 参考图像* @param [out] offsetX 待检测图像相对于参考图像在x轴上的偏移量* @param [out] offsetY 待检测图像相对于参考图像在y轴上的偏移量* @return 返回函数执行的状态* @retval 0 表示成功* @retval -1 表示失败*/
int JitterDetect(const cv::Mat& srcImg, const cv::Mat& refImg, double& offsetX, double& offsetY) {if (srcImg.empty() || refImg.empty()) {return -1;}cv::Mat img = srcImg.clone();cv::Mat imgRef = refImg.clone();cv::Rect roi(0, img.rows / kRoiYOffset, img.cols, img.rows * kRoiHeightFactor / kRoiYOffset);img = img(roi);imgRef = imgRef(roi);double scale = 1.0;cv::Mat imgScaled, imgRefScaled;if (img.cols > kScaleWidth) {scale = kScaleWidth / static_cast<double>(img.cols);cv::resize(img, imgScaled, cv::Size(static_cast<int>(kScaleWidth), static_cast<int>(scale * img.rows)));cv::resize(imgRef, imgRefScaled, cv::Size(static_cast<int>(kScaleWidth), static_cast<int>(scale * img.rows)));} else {imgScaled = img;imgRefScaled = imgRef;}cv::Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create(kMinHessian);std::vector<cv::KeyPoint> keypoints1, keypoints2;detector->detect(imgScaled, keypoints1);detector->detect(imgRefScaled, keypoints2);if (keypoints1.size() < kMinKeypoints || keypoints2.size() < kMinKeypoints) {return -1;}cv::Ptr<cv::xfeatures2d::SURF> extractor = cv::xfeatures2d::SURF::create();cv::Mat descriptors1, descriptors2;extractor->compute(imgScaled, keypoints1, descriptors1);extractor->compute(imgRefScaled, keypoints2, descriptors2);cv::FlannBasedMatcher matcher;std::vector<cv::DMatch> matches;matcher.match(descriptors1, descriptors2, matches);double minDist = kDefaultMinDist;for (const auto& match : matches) {if (match.distance < minDist) {minDist = match.distance;}}std::vector<cv::DMatch> goodMatches;std::vector<float> distances(matches.size());for (size_t i = 0; i < matches.size(); ++i) {distances[i] = matches[i].distance;}std::sort(distances.begin(), distances.end());double distFlag =(matches.size() < kGoodMatchesCount) ? distances[matches.size() - 1] : distances[kGoodMatchesCount - 1];for (size_t i = 0, cntK = 0; i < matches.size() && cntK < kGoodMatchesCount; ++i) {if (matches[i].distance <= distFlag) {goodMatches.push_back(matches[i]);++cntK;}}std::vector<float> moveX(goodMatches.size()), moveY(goodMatches.size());for (size_t i = 0; i < goodMatches.size(); ++i) {moveX[i] = std::abs(keypoints1[goodMatches[i].queryIdx].pt.x - keypoints2[goodMatches[i].trainIdx].pt.x);moveY[i] = std::abs(keypoints1[goodMatches[i].queryIdx].pt.y - keypoints2[goodMatches[i].trainIdx].pt.y);}std::sort(moveX.begin(), moveX.end());std::sort(moveY.begin(), moveY.end());for (size_t p = goodMatches.size() / kFilterThresholdFactor;p < goodMatches.size() * kFilterEndFactor / kFilterThresholdFactor; ++p) {offsetX += moveX[p];offsetY += moveY[p];}offsetX /= (goodMatches.size() / 2);offsetY /= (goodMatches.size() / 2);if (scale != 1.0) {offsetX *= scale;offsetY *= scale;}return 0;
}

以下是原始代码的核心步骤:

  • 图像预处理:对输入图像和参考图像进行ROI裁剪和缩放。
  • 特征检测与描述子计算:使用SURF算法检测关键点并计算描述子。
  • 特征匹配:使用FLANN匹配器匹配描述子。
  • 匹配点筛选:根据距离筛选好的匹配点。
  • 偏移量计算:手动计算匹配点之间的位移,得到图像的偏移量。

2. 优化方案

我们对代码进行如下优化:

  • 移除不必要的图像拷贝:避免使用clone(),直接在ROI裁剪后的图像上进行操作,减少内存占用和拷贝时间。
  • 合并特征检测和描述子计算:使用detectAndCompute方法,将特征检测和描述子计算合并,提高效率。
  • 简化特征匹配流程:通过排序匹配结果,直接选择距离最小的前N个匹配点,简化了匹配筛选过程。
  • 采用鲁棒的变换估计方法:使用cv::estimateAffinePartial2D函数结合RANSAC算法,更准确地估计图像间的平移和旋转,增强鲁棒性。
  • 直接提取平移量:从估计的仿射变换矩阵中直接获取偏移量,避免手动计算的复杂性。

3. 优化后的代码

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>namespace {
constexpr int kMinHessian = 400;
constexpr int kMinKeypoints = 20;
constexpr double kScaleWidth = 800.0;
constexpr int kRoiYOffset = 5;
constexpr int kRoiHeightFactor = 3;
}  // namespace/*** @brief 检测图像抖动的函数。* @param [in] srcImg 待检测的图像* @param [in] refImg 参考图像* @param [out] offsetX 待检测图像相对于参考图像在x轴上的偏移量* @param [out] offsetY 待检测图像相对于参考图像在y轴上的偏移量* @return 返回函数执行的状态* @retval 0 表示成功* @retval -1 表示失败*/
int JitterDetect(const cv::Mat& srcImg, const cv::Mat& refImg, double& offsetX, double& offsetY) {if (srcImg.empty() || refImg.empty()) {return -1;}// 定义ROI区域int roiY = srcImg.rows / kRoiYOffset;int roiHeight = srcImg.rows * kRoiHeightFactor / kRoiYOffset;cv::Rect roi(0, roiY, srcImg.cols, roiHeight);// 裁剪图像到ROI区域cv::Mat img = srcImg(roi);cv::Mat imgRef = refImg(roi);// 如果图像宽度大于设定值,则缩放图像double scale = 1.0;if (img.cols > kScaleWidth) {scale = kScaleWidth / static_cast<double>(img.cols);cv::resize(img, img, cv::Size(), scale, scale);cv::resize(imgRef, imgRef, cv::Size(), scale, scale);}// 初始化特征检测器和描述子提取器cv::Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create(kMinHessian);// 检测并计算关键点和描述子std::vector<cv::KeyPoint> keypoints1, keypoints2;cv::Mat descriptors1, descriptors2;detector->detectAndCompute(img, cv::noArray(), keypoints1, descriptors1);detector->detectAndCompute(imgRef, cv::noArray(), keypoints2, descriptors2);if (keypoints1.size() < kMinKeypoints || keypoints2.size() < kMinKeypoints) {return -1;}// 使用FLANN匹配器匹配描述子cv::FlannBasedMatcher matcher;std::vector<cv::DMatch> matches;matcher.match(descriptors1, descriptors2, matches);if (matches.empty()) {return -1;}// 按距离排序匹配结果std::sort(matches.begin(), matches.end(), [](const cv::DMatch& a, const cv::DMatch& b) {return a.distance < b.distance;});// 选择前N个好的匹配const int numGoodMatches = std::min(50, static_cast<int>(matches.size()));std::vector<cv::DMatch> goodMatches(matches.begin(), matches.begin() + numGoodMatches);// 提取匹配的关键点坐标std::vector<cv::Point2f> points1, points2;for (const auto& match : goodMatches) {points1.push_back(keypoints1[match.queryIdx].pt);points2.push_back(keypoints2[match.trainIdx].pt);}// 使用RANSAC估计仿射变换矩阵cv::Mat inliers;cv::Mat affine = cv::estimateAffinePartial2D(points1, points2, inliers, cv::RANSAC);if (affine.empty()) {return -1;}// 提取平移量offsetX = affine.at<double>(0, 2);offsetY = affine.at<double>(1, 2);// 根据缩放比例调整偏移量if (scale != 1.0) {offsetX /= scale;offsetY /= scale;}return 0;
}

4. 代码详细解读

开始
srcImg和refImg是否为空?
返回-1
定义ROI区域
裁剪图像到ROI
图像宽度是否大于设定值?
缩放图像
跳过缩放
检测并计算关键点和描述子
关键点数量是否足够?
返回-1
匹配描述子
匹配结果是否为空?
返回-1
按距离排序匹配结果
选择前N个好的匹配
提取匹配的关键点坐标
估计仿射变换矩阵
仿射变换矩阵是否为空?
返回-1
提取平移量
根据缩放比例调整偏移量
返回0

流程说明:

  1. 开始:函数JitterDetect开始执行。
  2. 检查输入图像是否为空:如果输入图像为空,返回错误。
  3. 定义ROI区域:根据预设的偏移量和比例,定义感兴趣区域(ROI)。
  4. 裁剪图像到ROI:将输入图像和参考图像裁剪到指定的ROI区域。
  5. 检查图像是否需要缩放:如果图像宽度大于设定的最大宽度,进行缩放。
  6. 检测并计算关键点和描述子:使用SURF算法检测关键点并计算描述子。
  7. 检查关键点数量是否足够:如果关键点数量不足,返回错误。
  8. 匹配描述子:使用FLANN匹配器匹配两个图像的描述子。
  9. 检查匹配结果是否为空:如果没有找到匹配,返回错误。
  10. 排序匹配结果:将匹配结果按距离从小到大排序。
  11. 选择好的匹配点:选择距离最小的前N个匹配点。
  12. 提取匹配的关键点坐标:从好的匹配中提取对应的关键点坐标。
  13. 估计仿射变换矩阵:使用RANSAC算法估计图像间的仿射变换。
  14. 检查仿射变换矩阵是否有效:如果估计失败,返回错误。
  15. 提取平移量:从仿射变换矩阵中获取偏移量。
  16. 调整偏移量:根据图像缩放比例,调整偏移量。
  17. 返回成功状态:函数执行成功,返回0。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com