跳转至

OpenCV 面试题库大全

第一部分:基础与数据结构

  1. OpenCV 中 cv::Mat 的存储机制是什么?解释 depth()channels() 的区别。

答案: cv::Mat 是 OpenCV 中用于存储图像和矩阵数据的核心结构,它本质上是一个头信息 + 数据指针的结构。

  • 存储机制:数据在内存中通常是行优先连续存储的,但对于多通道图像(如 RGB),每个像素的多个通道是交错存储的(即 BGR BGR BGR ...)。step 成员变量表示每一行的字节数(包含填充对齐)。

  • depth():返回单个通道的像素深度(数据类型),如 CV_8U (0)、CV_32F (5) 等,仅代表一个通道的数据类型。

  • channels():返回图像的通道数(如灰度图为1,彩色图为3)。

  • 组合:type() 返回 CV_8UC3 这种完整类型,结合了深度和通道数。

  • 解释 OpenCV 中 cv::Rect 的成员变量 x, y, width, height 以及 tl()br() 的含义。

答案:

  • x, y:表示矩形左上角的坐标(在图像坐标系中,原点位于左上角,x轴向右,y轴向下)。

  • width, height:矩形的宽度和高度(像素单位)。

  • tl() (top-left):返回左上角点 Point(x, y)

  • br() (bottom-right):返回右下角点 Point(x + width, y + height)

  • 注意:在 OpenCV 中,矩形区域通常包含左上角像素,但不包含右下角像素(左闭右开区间 [x, x+width)),这在进行图像 ROI(感兴趣区域)操作时非常重要,以避免索引越界。

  • OpenCV 中 BGR 色彩空间与 RGB 的区别是什么?为什么 OpenCV 默认使用 BGR

答案:

  • 区别:两者只是通道存储顺序不同。在 RGB 中,内存顺序为 R、G、B;在 OpenCV 的 BGR 中,内存顺序为 B、G、R。

  • 原因:OpenCV 最初由 Intel 开发,其底层图像处理库(IPL)为了兼容 Windows 的 GDI(图形设备接口)以及早期摄像头的硬件输出格式,采用了 BGR 格式。这一历史原因被保留下来。

  • 影响:当使用 matplotlib(默认 RGB)显示 OpenCV 图像时,如果不做转换(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)),颜色会显示异常(红蓝颠倒)。


第二部分:图像处理与操作

  1. 图像的卷积操作(Filter2D)是如何计算的?简述边界处理(Border Handling)的常见模式。

答案:

卷积操作是通过一个核(Kernel,通常为奇数大小)在图像上滑动,将核覆盖下的像素值与核系数相乘后求和,得到中心像素的输出值。

常见边界处理模式:

  1. BORDER_CONSTANT:用常数填充(常用黑色 0)。

  2. BORDER_REPLICATE:复制边缘像素(如 aaaaaa|abcdefgh|hhhhhhh)。

  3. BORDER_REFLECT:镜像反射(如 fedcba|abcdefgh|hgfedcb)。

  4. BORDER_REFLECT_101 (或 BORDER_DEFAULT):镜像反射但不重复边界(gfedcb|abcdefgh|gfedcba),这是高斯模糊、Sobel 等算子的默认方式。

  5. BORDER_WRAP:环绕,对侧像素拼接。

  6. 解释高斯模糊(GaussianBlur)与中值模糊(medianBlur)的原理区别及适用场景。

答案:

  • 高斯模糊:
  • 原理:线性滤波。使用符合高斯分布的核进行加权平均。权重随距离中心距离增加而减小。
  • 特点:平滑效果好,能有效抑制服从正态分布的噪声,但会模糊边缘。
  • 适用:去噪预处理、图像缩放前的抗锯齿。

  • 中值模糊:

  • 原理:非线性滤波。取核窗口内所有像素值的中位数作为输出。
  • 特点:对椒盐噪声(随机黑白点)有极佳的去除效果,且能较好地保留边缘细节(因为不涉及线性加权)。
  • 适用:去除椒盐噪声、文档图像预处理。

  • 什么是图像直方图均衡化(Histogram Equalization)?它的作用是什么?

答案:

图像直方图均衡化是一种通过拉伸像素强度分布范围来增强图像对比度的方法。

  • 原理:对于灰度图像,计算累积分布函数(CDF),然后将原始像素值映射到新的值,使得输出图像的直方图尽可能平坦(均匀分布)。

  • 作用:对于曝光过度或曝光不足的图像,能够增强细节,使暗部变亮,亮部变暗,从而提升视觉对比度。

  • 局限:全局均衡化可能过度增强噪声或导致图像失真。对于局部光照不均的情况,通常使用 CLAHE(对比度受限自适应直方图均衡化)。

  • 图像金字塔(Image Pyramid)是什么?简述高斯金字塔与拉普拉斯金字塔的区别。

答案:

图像金字塔是同一图像不同分辨率的集合。

  • 高斯金字塔:
  • 生成:通过下采样(先高斯模糊,再删除偶数行和列)得到更小尺寸的图像;通过上采样(扩展行和列,再卷积)恢复尺寸。
  • 用途:图像缩放、多尺度模板匹配、视觉显著图。

  • 拉普拉斯金字塔:

  • 生成:高斯金字塔中,上层图像(低分辨率)经过上采样后与下层图像(高分辨率)的差。
  • 本质:存储了高斯金字塔在降采样过程中丢失的高频细节信息。
  • 用途:图像压缩、图像重建(如将低分辨率图像恢复细节)、图像融合(如实现无缝拼接)。

第三部分:特征检测与描述子

  1. 请对比 SIFT 和 SURF 的优缺点。在 OpenCV 中为什么有时无法直接调用它们?

答案:

  • SIFT(尺度不变特征变换):
  • 优点:对旋转、尺度缩放、亮度变化保持不变性,对视角变化、噪声也有一定程度的稳定性。特征描述子具有独特性,匹配准确率高。
  • 缺点:计算速度慢,实时性差。

  • SURF(加速稳健特征):

  • 优点:SIFT 的加速版,利用 Haar 小波和积分图加速计算,速度比 SIFT 快数倍。保持了较好的鲁棒性。
  • 缺点:虽然速度快,但匹配精度略逊于 SIFT。

  • 可用性问题:

  • SIFT 和 SURF 在 OpenCV 中属于 xfeatures2d 非自由模块(non-free)。在 OpenCV 3/4 的高版本中,由于专利授权问题,它们被移出了主仓库(contrib 模块中需要额外编译),或者需要安装 opencv-contrib-python 的非免费部分。在 OpenCV 4.5.1 之后,SIFT 专利已过期,现在可以直接在 cv2.SIFT_create() 中使用,但 SURF 仍受限。

  • ORB (Oriented FAST and Rotated BRIEF) 相比 SIFT 有什么优势?简述其原理。

答案:

ORB 是一种融合了 FAST 角点检测与 BRIEF 描述子的算法,并加入了旋转不变性。其优势在于:

  • 速度极快:比 SIFT 快两个数量级,适合实时应用(如手机端、嵌入式)。

  • 免费开源:没有专利限制。

  • 原理:

  • 特征点检测:使用 FAST 检测角点,并利用灰度质心法为每个特征点添加方向(orientation)。
  • 特征描述:使用 rBRIEF(旋转感知的 BRIEF)。BRIEF 原本是二进制描述子(0/1串),计算速度快但无方向。ORB 将特征点方向加入 BRIEF,使其具有旋转不变性。

  • 在 OpenCV 中,如何利用特征匹配(如 BFMatcher 或 FLANN)筛选正确的匹配点?常用方法有哪些?

答案:

在获得初步匹配点对后,通常存在大量误匹配(外点),需要筛选:

  1. 交叉验证(Cross Check):在 BFMatcher 中设置参数 crossCheck=True。它要求 A 图中的点匹配到 B 图,且 B 图中对应的点匹配回 A 图必须是同一个点。

  2. 比率测试(Lowe’s Ratio Test):针对 knnMatch(k=2)。计算最近邻距离与次近邻距离的比值,若比值小于阈值(通常设为 0.7-0.8),则认为该匹配是好的。这是 SIFT 论文中提出的经典方法,用于剔除模糊匹配。

  3. 几何约束(RANSAC):使用 cv2.findHomographycv2.estimateAffinePartial2D 并设定 RANSAC 算法,通过计算单应性矩阵或基础矩阵,剔除不符合几何变换模型的离群点。函数返回的 mask 即为筛选后的内点索引。


第四部分:目标检测与机器学习

  1. OpenCV 中 Haar Cascade(级联分类器)的工作原理是什么?它的优点和局限性有哪些?

答案:

  • 原理:
  • 特征:使用Haar-like 特征(矩形特征,如边缘、线性、中心特征),通过积分图快速计算。
  • 分类器:使用 Adaboost 算法从大量特征中挑选出最有效的几个特征,训练成强分类器。
  • 级联结构:将多个强分类器串联成级联。大部分非目标区域在前几层就被快速淘汰,只有疑似区域进入深层分类器,实现了高检测率和高排除率。

  • 优点:检测速度快(尤其是早期版本),适合嵌入式设备。

  • 局限性:

  • 对旋转、倾斜、非正面目标检测效果差。
  • 训练过程复杂,需要大量正负样本。
  • 容易产生误检(False Positive),且对光照敏感。
  • 目前已逐渐被基于深度学习的目标检测器(如 YOLO)取代。

  • 解释 OpenCV 中 HOG (方向梯度直方图) 特征与 SVM (支持向量机) 结合用于行人检测的原理。

答案:

这是 Dalal & Triggs 在 2005 年提出的经典方法。

  1. HOG 特征提取:
  2. 将图像划分为小的细胞单元(Cells,如 8x8 像素)。
  3. 计算每个细胞单元内像素的梯度方向(幅度和角度)。
  4. 将细胞单元组合成块(Blocks,如 2x2 cells),在块内对直方图进行归一化,以抵抗光照变化。
  5. 将所有块的向量串联起来,形成高维特征向量。

  6. SVM 分类:

  7. 使用线性 SVM 作为分类器。在训练阶段,用大量正样本(行人)和负样本(非行人)的 HOG 特征训练 SVM,得到一个最优分类超平面。
  8. 检测时,使用滑动窗口在图像上滑动,提取窗口的 HOG 特征,输入 SVM 判断是否为行人。

  9. 特点:对边缘、轮廓特征描述优秀,对光照变化鲁棒,但对遮挡和姿态变化敏感。

  10. OpenCV 中 DNN (Deep Neural Network) 模块的作用是什么?它支持哪些后端(Backend)和目标(Target)?

答案: OpenCV 的 dnn 模块专门用于加载预训练的深度学习模型并进行前向推理,但不支持训练。

  • 作用:允许在 OpenCV 中直接使用 TensorFlow、PyTorch (ONNX)、Caffe、Darknet 等框架训练好的模型,实现目标检测、人脸识别、图像分割等功能,无需依赖原始框架环境。

  • 后端(Backend):决定使用哪个计算库。如 DNN_BACKEND_OPENCV(默认)、DNN_BACKEND_INFERENCE_ENGINE(Intel OpenVINO)、DNN_BACKEND_CUDA(NVIDIA GPU)。

  • 目标(Target):决定在哪个硬件上运行。如 DNN_TARGET_CPUDNN_TARGET_OPENCLDNN_TARGET_CUDADNN_TARGET_OPENCL_FP16


第五部分:视频处理与实战

  1. 在视频处理中,如何实现“帧差法”运动检测?简述其步骤和局限性。

答案:

帧差法是最简单的运动检测方法。

  • 步骤:
  • 读取连续的三帧(或两帧)图像:frame_prev, frame_curr, frame_next
  • 转换为灰度图并高斯模糊去噪。
  • 计算差分:diff1 = abs(frame_curr - frame_prev), diff2 = abs(frame_next - frame_curr)
  • 二值化:ret, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
  • 逻辑与(针对三帧差分):motion = cv2.bitwise_and(thresh1, thresh2)
  • 形态学操作(膨胀、闭运算)填补空洞。

  • 局限性:

  • 无法区分物体和阴影。
  • 如果物体速度过慢,差分结果可能为空;如果速度过快,可能出现重影。
  • 对环境噪声和光照变化敏感。

  • OpenCV 中的 VideoCapture 类在读取视频时,grab()retrieve() 有什么区别?为什么配合使用可以提高效率?

答案:

  • grab():仅从视频流或摄像头中抓取(解码)下一帧,并将数据存入缓冲区,但不返回图像数据。

  • retrieve():对 grab() 存入缓冲区的帧进行解码并返回为 cv::Mat 格式。

  • 配合使用的优势: 当需要同时读取多个摄像头或多路视频流时,可以先对所有设备调用 grab()(并行解码,硬件层面解耦),然后再逐个调用 retrieve()。这样可以避免因等待某一帧解码完成而阻塞其他摄像头,显著提高多路视频处理的同步性和 FPS(帧率)。

  • 在 OpenCV 中,如何使用 cv2.findContours 查找轮廓?解释 RETR_EXTERNAL, RETR_TREE 以及 CHAIN_APPROX_SIMPLE 的含义。

答案:

  • cv2.findContours:输入通常是二值图像(如经过阈值化或边缘检测后的图像)。返回轮廓列表和层次结构。

  • 检索模式(Retrieval Mode):

  • RETR_EXTERNAL:只检索最外层轮廓,忽略内部孔洞(子轮廓)。
  • RETR_TREE:检索所有轮廓,并构建完整的层级结构(父子关系)。最常用,用于需要区分物体内部结构(如一个圆环内外圈)的场景。

  • 近似方法(Approximation Method):

  • CHAIN_APPROX_NONE:存储轮廓上的所有像素点。
  • CHAIN_APPROX_SIMPLE:压缩水平、垂直、对角线的连续点,只保留端点。例如,存储一个矩形只需要 4 个点,节省内存。

第六部分:性能优化与高级特性

  1. OpenCV 中的 UMat 是什么?它与 Mat 有何不同?

答案:

  • UMat (Unified Mat):是 OpenCV 引入的透明 API,用于支持 OpenCL 加速。

  • 区别:

  • Mat:数据存储在 CPU 内存中。
  • UMat:数据存储在统一的虚拟内存中(可能是 CPU 内存,也可能是 GPU 显存)。OpenCV 的 UMat 操作会自动判断是否有可用的 OpenCL 设备(如 Intel GPU、AMD GPU、NVIDIA GPU),如果有,后台会自动将数据迁移到 GPU 并执行并行计算。

  • 优势:开发者无需显式编写 OpenCL 代码,只需将代码中的 Mat 替换为 UMat,即可在支持 OpenCL 的设备上获得性能提升(尤其在图像处理滤波、颜色转换等像素级操作上)。

  • 在 OpenCV 中,如何优化图像处理循环的速度?请列举至少三种方法。

答案:

  1. 使用 OpenCV 内置函数:尽量避免使用 Python 层级的 for 循环遍历像素。OpenCV 的 C++ 底层实现(如 cv2.add, cv2.threshold)经过高度优化且支持 SIMD 指令集,速度远快于 Python 循环。

  2. 使用 UMat (OpenCL):将 cv2.UMat() 传递给函数,利用 GPU 并行计算。

  3. 使用 cv2.LUT (查找表):对于像素值映射(如伽马校正、自定义阈值),预先计算 0-255 的映射表,使用 cv2.LUT 一次性应用,避免逐像素计算。

  4. 预分配内存:在循环处理视频帧时,预先创建好 Mat 对象,避免在循环内部频繁申请和释放内存。

  5. 使用 numbaCython:如果必须自定义算法且无法避免 Python 循环,可以借助 numba JIT 编译加速,或将核心逻辑用 C++ 编写并封装为 Python 模块。

  6. 如何使用 OpenCV 进行相机标定(Camera Calibration)?简述其目的和主要步骤。

答案:

  • 目的:求解相机的内参矩阵(焦距、主点坐标)和畸变系数(径向畸变、切向畸变),从而校正图像畸变,并将像素坐标映射到现实世界的物理坐标(用于三维重建、测量)。

  • 主要步骤:

  • 准备标定板:通常使用棋盘格或圆点网格,测量其角点物理间距。
  • 拍摄多张(通常 15-20 张)不同角度、不同位置的标定板图像。
  • 使用 cv2.findChessboardCorners 提取图像中的亚像素角点坐标。
  • 调用 cv2.calibrateCamera,输入世界坐标(3D点)和图像坐标(2D点),输出相机矩阵 cameraMatrix、畸变系数 distCoeffs、旋转向量和平移向量。
  • 使用 cv2.undistort 对图像进行去畸变处理。

  • 描述 OpenCV 中 cv::Stitcher 进行图像拼接的主要流程。

答案: cv2.Stitcher 类提供了图像拼接的高级封装,其内部核心流程如下:

  1. 特征提取与匹配:对输入图像提取 SIFT、ORB 等特征点,并进行匹配。

  2. 图像配准(Registration):利用匹配点计算图像间的单应性矩阵(Homography),将图像变换到同一坐标系下。

  3. 曝光补偿(Exposure Compensation):由于不同图像的光照可能不同,算法会调整各图像的增益,使重叠区域的亮度平滑过渡。

  4. 寻找接缝(Seam Finding):使用图割(Graph Cut)等方法,在重叠区域确定一条最优的接缝线,使拼接处看起来自然,避免鬼影(特别是针对有移动物体的场景)。

  5. 多频段融合(Multi-band Blending):将不同频率的图像信息进行融合(高频使用小权重避免重影,低频使用大权重保证亮度一致),最终输出全景图。

图像分割中,分水岭算法(Watershed)的原理是什么?OpenCV 中如何实现?

答案:

分水岭算法是一种基于区域生长的分割方法,将图像视为地形表面(灰度值代表海拔高度),从局部极小值开始注水,随着水位上升,不同流域相遇处筑起“堤坝”,最终堤坝即为分割边界。

OpenCV 实现步骤:

  1. 使用 cv2.connectedComponents() 为前景和背景标记不同的索引(种子点)。

  2. 调用 cv2.watershed(img, markers),其中 markers 是一个整数矩阵,初始时前景区域>0,背景区域=0,未知区域=-1。

  3. 算法会修改 markers,将边界区域标记为 -1(或特定值),最终提取边界。

适用场景:粘连物体的分割(如细胞计数、硬币分割),但对噪声敏感,通常需结合距离变换使用。


光流法(Optical Flow)中,Lucas-Kanade 方法和 Farneback 方法的主要区别是什么?

答案:

  • Lucas-Kanade(稀疏光流):
  • 假设局部邻域内所有像素具有相同的运动矢量,通过最小二乘法求解。
  • 仅计算稀疏特征点(如 Shi-Tomasi 角点)的运动,计算量小,适合跟踪。
  • OpenCV 函数:cv2.calcOpticalFlowPyrLK()

  • Farneback(稠密光流):

  • 基于多项式展开,计算图像中每个像素的运动矢量,输出光流场(两通道图像)。
  • 精度高,但计算量大,适合分析整体运动模式。
  • OpenCV 函数:cv2.calcOpticalFlowFarneback()

在相机标定中,为什么要使用“棋盘格”作为标定板?如何提高标定精度?

答案:

  • 棋盘格优势:
  • 角点亚像素精度:棋盘格内角点是黑白交界处,可以通过 cv2.cornerSubPix() 获得亚像素级精确坐标。
  • 易于检测:cv2.findChessboardCorners() 鲁棒性高,对光照、畸变有一定容忍度。
  • 无需测量尺寸比例:只需知道格子实际物理大小(如 25mm),角点世界坐标可自动生成。

  • 提高精度的方法:

  • 拍摄 15~20 张以上 不同角度、不同距离的图像,覆盖整个视场。
  • 确保标定板占据图像 30%~70% 的面积。
  • 使用 亚像素角点检测 优化角点坐标。
  • 在标定函数中设置 cv2.CALIB_FIX_ASPECT_RATIOcv2.CALIB_RATIONAL_MODEL 以处理畸变模型。
  • 剔除重投影误差过大的图像,重新标定。

OpenCV 中 cv2.solvePnP() 的作用是什么?在增强现实(AR)中如何应用?

答案:

  • 作用:求解 PnP(Perspective-n-Point) 问题,即给定世界坐标系中的 3D 点及其对应的图像 2D 投影点,以及相机内参,估算相机相对于世界坐标系的旋转向量和平移向量(即外参)。

  • AR 应用:

  • 识别平面标记(如二维码、棋盘格),获得其角点的世界坐标(已知尺寸)和图像坐标。
  • 调用 solvePnP 得到相机位姿(R, t)。
  • 利用 cv2.projectPoints() 将虚拟三维物体的顶点投影到图像平面,实现虚拟物体的叠加。
  • 绘制叠加物体,实现增强现实效果。

什么是图像修复(Inpainting)?OpenCV 中 cv2.inpaint() 的两种算法有何区别?

答案:

图像修复是指去除图像中的不需要的物体或划痕,并用背景纹理合理填充。

OpenCV 提供两种算法:

  • INPAINT_NS(Navier-Stokes):
  • 基于流体动力学,利用偏微分方程将已知区域的信息沿等照度线(isophote)扩散到待修复区域。
  • 适合修复平滑区域、线条状划痕。

  • INPAINT_TELEA(Telea):

  • 基于快速行进法(Fast Marching Method),优先填充边界附近像素,通过加权平均邻域已知像素的值。
  • 计算速度较快,适合修复小面积瑕疵。

参数:inpaint(src, mask, inpaintRadius, flags)mask 为二值图,白色表示待修复区域,inpaintRadius 为修复半径。


如何利用 OpenCV 实现视频背景建模(Background Subtraction)?常用的算法有哪些?

答案:

背景建模用于分离前景运动物体,常用算法有:

  1. MOG2(高斯混合模型):cv2.createBackgroundSubtractorMOG2()
  2. 为每个像素建立多个高斯分布,自适应学习背景。
  3. 可输出阴影掩码(通过参数 detectShadows=True)。
  4. 适用于缓慢变化的场景(如监控摄像头)。

  5. KNN(K近邻):cv2.createBackgroundSubtractorKNN()

  6. 基于像素历史样本的分类,抗噪性好,对光照变化适应性强。

使用步骤:

python

fgbg = cv2.createBackgroundSubtractorMOG2()while cap.isOpened(): ret, frame = cap.read() fgmask = fgbg.apply(frame) # 前景掩码 # 后处理:形态学开运算去除噪点,闭运算填充空洞


OpenCV 的 cv2.UMat 在 GPU 加速上有什么限制?如何检查 OpenCV 是否启用了 OpenCL?

答案:

  • 限制:
  • 仅对支持 OpenCL 的设备有效(如 Intel 集成显卡、AMD、NVIDIA)。
  • 并非所有 OpenCV 函数都实现了 OpenCL 版本(常见的图像处理函数多数支持,但复杂算法可能不支持)。
  • 数据传输(CPU ↔ GPU)有额外开销,对于小图像或简单操作反而可能变慢。

  • 检查 OpenCL 状态:

  • python

  • print(cv2.ocl.haveOpenCL()) # 是否检测到 OpenCL 设备cv2.ocl.setUseOpenCL(True) # 启用print(cv2.ocl.useOpenCL()) # 查看当前是否启用

  • 调试:设置环境变量 OPENCV_OPENCL_DEVICE=:GPU:0 可以指定设备,或 OPENCV_OPENCL_ABORT_ON_BUILD_ERROR=0 避免因编译失败回退 CPU。


什么是图像矩(Image Moments)?OpenCV 中 cv2.moments() 返回的 mu20mu02 等可以用来做什么?

答案:

图像矩是描述图像形状特征的统计量,包括空间矩、中心矩、归一化中心矩等。

  • 空间矩:m00(面积)、m10m01(重心)。

  • 中心矩:mu20mu02mu11 反映物体相对于重心的分布,可用于计算方向角(主轴线):

  • text

  • angle = 0.5 * atan2(2 * mu11, mu20 - mu02)

  • 归一化中心矩:nu20nu02 等具有尺度不变性,可用于形状匹配。

  • Hu 矩:通过 cv2.HuMoments() 得到七个 Hu 不变矩,具有平移、旋转、尺度不变性,用于形状识别。


在 OpenCV 中,如何实现图像的直方图反向投影(Histogram Backprojection)?其应用场景是什么?

答案:

原理:反向投影用于定位图像中与给定直方图(目标模型)最相似的区域。它将输入图像每个像素替换为对应直方图 bin 的“概率”值,生成一个概率图,越亮的地方表示越可能为目标。

实现步骤:

  1. 计算目标区域(ROI)的直方图并归一化。

  2. 对全图计算反向投影:cv2.calcBackProject([image], [channel], hist, ranges, scale)

  3. 对概率图进行均值滤波或形态学操作,再通过阈值找到目标位置。

应用:目标跟踪(如 MeanShift、CamShift 算法)、肤色检测、纹理定位。


简述 OpenCV 中 cv::rotate()cv::flip()cv::transpose() 的作用与区别。

答案:

  • rotate():按 90° 的倍数旋转(90°、180°、270°)。不会改变图像尺寸,但行列会交换(90° 或 270° 时宽高互换)。
  • 标志:cv2.ROTATE_90_CLOCKWISEROTATE_180ROTATE_90_COUNTERCLOCKWISE

  • flip():沿水平、垂直或两个轴翻转(镜像)。图像尺寸不变。

  • flipCode = 0:垂直翻转(绕 x 轴);1:水平翻转(绕 y 轴);-1:双轴翻转(等价于旋转 180°)。

  • transpose():矩阵转置,即交换行和列。对于图像而言,相当于旋转 90° 后再镜像(或旋转 -90°)。通常用于配合 flip 实现任意角度旋转。

  • 区别:

  • rotate 仅限于 90° 倍数旋转,且自动处理尺寸变化。
  • flip 不改变尺寸,只做镜像。
  • transpose 是线性代数转置,需要自行结合 flip 达到特定旋转效果。

解释 OpenCV 中的 ROI(Region of Interest)操作,以及如何高效地复制或处理图像局部区域?

答案: ROI 是指图像中的一个矩形子区域。在 OpenCV 中,ROI 可以通过 cv::Rectcv::Range 来定义。创建 ROI 并不会复制数据,而是生成一个新的 cv::Mat 头,共享相同的数据内存(浅拷贝)。这样操作 ROI 会直接影响原始图像,避免了数据拷贝的开销。

高效处理局部区域:

  • 直接对 ROI 进行操作:Mat roi = img(rect); cv::cvtColor(roi, roi, cv::COLOR_BGR2GRAY);(原地转换)。

  • 如果需要独立处理,可使用 clone()copyTo() 进行深拷贝。

  • 对于循环处理多个 ROI,尽量预定义 ROI 对象,避免重复计算坐标。

注意:在多线程环境中,共享数据需要加锁保护。


如何利用 OpenCV 实现图像的自动白平衡(Auto White Balance)?简述灰度世界算法的原理。

答案:

自动白平衡用于消除光源颜色对图像的影响,使白色物体在任何光照下都呈现白色。

灰度世界算法(Gray World Assumption):

  • 假设场景中所有颜色的平均反射率是灰色的,即 RGB 三个通道的平均值应相等。

  • 算法步骤:

  • 计算图像每个通道的平均值 avgR, avgG, avgB
  • 计算全局灰度均值 gray = (avgR + avgG + avgB) / 3
  • 计算每个通道的增益系数:gainR = gray / avgR,同理 gainG, gainB
  • 对每个通道像素乘以对应的增益系数,并裁剪到 0-255 范围。

OpenCV 实现:可以直接用 cv2.splitcv2.merge 操作,也可使用 cv2.cvtColor 到 LAB 空间后调整 L 通道(更高级的方法)。


OpenCV 中 cv2.undistort()cv2.initUndistortRectifyMap() + cv2.remap() 有什么区别?为什么使用 remap 方式更高效?

答案:

  • cv2.undistort():直接输入原图和相机内参、畸变系数,输出去畸变后的图像。它在内部为每个像素计算映射并执行重映射,简单方便,但每次调用都会重新计算映射表,对于视频流处理开销较大。

  • cv2.initUndistortRectifyMap() + cv2.remap()

  • initUndistortRectifyMap 预先计算从畸变图像到非畸变图像的映射表(两个数组,分别对应 x 和 y 坐标)。
  • remap 使用预计算的映射表快速完成重映射。
  • 优势:映射表只需计算一次(或当相机参数改变时重新计算),后续每一帧仅执行 remap,避免了重复计算映射的开销,非常适合视频或批量图像处理。

在 OpenCV 中,cv::threshold()cv::adaptiveThreshold() 的适用场景有何不同?

答案:

  • cv::threshold()(全局阈值):
  • 使用一个固定的阈值分割图像,适用于图像光照均匀、前景与背景灰度差异明显的情况。
  • 简单快速,但对光照变化敏感。

  • cv::adaptiveThreshold()(自适应阈值):

  • 根据像素邻域内的灰度分布动态计算每个像素的阈值。
  • 适用于光照不均匀、背景灰度变化较大的图像(如文档扫描、阴影区域)。
  • 提供两种方法:ADAPTIVE_THRESH_MEAN_C(邻域均值减去常数)和 ADAPTIVE_THRESH_GAUSSIAN_C(邻域加权高斯均值)。
  • 计算量比全局阈值大,但对光照变化更鲁棒。

如何使用 OpenCV 对图像进行无损旋转(不裁剪)?例如旋转 30 度后保留完整图像内容。

答案:

当旋转非 90° 倍数时,图像会超出原始边界,需要扩大画布以容纳全部内容。

步骤:

  1. 获取图像尺寸和旋转中心(通常为图像中心)。

  2. 计算旋转矩阵:M = cv2.getRotationMatrix2D(center, angle, scale=1.0)

  3. 计算新图像尺寸:

  4. 将原始图像的四个角点通过旋转矩阵变换,得到新边界。
  5. 计算新宽度和高度:new_w = int(max(x_max - x_min, y_max - y_min)) 等。

  6. 调整旋转矩阵中的平移部分,使图像居中于新画布:M[0,2] += (new_w - w) / 2, M[1,2] += (new_h - h) / 2

  7. 使用 cv2.warpAffine(img, M, (new_w, new_h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=0)

注意:borderValue 可设置填充颜色(如黑色或白色)。


OpenCV 中如何实现图像的边缘检测?请对比 Canny 边缘检测与 Sobel 算子的区别。

答案:

  • Sobel 算子:
  • 一阶导数算子,通过计算图像在 x 和 y 方向上的梯度近似值。
  • 对噪声敏感,输出通常需要进一步处理(如阈值化)才能得到边缘二值图。
  • 可单独获得梯度幅值和方向。
  • 函数:cv2.Sobel(src, ddepth, dx, dy, ksize)

  • Canny 边缘检测:

  • 多阶段算法:高斯滤波去噪 → 计算梯度幅值和方向 → 非极大值抑制 → 双阈值连接边缘。
  • 输出二值边缘图,边缘连续性好,且能有效抑制假边缘。
  • 函数:cv2.Canny(src, threshold1, threshold2),其中两个阈值用于边缘连接。
  • 适用于高质量的边缘提取,是工程中最常用的边缘检测方法。

简述 OpenCV 中 cv2.calcHist() 的作用,以及如何计算多通道直方图(如 RGB 三维直方图)。

答案:

  • calcHist:计算一个或多个数组的直方图,可指定通道、bin 数量、范围等。

  • 多通道直方图:通过 channels 列表指定需要计算的通道索引,histSize 列表对应每个通道的 bin 数,ranges 列表对应每个通道的值范围。

  • 示例:计算 RGB 图像的三维直方图(每个通道 8 个 bin):

  • python

  • hist = cv2.calcHist([img], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])

  • 返回的 hist 形状为 (8, 8, 8),每个元素表示该颜色区间内的像素数量。

注意:多通道直方图计算量大,内存占用高,通常用于颜色特征提取或背景建模,不适合实时处理。


如何使用 OpenCV 实现图像的“图像金字塔”拉普拉斯残差融合(Laplacian Pyramid Blending)?简述其原理。

答案:

拉普拉斯金字塔融合用于无缝拼接两幅图像(如实现“克隆”效果),尤其适用于处理边界不平滑的情况。

原理:

  1. 对两幅图像分别构建高斯金字塔(逐步下采样)。

  2. 对高斯金字塔的每一层,通过扩展上采样后与上一层的差,得到拉普拉斯金字塔(存储高频细节)。

  3. 对两幅图像的拉普拉斯金字塔对应层进行融合,通常使用掩码(如二值掩码或权重渐变)进行加权平均。

  4. 对融合后的拉普拉斯金字塔从顶层开始向上重建,逐步叠加细节,最终得到融合图像。

OpenCV 实现:需手动构建金字塔和重建过程,但可通过 cv2.pyrDowncv2.pyrUp 实现。


在 OpenCV 中,如何实现多线程并行处理多张图像?有哪些注意事项?

答案: 可以使用 Python 的 concurrent.futures.ThreadPoolExecutormultiprocessing.Pool 来实现并行处理。由于 OpenCV 的一些操作(尤其是 DNN 推理)可能释放 GIL,线程并行在 I/O 密集型或底层 C 函数上效果较好,而 CPU 密集型操作使用进程并行更佳。

注意事项:

  • 线程安全:OpenCV 的大部分操作(如 cv2.imread, cv2.resize)是线程安全的,但修改全局变量或共享 Mat 对象需要加锁。

  • 视频捕获:每个 VideoCapture 对象应在各自线程中创建和使用,不能跨线程共享。

  • GIL 影响:纯 Python 循环处理像素会受 GIL 限制,应尽量使用 OpenCV 内置函数。

  • 进程并行:使用 multiprocessing 时,注意传递的数据需要序列化,可能增加开销;对于大图像,建议使用共享内存或传递文件路径。


如何使用 OpenCV 的 cv2.fisheye 模块处理鱼眼相机图像?与普通相机标定有何不同?

答案: 鱼眼相机具有极大的视场角(通常 > 150°),普通针孔模型无法准确描述其畸变。OpenCV 提供了专门的 fisheye 模块处理鱼眼相机。

主要区别:

  • 标定模型:鱼眼模型使用四阶径向畸变系数(k1, k2, k3, k4),而普通模型通常使用五个系数(k1, k2, p1, p2, k3)或更多。

  • 标定函数:cv2.fisheye.calibrate() 替代 cv2.calibrateCamera()

  • 去畸变:cv2.fisheye.undistortImage()cv2.fisheye.initUndistortRectifyMap() + remap

  • 参数:需指定新的相机矩阵(Knew)来调整视场角范围,可选择是否缩放以保留所有像素或裁剪黑边。

应用场景:全景摄像头、车载环视系统、VR 设备等。

OpenCV 中 cv2.dnn.NMSBoxes() 的作用是什么?在目标检测后处理中如何使用?

答案: NMSBoxes 用于执行非极大值抑制,去除重叠度高的冗余检测框,保留置信度最高的框。

  • 输入:边界框列表(格式为 [x, y, width, height][x1, y1, x2, y2])、对应的置信度分数、重叠阈值(nms_threshold)和可选的置信度阈值。

  • 使用示例:

  • python

  • boxes = np.array([[x1, y1, x2, y2], ...])scores = np.array([conf1, conf2, ...])indices = cv2.dnn.NMSBoxes(boxes.tolist(), scores.tolist(), score_threshold, nms_threshold)

  • 注意事项:

  • OpenCV 4.5.1 后增加了 cv2.dnn.NMSBoxesBatched 支持多类别 NMS。
  • 若框的表示格式不统一,需提前转换。

OpenCV 的 dnn 模块中,如何利用 cv2.dnn.readNetFromTensorFlow() 加载 TensorFlow 冻结图?如何指定输入输出节点?

答案:

python

net = cv2.dnn.readNetFromTensorFlow('frozen_graph.pb')

如果模型有多个输入/输出或需要显式指定节点名称,可以使用:

python

net.setInputNames(['input_tensor_name'])net.setInputShape('input_tensor_name', (1, 224, 224, 3))out_names = ['output_tensor_name1', 'output_tensor_name2']outputs = net.forward(out_names)

  • 注意:TensorFlow 1.x 的冻结图可用此方法;对于 TensorFlow 2.x,推荐导出为 SavedModel 再转 ONNX,然后用 readNetFromONNX

解释 OpenCV 中 cv2.rectangle()cv2.polylines() 在绘制多边形时的区别,如何绘制带填充的多边形?

答案:

  • cv2.rectangle:仅能绘制轴对齐矩形(四个角点),不能绘制任意多边形。

  • cv2.polylines:可以绘制任意多边形(通过点集),默认只绘制轮廓,不填充。若需要填充,使用 cv2.fillPoly

  • 填充多边形示例:

  • python

  • pts = np.array([[x1, y1], [x2, y2], [x3, y3], ...], np.int32)pts = pts.reshape((-1, 1, 2))cv2.fillPoly(img, [pts], color=(0, 255, 0))

  • 注意:polylinesisClosed 参数控制是否闭合。


OpenCV 中如何实现图像的透视变换(Perspective Transformation)?与仿射变换有何区别?

答案:

  • 透视变换:将图像从一个平面映射到另一个平面,可处理倾斜、视角变化。需要4个对应点(原图和目标图),求解 3x3 变换矩阵(包含投影分量)。

  • 实现步骤:

  • python

  • pts_src = np.float32([[x1,y1], [x2,y2], [x3,y3], [x4,y4]])pts_dst = np.float32([[x1',y1'], [x2',y2'], [x3',y3'], [x4',y4']])M = cv2.getPerspectiveTransform(pts_src, pts_dst)warped = cv2.warpPerspective(img, M, (w, h))

  • 与仿射变换区别:

  • 仿射变换(cv2.getAffineTransform)只需3个点,保持平行线关系(旋转、平移、缩放、剪切),变换矩阵为 2x3。
  • 透视变换不保持平行性,矩阵为 3x3。

OpenCV 中 cv2.undistort()cv2.initUndistortRectifyMap() + cv2.remap() 两种去畸变方式有何优劣?

答案:

  • cv2.undistort:一次性完成映射计算和重映射,代码简洁,适合单张图像或低频率调用。

  • initUndistortRectifyMap + remap:预先计算映射表(map1, map2),后续多张图像可直接使用 remap,避免重复计算映射,速度更快,尤其适用于视频流或批量处理。

  • 选择建议:对视频帧或批量图像,推荐第二种方式。


在 OpenCV 中,如何实现图像的自动白平衡(Auto White Balance)?简述灰度世界算法的原理。

答案:

灰度世界算法假设场景的平均颜色是灰色,即三个通道的平均值应相等。

  • 步骤:
  • 计算图像 B、G、R 各通道的平均值 avg_b, avg_g, avg_r
  • 计算整体平均灰度 gray = (avg_b + avg_g + avg_r) / 3
  • 对每个通道分别乘以增益 gain = gray / avg_channel
  • 裁剪到 [0,255] 并输出。

  • OpenCV 实现:

  • python

  • b, g, r = cv2.split(img)avg_b, avg_g, avg_r = np.mean(b), np.mean(g), np.mean(r)gray = (avg_b + avg_g + avg_r) / 3b = np.clip(b * (gray / avg_b), 0, 255).astype(np.uint8)# 同理 g, rresult = cv2.merge([b, g, r])


什么是图像的超分辨率(Super Resolution)?OpenCV 中提供了哪些超分辨率方法?

答案:

超分辨率是从低分辨率图像恢复高分辨率图像的技术。

  • OpenCV 提供的传统方法(xphoto 模块):
  • cv2.xphoto.dctDenoising:基于 DCT 的去噪,可间接提升细节。
  • cv2.xphoto.bm3dDenoising:BM3D 去噪算法。

  • 深度学习模型(dnn_superres 模块):

  • 支持 EDSR、ESPCN、FSRCNN、LapSRN 等模型。
  • 使用方式:加载预训练模型,调用 upsample 方法。

  • 注意事项:深度学习模型需要额外下载权重文件,且推理速度较慢。


OpenCV 中 cv2.rotate()cv2.transpose() + cv2.flip() 实现旋转的区别是什么?

答案:

  • cv2.rotate:仅支持 90°、180°、270° 的旋转,代码简洁,且自动调整尺寸(宽高互换)。

  • 组合实现:transpose + flip 可以实现任意角度的旋转,但需注意:

  • 顺时针 90°:cv2.flip(cv2.transpose(img), 1)
  • 逆时针 90°:cv2.flip(cv2.transpose(img), 0)
  • 旋转 180°:cv2.flip(img, -1)cv2.rotate(img, cv2.ROTATE_180)

  • 性能:rotate 内部经过优化,通常比组合操作稍快。


OpenCV 中 cv2.calcHist() 的参数 channelsmaskhistSizeranges 各代表什么?

答案:

  • channels:指定要计算直方图的通道索引(如 [0] 表示第0通道,对于彩色图,0=B,1=G,2=R)。

  • mask:掩膜图像,若不为空,只计算掩膜非零区域的直方图,用于局部直方图。

  • histSize:每个通道的直方图 bins 数量(如 [256] 表示灰度级)。

  • ranges:每个通道的取值范围,通常为 [0,256](半开区间)。

  • 示例:

  • python

  • hist = cv2.calcHist([img], [0], None, [256], [0,256])


如何使用 OpenCV 进行人脸检测(基于 Haar Cascade 或 DNN)?比较两种方法的优缺点。

答案:

  • Haar Cascade:
  • 优点:速度快,适合嵌入式设备;无需额外依赖;简单易用。
  • 缺点:准确率较低,对角度、遮挡敏感;训练需要大量样本。

  • DNN(如基于 ResNet 或 MobileNet 的模型):

  • 优点:准确率高,支持多角度、遮挡;可结合开源模型(如 OpenCV 的 face_detection)。
  • 缺点:需要模型文件,推理速度较慢(尤其在 CPU 上),对硬件有一定要求。

  • 代码示例(DNN):

  • python

  • net = cv2.dnn.readNetFromCaffe('deploy.prototxt', 'res10_300x300_ssd_iter_140000.caffemodel')blob = cv2.dnn.blobFromImage(img, 1.0, (300,300), (104.0,177.0,123.0))net.setInput(blob)detections = net.forward()


在 OpenCV 中,如何将图像从 BGR 转换到 HSV 色彩空间?HSV 在图像处理中的优势是什么?

答案:

  • 转换:cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

  • HSV 分量:

  • Hue(色相):颜色类型(0~180,OpenCV 中范围减半以适应 uint8)。
  • Saturation(饱和度):颜色纯度(0~255)。
  • Value(明度):亮度(0~255)。

  • 优势:将颜色信息(H)与亮度(V)分离,使得颜色分割、跟踪对光照变化更鲁棒。例如在肤色检测中,常使用 H 和 S 通道。


什么是图像金字塔的“拉普拉斯残差”?它在图像融合中如何发挥作用?

答案:

  • 拉普拉斯残差:高斯金字塔中,相邻两层图像的差异(下层图像减去上采样后的上层图像),包含高频细节。

  • 图像融合:将多幅图像分别构建拉普拉斯金字塔,然后在每个尺度上按掩膜(如权重图)进行融合,最后重建得到融合图像。这种方法可以平滑过渡拼接边界,避免鬼影和色差,常用于多焦距图像融合、全景拼接。


OpenCV 中 cv2.HoughCircles() 检测圆形的原理是什么?参数 dpminDistparam1param2 的含义。

答案: HoughCircles 基于霍夫梯度法。

  • 原理:
  • 使用 Canny 边缘检测。
  • 对边缘点计算梯度方向,沿梯度方向累加圆心候选。
  • 对圆心候选进行阈值过滤,再对每个圆心估计半径。

  • 参数:

  • dp:累加器分辨率与图像分辨率的反比(如 dp=1 表示相同,dp=2 表示累加器宽高减半)。
  • minDist:圆心之间的最小距离,防止检测到相邻的重复圆。
  • param1:Canny 边缘检测的高阈值。
  • param2:圆心累加器的阈值,值越小越容易误检。

  • 注意:函数对参数敏感,通常需要多次调整。


在 OpenCV 中,如何利用 cv2.connectedComponentsWithStats() 实现连通域分析?返回的 stats 矩阵包含哪些信息?

答案:

python

num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_img, connectivity=8)

  • stats:形状为 (num_labels, 5) 的矩阵,每行对应一个连通域的统计信息:
  • [x, y, width, height, area]
  • 其中 x, y 为外接矩形左上角坐标。

  • 用途:通过面积筛选去除小噪点,或通过宽高比筛选目标形状。


OpenCV 的 cv2.estimateAffinePartial2D()cv2.findHomography() 的区别是什么?分别适用于什么场景?

答案:

  • estimateAffinePartial2D:估计部分仿射变换(刚性变换 + 缩放),变换矩阵为 2x3,自由度 4(旋转、平移、各向同性缩放)。适用于运动估计、图像配准(如两帧之间的相机运动)。

  • findHomography:估计单应性矩阵(3x3),自由度 8,可描述透视变换(平面到平面的映射)。适用于全景拼接、平面物体跟踪。

  • 选择:若变换仅为旋转/平移/缩放(如相机旋转),用仿射;若涉及透视变形(如拍摄平面倾斜),用单应性。


在 OpenCV 中,如何实现图像的“自动裁剪”(去除白边或黑边)?

答案:

常见方法是利用二值化 + 轮廓查找。

  • 步骤:
  • 将图像转为灰度,二值化(若背景是黑色,使用 THRESH_BINARY;若白色,使用 THRESH_BINARY_INV)。
  • 查找所有轮廓,找到最大轮廓的外接矩形。
  • 裁剪该矩形区域。

  • 代码:

  • python

  • gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)_, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)x, y, w, h = cv2.boundingRect(contours[0])cropped = img[y:y+h, x:x+w]


简述 OpenCV 中 cv2.StereoBM(块匹配)与 cv2.StereoSGBM(半全局匹配)的核心区别。

答案:

  • StereoBM:局部匹配算法,在固定窗口内计算 SAD(绝对差和),速度快,但容易在弱纹理区域产生空洞,且对噪声敏感。

  • StereoSGBM:半全局匹配,通过在多个方向(8 或 16 方向)上优化能量函数(数据项 + 平滑项),得到更平滑的视差图,对弱纹理和遮挡更鲁棒,但计算量更大。

  • OpenCV 实现:StereoSGBM 提供了更多参数(如 P1, P2 控制平滑惩罚),是实际项目中的首选。


OpenCV 中 cv2.kmeans() 函数的作用是什么?在图像分割中如何使用?

答案: kmeans 实现 K-Means 聚类算法,将数据点划分为 K 个簇。

  • 图像分割应用:将每个像素的颜色作为特征(3 维向量),聚类后每个像素被赋予簇标签,实现颜色量化或分割。

  • 使用步骤:

  • 将图像 reshape 为 (N, 3) 的二维数组(N = 像素总数)。
  • 调用 cv2.kmeans(data, K, bestLabels, criteria, attempts, flags)
  • bestLabels reshape 回原图像尺寸,得到分割结果。

  • 注意事项:需要指定 K 值(簇数),且对初始中心敏感。


如何利用 OpenCV 进行视频帧的“时间戳同步”?若摄像头提供的时间戳不准确,如何估计帧间时间?

答案:

  • 同步方式:
  • 若使用 VideoCapture,可通过 cap.get(cv2.CAP_PROP_POS_MSEC) 获取当前帧的时间戳(毫秒),但此值依赖于编解码器的 PTS,可能不准确。
  • 对于实时摄像头,可以记录 time.time()cv2.getTickCount() 作为帧接收时间。

  • 估计帧间时间:计算连续帧的时间差,并利用帧率做平滑(如取中位数)。若帧率已知,可直接用 1/fps 作为间隔。

  • 同步多个源:可启动独立线程采集,将每帧与其接收时间戳绑定,然后在处理时按时间对齐。


OpenCV 的 contrib 模块包含哪些常用的扩展功能?举例说明。

答案: opencv_contrib 包含非稳定或受专利保护的算法,常见的有:

  • xfeatures2d:SIFT(已移入主库)、SURF、FREAK 等特征算法。

  • face:人脸识别(LBPH、Fisherfaces、Eigenfaces)。

  • text:文本检测与识别(如 ERFilter、OCR)。

  • rgbd:RGB-D 深度相机处理(如 Kinect)。

  • aruco:ArUco 标记检测与姿态估计。

  • line_descriptor:二进制线特征描述子。

  • 使用:安装 opencv-contrib-python 后即可导入,但需注意部分功能依赖专利(如 SURF)可能需特殊配置。


OpenCV 中 cv2.solve()cv2.solveLP() 分别用于解决什么问题?

答案:

  • cv2.solve:求解线性方程组 A * X = B(最小二乘或精确解),支持多种分解方法(DECOMP_LU, DECOMP_SVD 等)。

  • cv2.solveLP:求解线性规划问题(min c^T x,约束 Ax <= bx >= 0),用于简单线性优化。

  • 应用:相机标定中的参数优化、约束求解等。


如何利用 OpenCV 实现图像的“仿射变换”中的旋转?与 cv2.getRotationMatrix2D 结合如何使用?

答案:

python

center = (w//2, h//2)angle = 45scale = 1.0M = cv2.getRotationMatrix2D(center, angle, scale)rotated = cv2.warpAffine(img, M, (w, h))

  • 原理:getRotationMatrix2D 生成一个 2x3 矩阵,包含旋转和平移(确保中心不变)。warpAffine 应用变换。

  • 扩展:若需要旋转后图像完整包含原图,需计算新尺寸并调整平移。


OpenCV 中 cv2.goodFeaturesToTrack()cv2.cornerHarris() 的区别是什么?各自的应用场景?

答案:

  • cornerHarris:Harris 角点检测,返回每个像素的角点响应值,需手动阈值筛选。适用于需要所有角点响应的场景(如配准)。

  • goodFeaturesToTrack:基于 Shi-Tomasi 改进(最小特征值),直接返回筛选后的角点坐标,且支持质量等级和最小距离。适用于光流跟踪、特征点提取。

  • 优势:goodFeaturesToTrack 通常返回更均匀的角点,且内置非极大值抑制。


如何利用 OpenCV 实现图像的“运动放大”(Motion Magnification)?简要说明思路。

答案:

运动放大用于放大视频中微小的运动(如脉搏、振动)。经典方法(欧拉视频放大):

  1. 将视频帧分解为空间金字塔(拉普拉斯或高斯)。

  2. 对每个尺度的时间序列进行带通滤波(保留目标频率的运动)。

  3. 放大滤波后的信号(乘以放大因子),叠加回原图。

  4. 重建视频。

  5. OpenCV 实现:需结合图像金字塔、cv2.filter2D 时域滤波等。OpenCV 本身没有直接提供该功能,但可利用其基础组件构建。


OpenCV 中 cv2.floodFill() 的作用是什么?在图像填充、分割中有哪些应用?

答案: floodFill 实现泛洪填充(类似 Photoshop 的魔棒),从种子点开始,将相邻且颜色相似的像素填充为指定颜色。

  • 参数:image, mask, seedPoint, newVal, loDiff, upDiff

  • 应用:

  • 去除图像背景(如证件照换背景)。
  • 标记连通区域(替代 connectedComponents 的特定场景)。
  • 交互式图像分割。

  • 注意:mask 需比原图宽高各多 2 像素,且为单通道。


如何利用 OpenCV 计算两个图像之间的“结构相似性指数”(SSIM)?

答案:

OpenCV 没有直接提供 SSIM 函数,但可以通过公式手动实现:

python

def ssim(img1, img2): C1 = (0.01 * 255)2 C2 = (0.03 * 255)2 img1 = img1.astype(np.float64) img2 = img2.astype(np.float64) kernel = cv2.getGaussianKernel(11, 1.5) window = np.outer(kernel, kernel.transpose()) mu1 = cv2.filter2D(img1, -1, window)[5:-5,5:-5] mu2 = cv2.filter2D(img2, -1, window)[5:-5,5:-5] mu1_sq = mu12 mu2_sq = mu22 mu1_mu2 = mu1 * mu2 sigma1_sq = cv2.filter2D(img12, -1, window)[5:-5,5:-5] - mu1_sq sigma2_sq = cv2.filter2D(img22, -1, window)[5:-5,5:-5] - mu2_sq sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5,5:-5] - mu1_mu2 ssim_map = ((2mu1_mu2 + C1)(2sigma12 + C2)) / ((mu1_sq + mu2_sq + C1)(sigma1_sq + sigma2_sq + C2)) return ssim_map.mean()

  • 应用:图像质量评估、视频压缩效果对比。

OpenCV 中 cv2.pyrMeanShiftFiltering() 的作用是什么?与均值漂移分割有何关系?

答案: pyrMeanShiftFiltering 实现均值漂移滤波,用于图像平滑和分割。

  • 原理:在颜色空间和空间坐标联合域中进行均值漂移迭代,将像素聚类到局部模式。

  • 参数:sp(空间半径)、sr(颜色半径)、maxLevel(金字塔层数)。

  • 输出:平滑后的图像,相同区域的像素颜色趋于一致。

  • 应用:作为图像分割的前处理,或直接生成过分割区域(需后续合并)。


如何利用 OpenCV 实现图像的“自动色阶”(Auto Levels)?

答案:

自动色阶通过拉伸直方图的动态范围来增强对比度。

  • 步骤:
  • 计算图像直方图。
  • 找到累积分布的低端(如 0.5%)和高端(如 99.5%)对应的灰度值 lowhigh
  • 将原图像素映射到 [0,255]new = (old - low) * 255 / (high - low)
  • 裁剪超出范围的值。

  • OpenCV 实现:利用 cv2.normalizeNORM_MINMAX 可简单实现,但需注意按通道处理。


OpenCV 中 cv2.createBackgroundSubtractorGMG() 与 MOG2 的区别?它有哪些特点?

答案:

GMG(Gaussian Mixture-based Background/Foreground Segmentation)是另一种背景建模方法,已不再推荐使用。

  • 特点:
  • 需要前几帧进行初始化(通常前 120 帧用于学习)。
  • 结合了前景/背景的贝叶斯决策。
  • 对光照变化较敏感,且计算量较大。

  • 现状:OpenCV 中该算法已标记为废弃,推荐使用 MOG2 或 KNN。


在 OpenCV 中,如何实现图像的“伽马校正”(Gamma Correction)?公式是什么?

答案:

伽马校正用于调整图像的亮度非线性:

text

O = 255 * (I / 255) ^ γ

其中 γ > 1 使图像变暗,γ < 1 使图像变亮。

  • OpenCV 实现:

  • python

  • def gamma_correction(img, gamma): inv_gamma = 1.0 / gamma table = np.array([(i / 255.0) ** inv_gamma * 255 for i in range(256)]).astype('uint8') return cv2.LUT(img, table)

  • 应用:改善过暗或过亮图像的视觉效果,或匹配显示设备的伽马曲线。