题记:前文介绍OpenCV的基本操作,本节会继续介绍OpenCV的更多效果。图像处理需要用到很多专业的算法,本人业余学习略知皮毛,只是庶竭驽钝叙其所得,在音视频学习Demo有一些的示例。文章或代码若有错误,也希望大佬不吝赐教。
一、滤波
在编码原理中介绍了滤波效果,前文中是Python代码,C++代码类似,高通滤波如下
cv::Mat gray;
cv::cvtColor(mat, gray, cv::COLOR_BGR2GRAY);
// 强制对齐到偶数尺寸
int evenRows = (gray.rows + 1) & -2;
int evenCols = (gray.cols + 1) & -2;
cv::Mat channelPadded;
cv::copyMakeBorder(gray, channelPadded,
0, evenRows - gray.rows,
0, evenCols - gray.cols,
cv::BORDER_CONSTANT, cv::Scalar::all(0));
cv::Mat filter = cv::Mat::ones(channelPadded.size(), CV_32F);
for(int i=0; i<100; i++) {
for(int j=0; j<100; j++) {
filter.at<float>(i,j) = 0.0;
}
}
// DCT变换处理
cv::Mat dctMat;
channelPadded.convertTo(dctMat, CV_32F);
// 前向DCT变换
cv::dct(dctMat, dctMat);
// 应用DCT域滤波器
cv::multiply(dctMat, filter, dctMat);
// 逆向DCT变换
cv::idct(dctMat, dctMat);
// 转换为8位并裁剪
cv::Mat result;
dctMat.convertTo(result, CV_8U);
result = result(cv::Rect(0, 0, gray.cols, gray.rows));
cv::bitwise_not(result, result);
return result;
二、直方图均衡
2.1 直方图均衡
直方图均衡,可以先看效果,再说原理,均衡代码如图:
cv::Mat gray, equalized;
cv::cvtColor(mat, gray, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray, equalized);
效果如图,上图是原图,下图是均衡化效果:

由上图可见,在偏暗或者偏亮的环境下,色值会集中在一部分。如右边是直方图的分布,横坐标是0-255的色值,纵坐标是统计值。均衡化的目标是将直方图的分布均匀一些,如下方的图。
cv::Mat origHist, eqHist;
int histSize = 256;
float range[] = {0,256};
const float* histRange = {range};
cv::calcHist(&gray, 1, 0, cv::Mat(), origHist, 1, &histSize, &histRange);
cv::calcHist(&equalized, 1, 0, cv::Mat(), eqHist, 1, &histSize, &histRange);
2.2 均衡化原理
基本思想是把图像的直方图分布变得更均匀,图像的对比度就会提高,效果如上图。
说明 |
公式 |
统计图像中每个灰度级 |
 |
每个灰度级的累积分布 |
 |
将CDF线性映射到0-255范围,生成像素值的映射表:M×N为图像总像素数, |
 |
应用映射表 |
-- |
上述公式其实解释起来很简单,就是把色值转换为累计分布,如下图0-4
最后映射的结果。密度大的色值范围会变大,密度小的色值范围变小,从而达到均衡的目的。
原始值色 |
0 |
1 |
2 |
3 |
4 |
概率 |
0.3 |
0.3 |
0.2 |
0.1 |
0.1 |
累积概率 |
0.3 |
0.6 |
0.8 |
0.9 |
1.0 |
映射 |
1.2 |
2.4 |
3.2 |
3.6 |
4.0 |
2.3 自适应均衡化
上述属于全图均衡化,但图片如果偏大的情况下,自适应均衡化效果会更好一些。自适应实际上是对图块划分为格子,如下代码中的 8x8大小格子。对每个格子进行均衡化处理。最后,格子之间的分界进行线性插值得到最后结果。
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(4.0);
clahe->setTilesGridSize(cv::Size(8, 8));
自适应均衡化效果:

三、特征匹配
3.1 特征匹配
本文主要介绍一下SIFT算法,其他改进算法还有SURF,此外还有ORB和AKAZE。SIFT广泛应用在图像匹配与拼接、物体识别与跟踪等。SIFT在目前版本已经免费可用(专利过期),opencv
需要包含opencv_contrib
模块,pod
支持的版本不包含,需要自己编译一下。
git clone https://github.com/opencv/opencv.git # 切换到合适版本
git clone https://github.com/opencv/opencv_contrib.git # 切换到合适版本
cd opencv/platforms/ios
python build_framework.py ios --contrib ../../opencv_contrib --disable-swift
特征匹配效果(SIFT特征+暴力匹配
),相关代码音视频学习Demo

相关代码如下:
// 初始化SIFT检测器
auto detector = cv::SIFT::create();
// 检测关键点和计算描述子
std::vector<cv::KeyPoint> queryKpts, sceneKpts;
cv::Mat queryDesc, sceneDesc;
detector->detectAndCompute(queryMat, cv::noArray(), queryKpts, queryDesc);
detector->detectAndCompute(sceneMat, cv::noArray(), sceneKpts, sceneDesc);
// 特征匹配
auto matcher = cv::BFMatcher::create(cv::NORM_L2);
std::vector<cv::DMatch> matches;
matcher->match(queryDesc, sceneDesc, matches);
// 筛选最佳匹配
std::sort(matches.begin(), matches.end());
const int keepMatches = matches.size() * 0.05;
std::vector<cv::DMatch> goodMatches(matches.begin(), matches.begin() + keepMatches);
// 可视化匹配结果
cv::Mat resultMat;
cv::drawMatches(queryMat, queryKpts,
sceneMat, sceneKpts,
goodMatches, resultMat,
cv::Scalar::all(-1), cv::Scalar::all(-1),
std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
return resultMat;
SIFT(Scale-Invariant Feature Transform)是计算机视觉中经典的局部特征检测与描述算法。其核心优势在于对尺度缩放、旋转、光照变化、视角变化等具有强鲁棒性。
-
关键点检测的核心思想通过把图片模糊、缩放得到几组图片,然后通过差值得到能够识别图片特征的点。 
-
利用三维泰勒展开调整极值点位置,提高定位精度。
-
在关键点所在尺度的高斯图像中,计算邻域像素的梯度幅值和方向。生成36-bin直方图(每10°一bin),使用σ=1.5×关键点尺度的高斯窗口加权梯度幅值。主方向为最高峰,辅方向为超过主峰80%的次峰。
-
将坐标轴旋转至主方向,确保描述符与方向无关。这一步是方向不变的关键
-
区域划分,16×16窗口分为4×4子区域,每个子区域计算8方向梯度直方图,形成128维向量。
3.2 匹配
关于匹配方法,一般下列几种:
3.2.1 暴力匹配(Brute-Force Matcher)
-
原理:遍历第一幅图像的所有特征描述符,与第二幅图像的每个描述符计算距离,选择最优匹配。
-
用途:小规模数据集、精确匹配。
-
代码示例:
import cv2
# 创建BFMatcher对象(使用汉明距离,适用于ORB、BRISK等)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 匹配描述符
matches = bf.match(des1, des2)
# 按距离排序
matches = sorted(matches, key=lambda x: x.distance)
3.2.2 快速近似最近邻(FLANN)
-
原理:基于高维数据的近似最近邻搜索,通过树结构加速匹配。
-
用途:大规模数据集、实时性要求高的场景。
-
代码示例:
# 设置FLANN参数(适用于SIFT、SURF等)
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50) # 搜索次数
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
3.2.3 比率测试(Ratio Test)
-
原理:对每个关键点的两个最佳匹配计算距离比值(如0.7),过滤模糊匹配。
-
用途:去除错误匹配,提高匹配质量。
-
代码示例:
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
3.2.4 基于几何约束的筛选(RANSAC)
-
原理:通过随机采样一致性算法(RANSAC)估计基础矩阵或单应性矩阵,剔除不符合几何约束的匹配。
-
用途:图像拼接、相机位置估计。
-
代码示例:
src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
# 使用RANSAC计算单应性矩阵
H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
# 保留内点(符合几何约束的匹配)
inlier_matches = [m for i, m in enumerate(good_matches) if mask[i]]
3.2.5 总结
方法 |
优点 |
缺点 |
适用场景 |
暴力匹配 |
精确度高 |
计算复杂度高,速度慢 |
小规模数据、精确匹配需求 |
FLANN |
速度快,适合高维数据 |
近似匹配,可能存在误差 |
大规模数据、实时性要求高 |
比率测试 |
有效过滤模糊匹配 |
可能丢失部分正确匹配 |
提高匹配质量 |
RANSAC |
鲁棒性强,抗噪声 |
依赖初始匹配的准确性 |
几何模型估计(如单应性) |