一、目的
通过本次实验,加深对数字图像的理解,熟悉MATLAB中的有关函数;应用DCT对图像进行变换;熟悉图像常见的统计指标,实现图像几何变换的基本方法。
二、内容与设计思想
1、实验内容:选择两幅图像,读入图像并显示,同时使用Matlab计算图像的大小、灰度平均值、协方差矩阵、灰度标准差和相关系数。
设计思想:
(1)图像读取和预处理:通过 imread 读取两张图像,确保图像文件路径正确并能够成功加载,并将彩色图像转换为灰度图像。
(2)灰度平均值:通过mean函数计算两幅图像的灰度平均值,反映图像的亮度特征。每个像素的灰度值可以理解为一个标量,整个图像的灰度平均值提供了该图像的整体亮度信息。
(3)协方差矩阵:使用cov函数计算图像的灰度值的协方差,反映图像中不同像素之间的灰度关系。这里,使用cov(double(picture(: )))是为了将图像的像素值展平为一维向量后计算其协方差。
(4)标准差:通过std函数计算每张图像的灰度标准差,标准差反映了图像灰度值的分布离散程度。标准差越大,表示图像灰度变化越剧烈,细节丰富;标准差越小,图像灰度变化较平稳,细节较少。
(5)计算图像相关系数:使用corr2 函数来计算两幅图像的相关系数。
输出结果:
根据实验的输出结果,可以得到,它们的图像的尺寸一致;两幅图像的灰度平均值非常接近,差异约为 1.06。灰度平均值反映了图像的亮度,较高的平均值表示图像整体较亮。这个差异相对较小,说明两幅图像在亮度方面比较接近;两幅图像的协方差矩阵相差不大,差异仅约为 30,说明它们的灰度变化模式相似;标准差衡量的是灰度值的波动性,标准差越大,图像的灰度变化越剧烈,细节更多。两幅图像的标准差差异也非常小,仅约 0.32,表明它们在灰度变化的分布上相差不大;相关系数为-0.0391,意味着两幅图像在灰度分布上的相似性较低。负值说明两幅图像在某些灰度层级上呈现出一定的反向关系,但由于值非常接近 0,说明它们的整体结构或模式差异较大。
2、实验内容:选择一幅图像,并对其添加高斯噪声,重复步骤多次,再将所得到的图像相加取平均,检验加法去噪的效果,写出加法去噪的原理。
设计思想:
通过imread函数加载图像,并循环用imnoise函数生成的带有高斯噪声的图像,尺寸与原始图像相同。在每次循环中,图像J会被加到total中,total是初始化为一个大小与原图像相同的零矩阵,用于存储所有噪声图像的累加结果。将 total除以num得到去噪的平均图像。最终,转换为uint8类型,以便显示和处理。
输出结果:
可以看到原始图像显示的是没有任何噪声的清晰图像;带噪图像很模糊,图像细节可能会被模糊或丢失。显示的带噪图像可能会出现斑点或颜色不一致的现象,尤其在高噪声区域更加明显;加法去噪后能看到通过对多张带噪图像进行平均,噪声会被部分抵消,因为噪声是随机分布的,多个带噪图像的平均值能够减轻噪声的影响,恢复图像的真实细节,但相比于原始图像还是比较模糊。
3、实验内容:FFT变换
设计思想:
f=zeros(30,30); f(5:24,13:17)=1; 创建了一个30x30的矩阵,其中中间区域为白色矩形(值为 1),其余区域为黑色(值为 0)。通过 fft2(f) 对图像进行二维快速傅里叶变换,得到频域表示 F。 log(abs(F)) 对频域结果取模并对其取对数,用于增强可视化效果。imshow(F2,[-1 5]) 将频域的图像显示出来,[-1 5] 设置了显示的像素值范围,colormap(jet) 使用了“jet”色图。修改后的代码中,fft2(f, 256, 256) 对图像进行了零填充,将图像的大小从 30x30 增加到 256x256。fftshift(F) 将频谱从左上角的低频区域移到图像中心,使得频域图像更容易观察。
输出结果:
①如图所示:
原图像(左图)显示为一个简单的30x30图像,其中白色矩形处表示一个频率信号的集中区域。频域图像(右图) 会显示傅里叶变换后的频谱。由于输入图像的大小较小且只包含一个简单的矩形区域,频域图像的中心部分通常包含了低频信息,而周围则是高频信息的表现。
②如图所示:
对比可得,原始图像的傅里叶变换可能会使得低频部分偏离图像的中央,fftshift函数则会将这些低频部分移动到中心。fftshift 函数会将图像的频谱中的低频分量从四个角落移到频谱的中心位置,使得频域图像更加对称,便于观察。
③如图所示:
当增大图像尺寸(60x60)和白色矩形区域的大小(15:46, 13:47)时,傅里叶变换后频域的分辨率提高,频域图像的细节更清晰,出现更多的高频分量,低频部分更加集中且分布更加均匀。
原因:这些变化的原因在于傅里叶变换是基于图像的空间频率特性进行转换的,不同的图像内容和尺寸都会影响频域的表现。
4、输出结果:
图像色彩变换规律:在 DCT 变换后,图像的频域表示被提取出来,原始的空间域图像被转化成频率信息,低频成分集中在图像的左上角,它们通常对应于图像中变化较少、细节较少的区域,高频成分集中在图像的右下角,对应的是图像中细微的变化和快速的像素变化,通常位于图像的边缘和细节部分。
图像的颜色发生变化的原因:在进行 DCT 变换后,图像的频率成分会呈现出很大的动态范围。例如,低频成分的幅值通常较大,而高频成分幅值较小。为了增强对比度和细节,通常采用对数变换(log(abs(J))),这样做可以有效扩展图像中细节较少的部分,使高频部分更可见,从而影响图像的颜色表现。jet(64)是一种颜色映射方案,它将数值范围映射到一系列颜色上,通常从蓝色到红色表示数值从低到高。在 DCT 变换后的图像中,频率较低的区域(左上角)会映射到图像的某一颜色(如红色),而频率较高的区域(右下角)则会映射到另一种颜色(如蓝色)。这会导致图像显示出明显的色彩变化。
5、①图像压缩的基本原理:
频率域表示:通过DCT变换,将图像从空间域转换到频率域。
去除冗余信息:通过丢弃图像的高频信息,减少存储的数据量。
重建图像:通过逆DCT变换,将图像从频率域恢复回空间域。
图像压缩通过这种方式实现了数据量的压缩,且通常会保留图像的大部分重要信息,从而保证视觉质量。
②diff=I-I2; figure; imshow(diff,[]);
这将显示一幅图像,其中的像素值表示原始图像和压缩后图像之间的差异。差异越大,说明压缩造成的失真越大。
③
非零元素个数与图像差异关系:
非零元素数量增加,更多低频信息被保留,压缩效果减少,图像质量提高,MSE值下降。
非零元素数量减少,更多高频信息被丢弃,压缩效果增强,但图像质量下降,如图所示压缩后的照片模糊许多,MSE值上升。
变换后系数的重要性:
低频系数:图像的主要信息(如亮度、形状等)通常集中在低频系数中,这些系数对于图像的质量至关重要。
高频系数:细节信息(如边缘、噪声等)通常集中在高频系数中,这些系数对人眼的感知影响较小,因此可以舍弃。
综上所述:保留较多的低频系数会保证较好的图像质量,减少高频系数则有助于压缩图像的文件大小,但图像会失去一些细节。
④可以看出,第二次比第一次的图像质量要差很多,因此验证可得③的结论是正确的。
6、原图:
变换后的图像:
7、实验内容:编写程序实现图像的水平垂直和中心对称
设计思想:
图像可以通过二维矩阵表示,每个元素通常表示一个像素点的颜色值。对称操作实际上是对矩阵进行某些特定的转换,通过修改矩阵的行列索引来实现。
水平对称:将矩阵的每一列逆序。
垂直对称:将矩阵的每一行逆序。
中心对称:将整个矩阵在行和列上同时进行逆序。
输出结果:
三、使用环境
Matlab、Dev-C++、openCV
四、小结
1、第一题在求相关系数时报错
分析:在使用 corr2 函数计算两个图像的相关系数时,它要求两个图像的尺寸必须相同。
2、在进行图像处理操作时,结果图像的处理效果与预期不符。
原因:在不同的图像处理步骤中,图像的类型(如 BGR 转灰度图)没有正确转换,导致处理结果不正确。
3、 实验体会和收获
通过这次实验,我深刻认识到理论知识的重要性,尤其是在图像处理领域。通过实际编程实践,我能更好地理解和运用图像处理算法,尤其是在 OpenCV 等工具库的使用上得到了更深入的理解。在实验中遇到的问题让我对如何快速定位和解决问题有了更高的敏感性。从查阅文档、调试程序到在网上寻找解决方案,每一步都增加了我的技术储备和应对突发问题的能力。通过本次实验,我不仅提升了自己的编程技能,还增强了系统调试和问题解决的能力。将来的实验中,我会更加注重理论学习与实践操作的结合,并不断积累解决问题的经验。
源代码附件
1、
picture1 = imread(‘C:\Users\吴倩\Pictures\Saved Pictures\图片一.png’);
picture2 = imread(‘C:\Users\吴倩\Pictures\Saved Pictures\图片二.png’);
if size(picture1, 3) == 3
picture1 = rgb2gray(picture1);
end
if size(picture2, 3) == 3
picture2 = rgb2gray(picture2);
end
% 图像的大小
size1 = size(picture1);
size2 = size(picture2);
disp(‘图像一的大小:’);
disp(size1);
disp(‘图像二的大小:’);
disp(size2);
% 灰度平均值
mean1 = mean(picture1(😃);
mean2 = mean(picture2(😃);
disp(‘图像一的灰度平均值为:’);
disp(mean1);
disp(‘图像二的灰度平均值为:’);
disp(mean2);
% 协方差矩阵
cov1 = cov(double(picture1(😃));
cov2 = cov(double(picture2(😃));
disp(‘图像一的协方差矩阵:’);
disp(cov1);
disp(‘图像二的协方差矩阵:’);
disp(cov2);
% 灰度标准差
sdg1 = std(double(picture1(😃));
sdg2 = std(double(picture2(😃));
disp(‘图像一的灰度标准差:’);
disp(sdg1);
disp(‘图像二的灰度标准差:’);
disp(sdg2);
% 相关系数
correlation = corr2(picture1, picture2);
disp(‘两张图片的相关系数为:’);
disp(correlation);
2、
I = imread(‘C:\Users\吴倩\Pictures\壁纸\图片一.jpg’);
num = 10;
[m, n, p] = size(I);
total = zeros(m, n, p);
for k = 1:num
J = imnoise(I, ‘gaussian’, 0, 0.01);
total = total + double(J);
end
aver = uint8(total / num);
subplot(2, 2, 1), imshow(I), title(‘原始图像’);
subplot(2, 2, 2), imshow(J), title(‘带噪图像’);
subplot(2, 2, 3), imshow(aver), title(‘加法去噪结果’);
3、
f = zeros(60, 60);
f(15:46, 13:47) = 1;
figure(1)
imshow(f);
F=fft2(f,256,256);
F2=fftshift(F);
figure(2)
imshow(F2, [-1 5]);
colormap(jet);
4、
RGB = imread(‘C:\Users\吴倩\Desktop\美丽女人照片\IMG_7091.JPG’);
I = rgb2gray(RGB);
figure(1);
imshow(I);
J = dct2(I);
figure(2);
imshow(log(abs(J)),[]), colormap(jet(64)), colorbar
5、
I=imread(‘C:\Users\吴倩\Pictures\壁纸\图片三.jpg’);
I = rgb2gray(I);
I=im2double(I);
T=dctmtx(8);
B=blkproc(I,[8 8],‘P1xP2’,T,T’);
mask=[ 1 1 1 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0];
B2=blkproc(B,[8 8],‘P1.x’,mask);
I2=blkproc(B2,[8 8],'P1x*P2’,T’,T);
subplot(1,2,1),imshow(I);
subplot(1,2,2),imshow(I2);
6、
#include <opencv2/opencv.hpp>
#include
#include
cv::Mat applyDCT(const cv::Mat& src) {
cv::Mat dct;
cv::dct(src, dct);
return dct;
}
cv::Mat applyIDCT(const cv::Mat& dct) {
cv::Mat idct;
cv::idct(dct, idct);
return idct;
}
cv::Mat applyMask(const cv::Mat& dct, const cv::Mat& mask) {
cv::Mat maskedDct = dct.clone();
for (int i = 0; i < dct.rows; ++i) {
for (int j = 0; j < dct.cols; ++j) {
if (mask.at(i, j) == 0) {
maskedDct.at(i, j) = 0;
}
}
}
return maskedDct;
}
int main() {
cv::Mat image = cv::imread(“C:\Users\吴倩\Pictures\壁纸\图片三.jpg”, cv::IMREAD_GRAYSCALE);
if (image.empty()) {
std::cerr << “Error!” << std::endl;
return -1;
}
image.convertTo(image, CV_32F, 1.0 / 255.0);
int blockSize = 8;
cv::Mat dctImage = image.clone();
for (int i = 0; i < image.rows; i += blockSize) {
for (int j = 0; j < image.cols; j += blockSize) {
cv::Rect roi(j, i, blockSize, blockSize);
cv::Mat block = image(roi);
cv::Mat dctBlock = applyDCT(block);
dctBlock.copyTo(dctImage(roi));
}
}
cv::Mat mask = cv::Mat::ones(blockSize, blockSize, CV_32F);
int nonZeroCount = 4; //
for (int i = nonZeroCount; i < blockSize; ++i) {
for (int j = nonZeroCount; j < blockSize; ++j) {
mask.at(i, j) = 0;
}
}
cv::Mat compressedImage = image.clone();
for (int i = 0; i < image.rows; i += blockSize) {
for (int j = 0; j < image.cols; j += blockSize) {
cv::Rect roi(j, i, blockSize, blockSize);
cv::Mat block = dctImage(roi);
cv::Mat maskedBlock = applyMask(block, mask);
maskedBlock.copyTo(compressedImage(roi));
}
}
cv::Mat reconstructedImage = compressedImage.clone();
for (int i = 0; i < compressedImage.rows; i += blockSize) {
for (int j = 0; j < compressedImage.cols; j += blockSize) {
cv::Rect roi(j, i, blockSize, blockSize);
cv::Mat block = compressedImage(roi);
cv::Mat idctBlock = applyIDCT(block);
idctBlock.copyTo(reconstructedImage(roi));
}
}
cv::imshow("原图", image);
cv::imshow("重建图像", reconstructedImage);
cv::waitKey(0);
cv::Mat diffImage;
cv::absdiff(image, reconstructedImage, diffImage);
cv::imshow("Difference Image", diffImage);
cv::waitKey(0);
std::cout << "Non-zero elements in mask: " << nonZeroCount << std::endl;
return 0;
}
7、
picture = imread(‘C:\Users\吴倩\Pictures\Saved Pictures\图片一.png’);
%水平对称
hor = picture;
hor = hor(:, end👎1, 😃;
%垂直对称
ver = picture;
ver = ver(end👎1, :, 😃;
% 中心对称
cen = picture;
cen = cen(end👎1, end👎1, 😃;
figure;
subplot(2,2,1);
imshow(picture);
title(‘原图’);
subplot(2,2,2);
imshow(hor);
title(‘水平对称’);
subplot(2,2,3);
imshow(ver);
title(‘垂直对称’);
subplot(2,2,4);
imshow(cen);
title(‘中心对称’);