OpenCV入门(21):图像处理之图像锐化

一、图像锐化是什么?

图像锐化 (image sharpening) 是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空间域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。

二、图像锐化的基本原理

图像锐化的核心思想是增强图像中像素值变化剧烈的区域,即边缘和细节。这通常可以通过以下几种方式实现:

  • 反锐化掩模 (Unsharp Masking):这是最经典和广泛使用的方法之一。
  • 拉普拉斯算子 (Laplacian Operator):利用二阶导数来检测边缘和细节。
  • 自定义卷积核 (Custom Kernel Convolution):直接使用一个设计好的锐化卷积核。

三、方法:反锐化掩模 (Unsharp Masking)

反锐化掩模的步骤如下:

  • 模糊图像:首先,对原始图像进行模糊处理(通常使用高斯模糊)。
    blurred = GaussianBlur(original, ...)
  • 计算掩模 (Mask):从原始图像中减去模糊后的图像,得到“掩模”。这个掩模包含了图像中的高频细节。
    mask = original - blurred
  • 锐化:将这个掩模按一定权重(强度因子)加回到原始图像中。
    sharpened = original + amount * mask
    这可以改写为:
    sharpened = original * (1 + amount) - blurred * amount

在 OpenCV 中,可以使用 cv::GaussianBlur() 进行模糊,然后使用 cv::addWeighted()cv::subtract()cv::add() 来实现。

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

// 方法:使用反锐化掩模进行锐化
cv::Mat unsharpMask(const cv::Mat& src, double sigma = 1.0, double amount = 1.0) {
    cv::Mat blurred_img, mask, sharpened_img;

    // 1. 高斯模糊
    cv::GaussianBlur(src, blurred_img, cv::Size(0, 0), sigma, sigma);

    // 2. 计算掩模: mask = original - blurred
    //    锐化: sharpened = original + amount * mask
    //    合并为: sharpened = original * (1 + amount) + blurred * (-amount)
    //    cv::addWeighted(src1, alpha, src2, beta, gamma, dst);
    //    dst = src1*alpha + src2*beta + gamma;
    cv::addWeighted(src, 1.0 + amount, blurred_img, -amount, 0, sharpened_img);

    return sharpened_img;
}

int main() {
    cv::Mat src = cv::imread("lena.jpg", cv::IMREAD_COLOR);
    if (src.empty()) {
        std::cerr << "错误: 无法加载图像 " << std::endl;
        return -1;
    }

    // 应用锐化方法:反锐化掩模
    // sigma 控制模糊程度,amount 控制锐化强度
    cv::Mat sharpened_unsharp = unsharpMask(src, 1.0, 1.5);

    cv::imshow("src Image", src);
    cv::imshow("Dst Image", sharpened_unsharp);

    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

可以发现图片的边缘明显增强了,效果图如下所示:

Blog_OpenCV_Learnl_112.png


四、方法:使用拉普拉斯算子

拉普拉斯算子是一种二阶微分算子,它可以有效地检测图像中的快速强度变化,即边缘。通过将拉普拉斯算子应用到图像上,并将结果与原始图像叠加,可以实现锐化效果。

锐化后的图像 Sharpened 可以通过从原始图像 Original 中减去(或加上,取决于核的符号定义和期望效果)拉普拉斯滤波后的图像 LaplacianImage 得到:Sharpened = Original - c * LaplacianImage ,其中 c 是一个缩放因子。

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

// 方法:使用拉普拉斯算子进行锐化
Mat & imgSharpen(const Mat & img, char * arith)       // arith为3*3模板算子
{
    int rows = img.rows;        // 原图的行
    int cols = img.cols * img.channels();   // 原图的列
    int offsetx = img.channels();       // 像素点的偏移量

    static Mat dst = Mat::ones(img.rows-2, img.cols-2, img.type());

    for(int i = 1; i < rows - 1; i++)
    {
        const uchar* previous = img.ptr<uchar>(i - 1);
        const uchar* current = img.ptr<uchar>(i);
        const uchar* next = img.ptr<uchar>(i + 1);
        uchar * output = dst.ptr<uchar>(i-1);
        for(int j = offsetx ; j < cols - offsetx; j++)
        {
            output[j - offsetx] =
            saturate_cast<uchar>( previous[j-offsetx]*arith[0] + previous[j]*arith[1] + previous[j+offsetx]*arith[2] +
                                  current[j-offsetx]*arith[3]  + current[j]*arith[4]  + current[j+offsetx]*arith[5]  +
                                  next[j-offsetx]*arith[6]     + next[j]*arith[7]     + next[j-offsetx]*arith[8] );
        }
    }
    return dst;
}

int main()
{
    Mat img = imread("lena.jpg");

    char arith[9] = {0, -1, 0, -1, 5, -1, 0, -1, 0}; // 使用拉普拉斯算子

    // 锐化
    Mat dst1 = imgSharpen(img, arith);

    imshow("src Image", img);
    imshow("dst Image", dst1);

    waitKey(0);

    return 0;
}

效果图如下所示:

Blog_OpenCV_Learnl_113.png


五、方法:使用自定义锐化卷积核

这是最直接的方法之一,通过定义一个特定的 3×3 卷积核并将其应用于图像。一个常见的锐化核是将单位矩阵(中心为 1,其余为 0)与一个拉普拉斯核(例如中心为 -4 或 -8,周围为 1)的某种组合。

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

// 方法:使用自定义卷积核进行锐化
cv::Mat sharpenWithKernel(const cv::Mat& src) {
    cv::Mat sharpened_img;
    cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
        0, -1,  0,
       -1,  5, -1,
        0, -1,  0);
    // 或者使用更强的锐化核:
    // cv::Mat kernel = (cv::Mat_<float>(3,3) <<
    //    -1, -1, -1,
    //    -1,  9, -1,
    //    -1, -1, -1);

    // cv::filter2D 函数应用卷积核
    // src.depth() 表示输出图像与输入图像有相同的深度
    cv::filter2D(src, sharpened_img, src.depth(), kernel);
    return sharpened_img;
}

int main() {
    cv::Mat src = cv::imread("lena.jpg", cv::IMREAD_COLOR);
    if (src.empty()) {
        std::cerr << "错误: 无法加载图像 " << std::endl;
        return -1;
    }

    // 应用锐化方法:自定义卷积核
    cv::Mat sharpened_kernel = sharpenWithKernel(src);

    cv::imshow("src Image", src);
    cv::imshow("dst Image", sharpened_kernel);

    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

效果图如下所示:

Blog_OpenCV_Learnl_114.png


posted @ 2025-08-19 14:18  fengMisaka  阅读(637)  评论(0)    收藏  举报