一、目的

通过本实验加深对数字图像增强操作的理解,熟悉MATLAB中的有关函数;了解直方图均衡化和卷积滤波的原理;熟悉低通和高通滤波模板的构造方法。

二、实验内容与设计思想

1、观察实验结果可看出,
原图像 I的对比度较低,暗部和亮部的细节不够明显,某些区域可能显得模糊或缺乏细节。处理后的图像 J对比度显著提高,细节更加丰富,尤其是边缘和纹理部分。
初始图像:
在这里插入图片描述

新图像:
在这里插入图片描述
原因:直方图均衡化可能会导致颜色的变化,因为它是对每个颜色通道分别进行处理的。某些颜色可能会变得更饱和或更淡。

I、J的直方图:
在这里插入图片描述

原图I的直方图集中在某些灰度级上,表明图像的对比度较低,直方图的峰值较高,而其他区域的值较低。
处理后的图像J更均匀地分布在所有灰度级上,且直方图的峰值降低,而其他区域的值会增加,整体分布更加均匀。

2、从输出结果可以看出,原始图像(左图)具有丰富的细节和鲜明的边缘,角色的表情、衣服的纹理以及背景的云朵都非常清晰和锐利,色彩鲜艳,对比度高。经过均值滤波处理后的图像(右图)则显得更加平滑和柔和,细节有所减弱,特别是角色的脸部表情、衣服的纹理和背景的云朵等细节变得较为模糊,边缘不再那么鲜明。此外,滤波后的图像色彩稍微变暗,对比度略低,整体色调趋于柔和,噪点也被有效去除,图像表面更加光滑。总的来说,均值滤波器成功地实现了图像的平滑处理,减少了噪点,但也带来了一些细节丢失和对比度下降的副作用。
在这里插入图片描述

  • 3x3 均值滤波器对图像进行平滑处理,但影响范围较小。图像的细节会有所减弱,但不会像 特别明显。边缘依然相对清晰,但噪点会被一定程度地去除。
  • 加权均值滤波器对中心像素赋予更大的权重,因此中心像素的影响更大。这种滤波器在平滑图像的同时,保留了更多的细节和边缘信息。相比于普通的均值滤波器,这种加权均值滤波器在保持图像细节方面表现更好。
  • 低通滤波器的主要作用是平滑图像,减少高频成分(如噪点和细节),使图像变得柔和。常见的低通滤波器有均值滤波器和高斯滤波器。
  • 高通滤波器的主要作用是增强图像的高频成分(如边缘和细节),使图像变得锐利。常见的高通滤波器有拉普拉斯滤波器和Sobel滤波器。

高通滤波和低通滤波的差别:
低通滤波器:平滑图像,减少高频成分(如噪点和细节),使图像变得柔和,图像的细节减弱,边缘变得模糊,噪点减少。
构造规律:低通滤波器的权重分布通常是均匀的(如均值滤波器)或呈高斯分布(如高斯滤波器),中心像素的权重较大,周围像素的权重逐渐减小。
高通滤波器:增强图像的高频成分(如边缘和细节),使图像变得锐利。图像的边缘和细节更加突出,但可能会引入一些噪点。
构造规律:高通滤波器的权重分布通常是中心像素的权重为正,周围像素的权重为负(如拉普拉斯滤波器),或者通过两个不同标准差的高斯滤波器相减(如高斯差分滤波器)。

3、使用C/C++编程实现直方图均衡化函数(histeq)和卷积滤波函数(imfilter)
主要步骤:
读取图像:使用cv::imread函数读取图像。
直方图均衡化:转换为灰度图,再使用cv::equalizeHist函数进行直方图均衡化。
卷积滤波:转换为灰度图,定义一个卷积核,再使用cv::filter2D函数进行卷积滤波。
显示图像:使用cv::imshow函数显示图像。
主要代码结构:
头文件和命名空间:引入必要的OpenCV头文件,并使用cv命名空间。
直方图均衡化函数:定义histeq函数,实现直方图均衡化。
卷积滤波函数:定义imfilter函数,实现卷积滤波。
主函数:读取图像,调用上述函数处理图像,调整图像大小,显示图像。

原始图像:
在这里插入图片描述

直方图均衡化:
在这里插入图片描述

卷积滤波:
在这里插入图片描述

三、使用环境

Matlab、VS、opencv

四、小结

1、问题:在调用cv::imread函数读取图像时,返回的图像矩阵为空。
解决过程:检查图像路径,并查看OpenCV库是否正确安装。
2、问题: 图片在显示时只显示了一小部分,而不是整个图片。
解决过程:使用resizeWindow函数调整窗口大小,使其适应图片的实际尺寸。
3、问题: 窗口标题显示乱码
原因分析:系统的默认编码与程序中使用的编码不一致。
解决方法:使用UTF-8编码保存源代码文件。
4、实验体会和收获
通过这次实验,我对OpenCV库有了更深入的了解,掌握了如何使用OpenCV读取、处理和显示图片的基本操作,了解了灰度映射的基本概念和不同类型的灰度映射方法,包括线性映射、分段线性映射、指数型映射和S型曲线映射,也提高了我的问题解决能力。实验中遇到的问题和解决过程让我更加深刻地理解了编程中的细节和注意事项。

源代码附件

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

// 直方图均衡化函数
cv::Mat histeq(const cv::Mat& input) {
    cv::Mat gray;
    if (input.channels() == 3) {
        cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
    }
    else {
        gray = input.clone();
    }

    cv::Mat output;
    cv::equalizeHist(gray, output);

    return output;
}

// 卷积滤波函数
cv::Mat imfilter(const cv::Mat& input, const cv::Mat& kernel) {
    cv::Mat gray;
    if (input.channels() == 3) {
        cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
    }
    else {
        gray = input.clone();
    }
    cv::Mat output;
    cv::filter2D(gray, output, -1, kernel);

    return output;
}

int main() {
    cv::Mat img = cv::imread("C:/Users/吴倩/Pictures/壁纸/pexels-emil-lin-770270.jpg");
    if (img.empty()) {
        std::cerr << "无法打开或找到图像" << std::endl;
        return -1;
    }

    cv::Mat eqImg = histeq(img);
    cv::Mat kernel = (cv::Mat_<float>(3, 3) << 1 / 9.0, 1 / 9.0, 1 / 9.0,
        1 / 9.0, 1 / 9.0, 1 / 9.0,
        1 / 9.0, 1 / 9.0, 1 / 9.0);

    cv::Mat filteredImg = imfilter(img, kernel);

    cv::Mat resizedImg, resizedEqImg, resizedFilteredImg;
    float scale = 0.5; 
    cv::resize(img, resizedImg, cv::Size(), scale, scale);
    cv::resize(eqImg, resizedEqImg, cv::Size(), scale, scale);
    cv::resize(filteredImg, resizedFilteredImg, cv::Size(), scale, scale);

    cv::imshow("原始图像", resizedImg);
    cv::imshow("直方图均衡化", resizedEqImg);
    cv::imshow("卷积滤波", resizedFilteredImg);
    cv::waitKey(0);

    return 0;
}


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

using namespace cv;
using namespace std;

// 线性映射
float linearMap(float s) {
    return s;
}

// 分段线性映射
float piecewiseLinearMap(float s) {
    if (s < 100)
        return s * 0.5;
    else if (s < 200)
        return (s - 100) * 2.0 + 50;
    else
        return (s - 200) * 0.5 + 150;
}

// 指数型映射
float exponentialMap(float s) {
    return 255 * pow(s / 255.0, 0.5);
}

// S型曲线映射
float sigmoidalMap(float s) {
    return 255 / (1 + exp(-0.05 * (s - 128)));
}

// 应用灰度映射
Mat applyGrayScaleMapping(const Mat& inputImage, float (*mappingFunc)(float)) {
    Mat outputImage(inputImage.size(), inputImage.type());

    for (int y = 0; y < inputImage.rows; y++) {
        for (int x = 0; x < inputImage.cols; x++) {
            float originalIntensity = static_cast<float>(inputImage.at<uchar>(y, x));
            float newIntensity = mappingFunc(originalIntensity);
            outputImage.at<uchar>(y, x) = static_cast<uchar>(newIntensity);
        }
    }

    return outputImage;
}

// 调整图片大小
Mat resizeImage(const Mat& inputImage, float scale) {
    int newWidth = static_cast<int>(inputImage.cols * scale);
    int newHeight = static_cast<int>(inputImage.rows * scale);
    Mat resizedImage;
    resize(inputImage, resizedImage, Size(newWidth, newHeight));
    return resizedImage;
}

int main() {
    // 读取图片
    Mat inputImage = imread("C:/Users/吴倩/Pictures/壁纸/pexels-emil-lin-770270.jpg");
    if (inputImage.empty()) {
        cout << "无法打开图片" << endl;
        return -1;
    }

    // 转换为灰度图
    Mat grayImage;
    cvtColor(inputImage, grayImage, COLOR_BGR2GRAY);

    // 应用四种不同的灰度映射
    Mat linearMappedImage = applyGrayScaleMapping(grayImage, linearMap);
    Mat piecewiseLinearMappedImage = applyGrayScaleMapping(grayImage, piecewiseLinearMap);
    Mat exponentialMappedImage = applyGrayScaleMapping(grayImage, exponentialMap);
    Mat sigmoidalMappedImage = applyGrayScaleMapping(grayImage, sigmoidalMap);

    // 调整图片大小到40%
    float scale = 0.4;
    inputImage = resizeImage(inputImage, scale);
    grayImage = resizeImage(grayImage, scale);
    linearMappedImage = resizeImage(linearMappedImage, scale);
    piecewiseLinearMappedImage = resizeImage(piecewiseLinearMappedImage, scale);
    exponentialMappedImage = resizeImage(exponentialMappedImage, scale);
    sigmoidalMappedImage = resizeImage(sigmoidalMappedImage, scale);

    // 保存结果
    imwrite("线性映射.png", linearMappedImage);
    imwrite("分段线性映射.png", piecewiseLinearMappedImage);
    imwrite("指数型映射.png", exponentialMappedImage);
    imwrite("S型曲线映射.png", sigmoidalMappedImage);

    // 创建窗口并设置中文标题
    namedWindow("原始图片", WINDOW_NORMAL);
    namedWindow("灰度图片", WINDOW_NORMAL);
    namedWindow("线性映射", WINDOW_NORMAL);
    namedWindow("分段线性映射", WINDOW_NORMAL);
    namedWindow("指数型映射", WINDOW_NORMAL);
    namedWindow("S型曲线映射", WINDOW_NORMAL);

    // 显示结果
    imshow("原始图片", inputImage);
    imshow("灰度图片", grayImage);
    imshow("线性映射", linearMappedImage);
    imshow("分段线性映射", piecewiseLinearMappedImage);
    imshow("指数型映射", exponentialMappedImage);
    imshow("S型曲线映射", sigmoidalMappedImage);

    // 输出中文信息
    cout << "图片处理完成,按任意键退出" << endl;

    waitKey(0);

    return 0;
}
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐