% 基于SVD的图像压缩演示clear; clc; close all;%% 1. 读取并显示原始图像try% 尝试读取内置图像original_img = imread('ex2.jpg');catch% 如果内置图像不存在,创建一个示例图像fprintf('使用内置图像失败,创建示例图像...\n');[X, Y] = meshgrid(1:256, 1:256);original_img = uint8(128 + 100 * sin(X/20) .* cos(Y/15));end% 如果图像是彩色的,转换为灰度图if ndims(original_img) == 3 && size(original_img, 3) == 3original_img = rgb2gray(original_img);end% 转换为double类型以便计算A = double(original_img);% 显示原始图像figure('Position', [100, 100, 1200, 600]);subplot(2, 3, 1);imshow(original_img);title('原始图像', 'FontSize', 12);xlabel(['尺寸: ', num2str(size(A, 1)), '×', num2str(size(A, 2))]);%% 2. 对图像矩阵进行SVD分解fprintf('正在进行SVD分解...\n');[U, S, V] = svd(A);% 获取奇异值singular_values = diag(S);total_singular_values = length(singular_values);fprintf('SVD分解完成!总奇异值个数: %d\n', total_singular_values);%% 3. 使用不同数量的奇异值重建图像k_values = [1, 5, 20, 50, 100]; % 选择不同的k值进行测试% 计算原始图像需要存储的元素数量original_elements = numel(A);fprintf('原始图像需要存储的元素数量: %d\n', original_elements);for i = 1:length(k_values)k = k_values(i);if k > total_singular_valuesk = total_singular_values;end% 使用前k个奇异值重建图像A_compressed = U(:, 1:k) * S(1:k, 1:k) * V(:, 1:k)';% 确保数值在合理范围内A_compressed = max(min(A_compressed, 255), 0);% 计算压缩比compressed_elements = size(U, 1)*k + k + size(V, 1)*k;compression_ratio = compressed_elements / original_elements;% 显示重建后的图像subplot(2, 3, i+1);imshow(uint8(A_compressed));title_str = sprintf('k = %d\n压缩比: %.1f%%', k, compression_ratio*100);title(title_str, 'FontSize', 10);% 计算PSNR(峰值信噪比)mse = mean((A(:) - A_compressed(:)).^2);if mse > 0psnr_val = 20*log10(255/sqrt(mse));elsepsnr_val = Inf;endxlabel(sprintf('PSNR: %.1f dB', psnr_val));end%% 4. 绘制奇异值分析图figure('Position', [100, 500, 1000, 400]);% 绘制奇异值衰减曲线subplot(1, 2, 1);plot_range = min(100, total_singular_values);plot(1:plot_range, singular_values(1:plot_range), 'b-', 'LineWidth', 2);xlabel('奇异值序号');ylabel('奇异值大小');title('前100个奇异值');grid on;% 绘制累积能量subplot(1, 2, 2);cumulative_energy = cumsum(singular_values.^2) / sum(singular_values.^2);plot(1:plot_range, cumulative_energy(1:plot_range), 'r-', 'LineWidth', 2);xlabel('使用的奇异值数量 (k)');ylabel('累积能量比例');title('信息保留程度 vs k值');grid on;% 标记关键点hold on;marker_k = [1, 5, 20, 50];for j = 1:length(marker_k)k = marker_k(j);if k <= plot_rangeplot(k, cumulative_energy(k), 'ro', 'MarkerSize', 8, 'MarkerFaceColor', 'red');text(k, cumulative_energy(k)-0.1, sprintf('k=%d\n%.1f%%', k, cumulative_energy(k)*100), ...'HorizontalAlignment', 'center', 'FontSize', 8);endend%% 5. 交互式压缩演示figure('Position', [200, 200, 800, 600]);fprintf('\n=== 交互式压缩演示 ===\n');fprintf('请输入想要的压缩级别 (k值,1-%d),输入0退出: ', total_singular_values);while truek_input = input('');if k_input == 0break;endif k_input < 1 || k_input > total_singular_valuesfprintf('请输入1-%d之间的数字: ', total_singular_values);continue;end% 使用指定k值重建图像A_custom = U(:, 1:k_input) * S(1:k_input, 1:k_input) * V(:, 1:k_input)';A_custom = max(min(A_custom, 255), 0);% 计算指标compressed_elems = size(U, 1)*k_input + k_input + size(V, 1)*k_input;comp_ratio = compressed_elems / original_elements;info_kept = cumulative_energy(k_input) * 100;mse_custom = mean((A(:) - A_custom(:)).^2);if mse_custom > 0psnr_custom = 20*log10(255/sqrt(mse_custom));elsepsnr_custom = Inf;end% 显示结果clf;subplot(1, 2, 1);imshow(original_img);title('原始图像', 'FontSize', 14);subplot(1, 2, 2);imshow(uint8(A_custom));title_str = sprintf('压缩图像 (k=%d)', k_input);title(title_str, 'FontSize', 14);% 显示压缩信息info_str = sprintf(['压缩比: %.2f%%\n', ...'信息保留: %.1f%%\n', ...'PSNR: %.1f dB\n', ...'存储元素: %d → %d'], ...comp_ratio*100, info_kept, psnr_custom, ...original_elements, compressed_elems);text(10, 30, info_str, 'Color', 'white', 'FontSize', 12, ...'BackgroundColor', 'black', 'VerticalAlignment', 'top');fprintf('k=%d: 压缩比=%.2f%%, 信息保留=%.1f%%, PSNR=%.1f dB\n', ...k_input, comp_ratio*100, info_kept, psnr_custom);fprintf('继续输入k值(1-%d)或输入0退出: ', total_singular_values);end%% 6. 压缩效果总结fprintf('\n=== 压缩效果总结 ===\n');fprintf('k值\t压缩比\t\t信息保留\tPSNR(dB)\n');fprintf('------------------------------------------------\n');for k = [1, 5, 10, 20, 50, 100]if k <= total_singular_valuescompressed_elems = size(U, 1)*k + k + size(V, 1)*k;comp_ratio = compressed_elems / original_elements;info_kept = cumulative_energy(k) * 100;A_temp = U(:, 1:k) * S(1:k, 1:k) * V(:, 1:k)';mse_temp = mean((A(:) - A_temp(:)).^2);if mse_temp > 0psnr_temp = 20*log10(255/sqrt(mse_temp));elsepsnr_temp = Inf;endfprintf('%d\t%.2f%%\t\t%.1f%%\t\t%.1f\n', k, comp_ratio*100, info_kept, psnr_temp);endendfprintf('\n程序运行完成!\n');
help format 得到的帮助文档对于有理数格式描述如下:分子或分母较大时用 * 符号代替。也可以简写为 RAT。那么计算得到的 * 符号应该如何判断是分子较大还是分母较大呢? 重新换成 long 格式进行判断吗?测试了一下,只有 1e-6 和 1e6 之间的数可以用有理数显示。
1. 对于可选位置参数 (addOptional) 和可选参数 (addParameter) 共同存在的情形, 仍不能正确的解析, 示例在原来的例子中加入 addRequired 如下:
function findArea(varargin)
p = inputParser;
p = addRequired(p, 'width', @(x) isnummeric(x) && isscalar(x) && (x > 0));
p = addOptional(p, 'height', 1);
p = addParameter(p, 'units', 'm');
p = addParameter(p, 'shape', 'square');
p = parse(p, varargin{:});
width = p.Results.width
height = p.Results.height
units = p.Results.units
shape = p.Results.shape
endfindArea(2, 3, "units", "cm") 现在可以正确解析了. 但是如果可选位置参数输入不足时, 如 findArea(2, "units", "cm") 就不能正常解析了.在 inputParser 类的代码第 152 行定义的当前参数位置指针 pos = 1, 有一个必须参数和一个可选位置参数, pos 经过两次加一得到 pos = 3, 此时解析参数的时候, 剩余可选参数为 varargin(3:end) = "cm", "units" 虽然没有像之前的版本被赋值给 "height", 但也被吞掉消失. 只剩下 "units" 不是成对出现导致解析可选参数出错.2. 在添加参数的时候, checkArgs(list, value, validator) 函数是通过 ismember 函数来判断是否存在该参数名的.ismember 只能判断字符元胞数组, 那么在添加参数的时候只能使用字符数组, 如上面的示例 p = addOptional(p, 'width', 1); 原本使用的字符串在使用的时候就全部报错.这个问题只需要在 inputParser 中添加几个 char 全部转化成字符数组即可, 而不用关心用户输入的是字符还是字符串.分别是 addParameter 函数 101, 102 行 paramName 外面添加 char(), addOptional 函数 112, 113 行 paramName 外面添加 char(), addRequired 函数 123 行添加 char().
您好,写程序的时候要读入csv文件,然后将计算结果保存到csv文件中,看了帮助文档,是可以通过界面导入导出csv文件,但是命令的话只有readcsv函数,是不是没有相应的写csv文件的函数?谢谢!
您好,在使用北太天元 4.2.0 时,我发现 readmatrix 方法不支持打开 .dat 后缀的带分隔符文本文件,若打开会报错
错误使用函数 readmatrix 仅支持'.txt'、'.csv'、'.xls' 及 '.xlsx' 文件格式。相比 MATLAB 中的 readmatrix 方法(https://ww2.mathworks.cn/help/matlab/ref/readmatrix.html),目前 Baltamatica 尚不支持其中的 .dat,.zip 和 .tar 等后缀的文件。但因为 .dat 后缀只表示一种和 .txt 相同的文本文件,实现应当较易,而我平时惯用的数据文件格式就是 .dat,所以不知道未来是否能够在 readmatrix 方法中加入对 .dat 文件的支持。谢谢您!
更新失败,如图所示。我的安装路径是D:\Programs\baltamatica. C:/Users/(用户名)/Downloads和D:\baltam这两个目录都不存在。
首先生成一个测试文件,第一行类似于表头,2到4行每行存储3个数,用tab键分隔
fwid = fopen("test.txt", "w");
fprintf(fwid, "%s\t%s\t%s\n", "column_1", "column_1", "column_3");
fprintf(fwid, "%d\t%d\t%d\n", 1, 2, 3);
fprintf(fwid, "%d\t%d\t%d\n", 4, 5, 6);
fprintf(fwid, "%d\t%d\t%d\n", 7, 8, 9);
fclose(fwid);得到的文件共5行,第5行是一空行。下面以 fgetl 函数逐行读取该文件。方法一:以 feof 函数作为 while 循环的判断条件,依次读取文件的每一行并显示出来frid = fopen("test.txt", "r");
fgetl(frid);
% 是否到达文件末尾 (EOF)
while ~feof(frid)
line = fgetl(frid);
disp(line);
end
fclose(frid);该方法在北太天元中除了显示文件中的3行数字,还会显示一个-1,这个-1是fgetl判断到文件末尾后返回的。而在 MATLAB 中只显示 3 行数字。方法二:考虑到方法一中 fgetl 函数返回了 -1 但 feof 条件没有起作用,将 while 循环条件改为 true,循环内部满足 feof 条件 break 循环。frid = fopen("test.txt", "r");
fgetl(frid);
while true
line = fgetl(frid);
% 如果到达文件末尾,则退出循环
if feof(frid)
break;
end
disp(line);
end
fclose(frid);该方法在北太天元中输出符合预期,但在 MATLAB 中只输出两行数据也就是说,在北太天元中,读取了 7 8 9 三个数后,需要再读取一行才到末尾 (EOF),所以读取到的 -1 没有 disp;而在 MATLAB 中,读取了之后已经到末尾,虽然读取了这三个数,就跳出循环不再显示。代码中的 if 判断更换任意位置在北太天元中都将显示 -1。验证:手动逐行读取文件进行验证frid = fopen("test.txt", "r");
fgetl(frid);
disp(feof(frid));
fgetl(frid);
disp(feof(frid));
fgetl(frid);
disp(feof(frid));
fgetl(frid);
disp(feof(frid));
fgetl(frid);
disp(feof(frid));
fclose(frid);在北太天元和 MATLAB 中输出的结果分别是测试文件共 5 行,前四行有内容,第五行是空行,在 MATLAB 中,读取完第四行就判断为文件末尾,而在北太天元中,五行全部读完才判断是文件末尾。
在插件中加载FAME 出现未加载成功在命令行窗口输入load_plugin(“FAME”) 出现未定义的函数或变量 '“FAME”'
在B站偶然看到李若教授的视频,自13年博士论文答辩请了李教授为评委之后就没见过了,仔细看完了整个视频,了解了北太天元。使用北太天元有几天了,有个问题反馈一下。函数:试了好多次,代码拷贝到网页直接去掉了换行符。。。直接上连接吧https://www.topopt.mek.dtu.dk/-/media/Subsites/topopt/apps/dokumenter-og-filer-til-apps/top88.ashx?la=da&hash=43B36C6FDE548DF726ACDDFBB952491391B8109F调用:tic; top88(120, 40, 0.5, 3.0, 3.5, 1); toc存在问题:性能问题。花了52s才运行到44行(组装刚度矩阵),而使用octave只需18s即可执行完整个程序88行。兼容问题。貌似sum函数不能针对sparse矩阵进行操作。导致程序出错。
使用 symbolic 插件提供的 sym 命令创建符号变量 x 后,工作区不显示任何变量信息使用 whos 命令查看发现只有 ans 这个变量,且类型识别为 extern. 将这个 ans 赋值给 x 之后,无论参与运算工作区都是不显示任何信息的,也就是工作区无法识别 extern 这种类型的变量。目前将所有公布过的正式版本都安装尝试了一遍,都是这种情况。
问题类型:功能问题使用的操作系统:Windows11问题描述:sort函数的功能和MATLAB有出入。当数组存在重复元素时,不会对重复元素排序。代码:clc;clear;a=ones(100,1);a(4,1)=2;a(10,1)=2;a(100,1)=2;[~,b]=sort(a)
x = 0:0.1:piplot(sin(x),'-o','MarkerIndices')报错:函数plot求值出错: 数据参数无效。