一、原理介绍
SVD,即奇异值分解(Singular Value Decomposition),是线性代数中一种重要的矩阵分解方法,它是特征分解在任意矩阵上的推广,主要目的是提取一个矩阵的最重要的特征。这种方法并不要求分解的矩阵为方阵,因此在许多领域都有广泛的应用,特别是在机器学习和数据降维等方面。
奇异值分解可以将一个复杂的矩阵分解为三个相对简单的矩阵的乘积,这三个矩阵分别是:
- U矩阵:一个m×m的酉矩阵(在复数域内),也是左奇异矩阵。U的列向量被称为左奇异向量。
- Σ矩阵:一个m×n的对角矩阵,对角线上的元素被称为奇异值,它们是从大到小排列的。这个矩阵实际上是一个由奇异值构成的对角矩阵,其余元素为0。
- V矩阵:一个n×n的酉矩阵(在复数域内),也是右奇异矩阵。V的列向量被称为右奇异向量。
SVD的公式可以表示为:A = UΣV^T,其中A是待分解的矩阵,U、Σ、V^T分别是分解后得到的三个矩阵。本文介绍利用svd奇异值分解将图片进行压缩,代价就是减低清晰度。
%svd--牺牲一定的清晰度来减少图片所占内存
clear;clc;
%读取为三维uint8矩阵
aa = imread('zhiyin.jpg'); %aa是三维矩阵
figure(1);
h = imshow(aa); %展示图片
% figure(2);
% imshow(rgb2gray(aa)); %彩色转灰色
%aa是uint8类型,转化为double型才能进行svd分解
a1 = double(aa(:,:,1)); %R红色矩阵
a2 = double(aa(:,:,2)); %G绿色矩阵
a3 = double(aa(:,:,3)); %B蓝色矩阵
%对a1,a2,a3矩阵进行svd分解
[u1,d1,v1] = svd(a1);
[u2,d2,v2] = svd(a2);
[u3,d3,v3] = svd(a3);
%非方阵也可以用diag函数得出对角元素
eig1 = diag(d1);
eig2 = diag(d2);
eig3 = diag(d3);
my_eig = {eig1,eig2,eig3}; %元胞数组
%对角元素求和
sum1 = sum(eig1);
sum2 = sum(eig2);
sum3 = sum(eig3);
my_sum = {sum1,sum2,sum3};
%temp表示不同阶段保留的清晰度
temp1 = 0;
temp2 = 0;
temp3 = 0;
my_temp = {temp1,temp2,temp3};
%RGB分别至少至少保留0.8,0.75,0.8的清晰度
ratio = [0.8,0.75,0.8];
bb = zeros(1,3); %初始化
for i = 1:3
for j = 1:length(my_eig{i})
my_temp{i} = my_temp{i}+my_eig{i}(j);
if (my_temp{i}/my_sum{i})>ratio(i)
break %大于预选比例时跳出循环
end
end
bb(i) = j;
end
r = u1(:,1:bb(1))*d1(1:bb(1),1:bb(1))*v1(:,1:bb(1))';
g = u2(:,1:bb(2))*d2(1:bb(2),1:bb(2))*v2(:,1:bb(2))';
b = u3(:,1:bb(3))*d3(1:bb(3),1:bb(3))*v3(:,1:bb(3))';
% cat(dim,A,B),沿维度dim将B串联到A的末尾
compress_img = cat(3,r,g,b);
compress_jige = uint8(compress_img);
figure(3);
imshow(compress_jige);
二、对比压缩前后的清晰度
仔细观察,可以发现压缩后的清晰度确实有所下降,但是压缩后的清晰度还是可以接受的。
三、对比内存占比
压缩前的图片信息保存在aa矩阵中,为640*640*3的uint8数据类型。
压缩后的图片信息保存在u1,u2,u3,d1,d2,d3,v1,v2,v3这9个矩阵中,
u1,v1取前67列,d1取67行67列;u2,v2取前54列,d2取54行54列;u3,v3取前58列,d3取58行58列;数据类型为double型。
对比可知,内存有所减少。其实svd方法,只要清晰度有减低内存就会有所减少。