)
OpenCV Photo 模块实战Non-Local Means 图像去噪cv.fastNlMeansDenoising 系列【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv本文基于 OpenCV 官方 Python 教程中“Non-Local Means Denoising”一章系统讲解 Non-Local Means非局部均值去噪算法的原理、cv.fastNlMeansDenoising/cv.fastNlMeansDenoisingColored/cv.fastNlMeansDenoisingMulti/cv.fastNlMeansDenoisingColoredMulti四个 API 的完整参数说明与可运行示例并结合 photo 模块 C 源码modules/photo/src/denoising.cpp与测试用例剖析 CIELAB 分量分离、窗口奇数约束、normType深度限制等底层实现细节帮助你在去噪强度参数h与细节保留之间做出可验证的权衡。从局部平滑到 Non-Local Means算法原理为什么“相似补丁平均”能去噪高斯模糊、中值模糊等传统平滑技术本质上是局部操作围绕每个像素取一个小邻域做加权平均或取中值。这类方法对少量噪声有效但邻域内不同纹理会互相“污染”噪声较多时细节很快被抹平。Non-Local Means 利用了噪声的两个统计性质噪声通常被视为零均值随机变量。对含噪像素可写为p p0 np0为真实值n为噪声。如果从多张相同场景中取N个同一位置的像素求平均由于噪声均值为零结果理想情况下会收敛到真实值p0自然图像具有大量自重复结构取图中一个 5x5 小块图像其他位置往往就在附近大概率存在与之相似的小块。于是算法思路非常自然以某个像素为中心取模板窗口在整个图像甚至整个视频片段中搜索与之相似的窗口对这些相似窗口做加权平均用平均结果替换中心像素。相比局部模糊它利用的是“非局部”的相似区域因此去噪效果显著更好代价是计算时间明显更长。教程中给出一个便于直观验证的实验让相机静止拍摄几秒得到大量同场景帧求所有帧的平均图像与原帧对比即可看到噪声下降但该实验对相机和场景运动不稳健且现实中常常只有一张含噪图像——这正是 Non-Local Means 用“图像内相似块”替代“多帧平均”的动机。OpenCV 提供的四个 fastNlMeansDenoising 变体OpenCV 在cv::photo模块中实现了带多项计算优化的 Non-Local Means 去噪针对高斯白噪声Python 侧共暴露四个函数函数适用输入cv.fastNlMeansDenoising()单幅灰度图像cv.fastNlMeansDenoisingColored()单幅彩色图像cv.fastNlMeansDenoisingMulti()短时间内连续采集的灰度图像序列cv.fastNlMeansDenoisingColoredMulti()同上但为彩色图像序列四个函数的公共参数对应 C 头文件 photo.hpp 中的声明h调节滤波强度的核心参数。h越大去噪越彻底但图像细节丢失越多h越小保留细节但也会保留部分噪声。C 默认值为 3教程建议彩色图一般取 10 左右即可hForColorComponentshColor仅彩色版本使用作用同h但只调节 L/AB 中颜色分量的强度通常与h相同或接近多数图像取 10 足以去除彩色噪声且不偏色templateWindowSize模板窗口尺寸像素必须为奇数推荐 7searchWindowSize搜索窗口尺寸像素必须为奇数推荐 21。搜索窗口与去噪耗时线性相关——窗口越大搜索耗时越长normType进阶重载支持权重计算使用的范数取cv.NORM_L2或cv.NORM_L1默认NORM_L2。Multi 版本还有两个序列专用参数imgToDenoiseIndex指定序列中需要去噪的目标帧下标temporalWindowSize参与去噪的邻近帧总数必须为奇数。算法会取目标帧前后共temporalWindowSize帧目标帧居中一起计算。例如传入 5 帧、imgToDenoiseIndex 2、temporalWindowSize 3则第 0、2、4 帧即第 2 帧及前后各 1 帧参与对第 2 帧的去噪。从源码结构看C 侧对h还提供更细粒度的重载fastNlMeansDenoising与fastNlMeansDenoisingMulti均接受std::vectorfloat h可以为每个通道单独设置强度h数组长度为 1 时对所有通道生效长度等于通道数时按通道生效这在 denoising.cpp 的CV_Assert(hn 1 || hn cn)中得到确认。实战 1cv.fastNlMeansDenoisingColored()彩色图像去噪对一张含高斯噪声的彩色图教程示例中输入噪声标准差sigma 25去噪注意dst参数传None表示由 OpenCV 自动创建输出import numpy as np import cv2 as cv from matplotlib import pyplot as plt img cv.imread(die.png) # 含高斯噪声 (sigma25) 的彩色骰子图需自备 dst cv.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21) # 参数依次为: # h10 —— 亮度分量滤波强度 # hColor10 —— 颜色分量滤波强度 # templateWindowSize7 —— 模板窗口奇数 # searchWindowSize21 —— 搜索窗口奇数 plt.subplot(121), plt.imshow(img) plt.subplot(122), plt.imshow(dst) plt.show()对结果局部放大可以看到噪点被明显压制而骰子边缘与纹理基本保留见文首nlm_result1对比图。为什么彩色版本要先转 CIELAB教程提到“彩色图像会先转换到 CIELAB 色彩空间再分别对 L 和 AB 分量去噪”。这一点可以直接在 denoising.cpp 的cv::fastNlMeansDenoisingColored实现中验证输入类型被严格校验为CV_8UC3或CV_8UC4否则抛出Type of input image should be CV_8UC3 or CV_8UC4!cvtColor(src, src_lab, COLOR_LBGR2Lab)完成色彩空间转换用mixChannels把 Lab 拆成单通道的l和双通道的ab两张图分别调用fastNlMeansDenoising(l, l, h, ...)和fastNlMeansDenoising(ab, ab, hForColorComponents, ...)——这就是h与hColor各自独立的原因合并后用COLOR_Lab2LBGR转回 BGR。这种“亮度与色度分开、各自定强度”的设计避免了直接在 BGR 上做相似性度量时颜色差异干扰结构匹配的问题也解释了为何h与hColor可以分开调节。实战 2cv.fastNlMeansDenoisingMulti()视频序列去噪多帧版本利用时间维度的相似帧做非局部平均适合短时间内拍摄的静止或缓动视频。注意该函数对输入有明确约束所有帧必须同类型、同尺寸灰度场景下先自行转灰度temporalWindowSize必须为奇数imgToDenoiseIndex前后必须留得下半个时间窗否则报错。这些校验对应 denoising.cpp 中的fastNlMeansDenoisingMultiCheckPreconditionsif (temporalWindowSize % 2 0 || searchWindowSize % 2 0 || templateWindowSize % 2 0) { CV_Error(Error::StsBadArg, All windows sizes should be odd!); } if (imgToDenoiseIndex - temporalWindowHalfSize 0 || imgToDenoiseIndex temporalWindowHalfSize src_imgs_size) { CV_Error(Error::StsBadArg, imgToDenoiseIndex and temporalWindowSize should be chosen corresponding srcImgs size!); }完整示例读取vtest.avi前 5 帧加上方差 25 的高斯噪声再对第 3 帧下标 2利用全部 5 帧去噪vtest.avi需自备import numpy as np import cv2 as cv from matplotlib import pyplot as plt cap cv.VideoCapture(vtest.avi) # create a list of first 5 frames img [cap.read()[1] for i in range(5)] # convert all to grayscale gray [cv.cvtColor(i, cv.COLOR_BGR2GRAY) for i in img] # convert all to float64 gray [np.float64(i) for i in gray] # create a noise of variance 25 noise np.random.randn(*gray[1].shape) * 10 # Add this noise to images noisy [i noise for i in gray] # Convert back to uint8 noisy [np.uint8(np.clip(i, 0, 255)) for i in noisy] # Denoise 3rd frame considering all the 5 frames dst cv.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35) # 参数依次为: # imgToDenoiseIndex2 —— 去噪下标 2 的帧 # temporalWindowSize5 —— 前后共 5 帧参与奇数 # dstNone —— 自动创建输出 # h4 —— 滤波强度 # templateWindowSize7 # searchWindowSize35 —— 比单帧示例更大 # 因为搜索范围扩展到多帧 plt.subplot(131), plt.imshow(gray[2], gray) plt.subplot(132), plt.imshow(noisy[2], gray) plt.subplot(133), plt.imshow(dst, gray) plt.show()结果三张图依次为原始帧、加噪帧、去噪帧见上文nlm_multi图。教程特别强调该计算耗时可观It takes considerable amount of time for computation。从源码结构看搜索窗口越大、时间窗越大参与比对的补丁数量呈乘积式增长虽然实现已用parallel_for_按行并行见 denoising.cpp 中fastNlMeansDenoisingMulti_时间复杂度本身无法靠并行摊薄实际使用时应尽量控制searchWindowSize与temporalWindowSize。源码级细节类型约束、OpenCL 与测试验证normType 与位深约束denoising.cpp 中对normType的分发逻辑给出了明确的输入位深边界NORM_L2默认仅支持CV_8U输入NORM_L1支持CV_8U与CV_16U其他取值直接报Unsupported norm type! Only NORM_L2 and NORM_L1 are supported。也就是说若你要用 16 位图像做 Non-Local Means 去噪必须选用NORM_L1重载。对应的回归测试位于 test_denoising.cpp其中包含 8U/16U 双位深NORM_L1对比测试如fastNlMeansDenoisingMulti(..., 7, 21, NORM_L1)以及单帧/多帧/彩色各变体的常规用例fastNlMeansDenoising(original, result, 10)等。OpenCL 后端fastNlMeansDenoising与fastNlMeansDenoisingColored入口均带有CV_OCL_RUN分发当输入输出任一为 UMat 且尺寸大于 5x5 时走 OpenCL 实现小图精度偏低故跳过内核为 nlmeans.cl分发与封装在 fast_nlmeans_denoising_opencl.hpp。CPU 核心的行级并行模板位于 fast_nlmeans_denoising_invoker.hpp 与 fast_nlmeans_multi_denoising_invoker.hpp。参数取值速查与调参建议综合头文件默认值与教程推荐值参数默认值C 声明教程推荐约束h3.010灰度单帧可试 4~15越大去噪越强、细节丢失越多hForColorComponents3.010同上仅作用于 L/AB 颜色分量templateWindowSize77必须为奇数searchWindowSize2121多帧示例用 35必须为奇数耗时随其线性增长temporalWindowSizeMulti—按序列长度定必须为奇数目标帧前后须留足半窗normType进阶重载NORM_L2—NORM_L1才支持 16 位输入算法背景可参考 Buades 等人的经典论文Non-local image and movie denoising2005OpenCV 头文件中对该方法的引用即指向此文献教程原文推荐的 IPol 在线演示站点不再于本文列出外部链接读者可按上述文献名自行检索。小结Non-Local Means 用“图像内或视频内相似补丁的加权平均”替代局部平滑以更高计算成本换取更干净且保真的去噪结果适用于高斯白噪声场景单帧灰度用cv.fastNlMeansDenoising单帧彩色用cv.fastNlMeansDenoisingColored内部转 CIELAB、L 与 AB 分量分别按h/hColor去噪视频序列则用对应的Multi变体通过imgToDenoiseIndex与奇数temporalWindowSize圈定参与帧两个窗口参数必须为奇数searchWindowSize直接决定耗时进阶重载下 16 位图像须搭配NORM_L1需要 GPU 加速时可传入 UMat 触发 OpenCL 路径内核见modules/photo/src/opencl/nlmeans.cl行为一致性有modules/photo/test/test_denoising.cpp与 OpenCL 测试modules/photo/test/ocl/test_denoising.cpp覆盖。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考