OpenCV 笔记(38):同态滤波

1. 同态滤波

同态滤波(Homomorphic Filtering)是一种经典的图像增强 方法,主要用于同时校正图像的 非均匀光照增强细节对比度

同态滤波的核心思想是将图像的光照分量 (低频)和反射分量(高频)分离,并分别进行调整,最终改善图像的对比度和细节。

2. 算法流程

2.1 图像模型

图像可表示为光照分量
和反射分量
的乘积:

其中:

  • :入射光照分量(illumination),通常变化平缓,包含低频信息。

  • :物体的反射分量(reflectance),变化剧烈,包含高频信息(细节、边缘)。

  • :观测到的图像。

2.2 对数变换

为了能够独立处理光照和反射,同态滤波的第一步是对图像的像素值取对数。因为在数学上,乘法运算在取对数后会变成加法运算。

此后,光照分量和反射分量在频域中更易于分离。

2.3 傅里叶变换

对取对数变换后的图像
进行傅里叶变换 ,转换到频域,得到频谱

这样做的目的是将图像分解为不同频率的成分。

2.4 设计滤波器

设计一个合适的滤波器函数
,并在频域中将频谱
与该滤波器相乘,得到滤波后的频谱

根据频率成分的特性进行增强或衰减。一个典型的同态滤波器会衰减低频成分(减少光照不均),并增强高频成分(增强细节和对比度)。

因此,滤波器函数
的设计是同态滤波的关键,不同的滤波器会产生不同的增强效果。

常见的同态滤波器形式包括:

  • 高斯型同态滤波器: 增强高频,衰减低频。过渡平滑,无振铃效应。

  • 巴特沃斯型同态滤波器: 具有更平滑的过渡带。阶数可调,灵活性高。

  • 指数型同态滤波器: 过渡特性介于高斯和巴特沃斯之间。

  • 理想高通同态滤波器: 低频完全抑制,高频完全保留。会导致严重振铃效应,实际应用较少。

这里,我们以高斯型同态滤波器为例,它是一种基于高斯函数设计的频域滤波器,结合同态滤波框架与高斯函数的频域特性,对图像的光照分量(低频)和反射分量(高频)进行差异化调整。我们用以下公式来表示高斯同态滤波器的传递函数:

其中,

  • : 低频增益(通常 <1,抑制光照不均)。

  • : 高频增益(通常 >1,增强细节)。

  • c : 控制滤波器陡峭程度的常数。

  • : 截止频率。

  • :频率点到中心的距离。

这个形式是一种 高斯型高通滤波器,嵌入到同态滤波的增益控制中,用来调节低频(光照分量)和高频(细节分量)的权重。

2.5 傅里叶逆变换

将滤波后的频谱
转换回空间域,得到滤波后的对数图像

2.6 指数运算

对图像
的每个像素值进行指数运算,得到最终的增强图像

这个步骤是为了恢复原始图像的尺度和亮度范围。由于第一步进行了对数运算,这里需要进行指数运算来还原。

总结一下整个算法的流程

原始图像 → 对数变换 → 傅里叶变换 → 同态滤波 → 逆傅里叶变换 → 指数变换 → 输出图像

3. 使用 OpenCV C++ 实现同态滤波

下面的例子,展示了如何基于上述的算法流程构建单通道同态滤波,以及如何构建高斯型高通同态滤波器。对于彩色图像而言,需要先分离出 B、G、R 通道,每个通道单独使用同态滤波,最后再合并回彩色图像。

go 复制代码
#include <opencv2/opencv.hpp>
#include <iostream>

usingnamespace cv;
usingnamespacestd;

// 构造高斯型高通同态滤波器
Mat createHighPassFilter(Size size, float gammaH, float gammaL, float c, float D0) {
    Mat H(size, CV_32F);
    Point center = Point(size.width / 2, size.height / 2);
    for (int u = 0; u < size.height; u++) {
        for (int v = 0; v < size.width; v++) {
            float D = sqrt(pow(u - center.y, 2) + pow(v - center.x, 2));
            H.at<float>(u, v) = (gammaH - gammaL) * (1.0f - exp(-c * (D * D) / (D0 * D0))) + gammaL;
        }
    }
    return H;
}

// 单通道同态滤波
Mat homomorphicFilter(const Mat& image, float gammaH, float gammaL, float c, float D0) {
    Mat floatImg;
    image.convertTo(floatImg, CV_32F);    // 转换为 float 类型,方便后续计算
    floatImg += 1;                      // 防止 log(0) 出现无穷大
    log(floatImg, floatImg);            // 对图像取对数:ln(f(x, y))

    // 对图像扩展到最佳 DFT 尺寸
    int m = cv::getOptimalDFTSize(image.rows);
    int n = cv::getOptimalDFTSize(image.cols);
    Mat padded;
    copyMakeBorder(floatImg, padded, 0, m - image.rows, 0, n - image.cols, BORDER_CONSTANT, Scalar::all(0));

    // 创建复数矩阵,实部为 padded,虚部为 0
    Mat planes[] = { padded, Mat::zeros(padded.size(), CV_32F) };
    Mat complexI;
    merge(planes, 2, complexI);

    // 进行傅里叶变换
    dft(complexI, complexI);

    // 创建高通同态滤波器,尺寸和 padded 一致
    Mat H = createHighPassFilter(padded.size(), gammaH, gammaL, c, D0);

    // 将频谱从笛卡尔坐标转换为极坐标(幅值和相位)
    split(complexI, planes);
    Mat mag, phase;
    cartToPolar(planes[0], planes[1], mag, phase);

    // 在频率域应用滤波器(只对幅值部分)
    mag = mag.mul(H);

    // 将极坐标转换回笛卡尔坐标
    polarToCart(mag, phase, planes[0], planes[1]);
    merge(planes, 2, complexI);

    // 傅里叶逆变换,回到空域
    idft(complexI, complexI);

    // 提取实部,去掉填充部分
    split(complexI, planes);
    Mat realI = planes[0](Rect(0, 0, image.cols, image.rows));

    // 归一化到 [0, 10],避免指数溢出
    normalize(realI, realI, 0, 10, NORM_MINMAX);

    // 对结果取指数,还原到线性空间
    Mat img_out;
    exp(realI, img_out);

    // 最后归一化到 [0, 255] 并转换为 8 位图像
    double minVal, maxVal;
    minMaxLoc(img_out, &minVal, &maxVal);
    img_out.convertTo(img_out, CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal));

    return img_out;
}

int main() {
    Mat src = imread(".../landscape.jpg", IMREAD_UNCHANGED);
    if (src.empty()) {
        cout << "无法加载图像" << endl;
        return-1;
    }

    Mat result;

    if (src.channels() == 1) {
        // 灰度图像处理
        result = homomorphicFilter(src, 1.5f, 0.5f, 1.0f, 30.0f);
    } elseif (src.channels() == 3) {
        // 彩色图像处理(逐通道)
        vector<Mat> channels;
        split(src, channels);
        vector<Mat> resultChannels(3);

        for (int i = 0; i < 3; ++i) {
            resultChannels[i] = homomorphicFilter(channels[i], 1.5f, 0.5f, 1.0f, 30.0f);
        }
        merge(resultChannels, result);
    } else {
        cout << "不支持的图像通道数" << endl;
        return-1;
    }

    imshow("src", src);
    imshow("result", result);
    waitKey(0);

    return0;
}

原图.png 同态滤波后的效果图.png

4. 总结

同态滤波是一种通过频域处理解决图像光照不均的关键技术,其作用在于分离并差异化调整图像的低频光照分量和高频反射分量,增强图像对比度和细节,从而提高图像的视觉质量和可分析性。这在光照条件复杂或需要突出局部特征的应用中具有重要意义。

相关推荐
NAGNIP11 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab12 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab12 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP16 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年16 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼16 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS17 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区18 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈18 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang18 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx