专利对应:《一种音频信号转换视觉颜色信息的方法及系统》
该专利的主要步骤如下:
1. 对原始音频信号进行采样,得到若干音频块,对每个音频块:
2. 根据块的平均能量得到变量V,表示亮度;
3. 对块进行傅里叶变换后,得到频率矩阵f和幅度谱F;
4. 根据公式将频率矩阵转换为矩阵H,用于表示色相;
5. 对幅度谱矩阵归一化,得到矩阵S,用于表示饱和度,此时HSV颜色空间三个维度的值均已获得;
6. 根据色相,计算块内每个信号对应的RGB值;
7. 计算块内所有信号的平均RGB值,作为这个块的颜色。
通过audioread("")函数可以得到两个结果,分别是n*1的离散音频数据audio,和 采样率sampHz。采样率表达了每秒从原始音频中采样得到的离散数据的数量,即audio中每sampHz个数据是在一秒内。
[audio,sampHz] = audioread("music.mp3");
接下来,我们对数据audio采样成若干个m*1大小的数据块audioBlock。最终每个数据块生成一个颜色,为了使人眼难以捕捉到变化,我们使每秒颜色变化30次,即刷新率为30Hz,对应m取值为n/30.
rate = 30; %每秒颜色刷新次数
% 分块大小
sampSize = sampHz / rate;
第t个块数据可以由索引得到:
audioBlock = audio(t*sampSize + 1: (t + 1) * sampSize);
计算平均平方能量如下,对应亮度V表示为其与预设的最大平均平方能量之比。
maxE = 0.1;
avgE = mean(audioBlock.^2);
V = avgE / maxE;
对audioBlock进行傅里叶变换,得到幅度谱audioFF,对应的饱和度矩阵S为其归一化后的结果:
audioF = fft(audioBlock);
audioFF = abs(audioF);
S = (audioFF - min(audioFF)) / (max(audioFF) - min(audioFF));
根据专利所述,色相H和仅频率有关。傅里叶变换后的各个频率值可以根据索引的映射关系得到:
由于傅里叶变换后的频率左右对称,因此只计算左侧频率,然后反转拼接得到频率矩阵:
audioF = fft(audioBlock);
for j = 1:sampSize / 2 %频率左右对称,因此只计算左边的频率
f_left(j) = j * rate;
end
f = [f_left, f_left(end : -1 : 1)];
根据专利所述,他们排除了色相中红色到紫色段(色相对应270°到360°),对20000Hz映射到0-270°这个颜色范围上:
即
H = f * 270 / 2e4;
根据HSV转RGB公式,我们得到audioBlock中的每个RGB值,储存在RGB矩阵中:,最后改矩阵的均值即这个audioBlock的整体颜色:
RGB = zeros(sampSize, 3); % sampSize 行 3 列
for j = 1 : sampSize
switch(Hk(j))
case 0
RGB(j,:) = [V, tt(j), p(j)];
case 1
RGB(j,:) = [q(j), V, p(j)];
case 2
RGB(j,:) = [p(j), V, tt(j)];
case 3
RGB(j,:) = [p(j), q(j), V];
case 4
RGB(j,:) = [tt(j), p(j), V];
case 5
RGB(j,:) = [V, p(j), q(j)];
end
end
avgRGB = mean(RGB,1); %每列均值
注意,matlab语法中switch-case不需要break.
完整代码:
clear all
clc
[audio,sampHZ] = audioread("Notification.wav");
% 取第一个声道的前1000帧信息
audio = audio(1:sampHZ*3,1);
% 此时audio是1*n的矩阵
rate = 100;
% 分块
sampSize = sampHZ/rate;
t = 0;
showRGB = uint8(zeros(30,3*rate,3));
maxE = 255 * 255 * 0.3;% 假设audio中所有元素值位于0-1之间
for i = 1: sampSize : length(audio)
%得到没一个长度为sampSize的块
%未进行重采样
audioBlock = audio(t*sampSize + 1: (t + 1) * sampSize);
% 计算块内平均能量
avgE = mean(audioBlock.^2);
%亮度
% V = avgE / maxE;
V = 1;
% 频谱
audioF = fft(audioBlock);
for j = 1:sampSize / 2 %频率左右对称,因此只计算左边的频率
f_left(j) = j * rate;
end
f = [f_left, f_left(end : -1 : 1)];
H = f * 270 / 2e4;
% 幅度谱
audioFF = abs(audioF);
S = (audioFF - min(audioFF)) / (max(audioFF) - min(audioFF));
Hk = uint8(mod (floor(H/60),6));
ff = H/60 - double(Hk);
ff= ff';
%S = S.^0.5;
p = V .* (1 - S);
q = V .* (1 - ff.*S);
tt = V .* (1 - (1 - ff) .*S);
% 计算对应的均值
RGB = zeros(sampSize, 3); % sampSize 行 3 列
for j = 1 : sampSize
switch(Hk(j))
case 0
RGB(j,:) = [V, tt(j), p(j)];
case 1
RGB(j,:) = [q(j), V, p(j)];
case 2
RGB(j,:) = [p(j), V, tt(j)];
case 3
RGB(j,:) = [p(j), q(j), V];
case 4
RGB(j,:) = [tt(j), p(j), V];
case 5
RGB(j,:) = [V, p(j), q(j)];
end
end
avgRGB = mean(RGB,1); %每列均值
avgRGB = abs(avgRGB * 255 ); %转为uint8,便于转为16进制
showRGB(:,t+1,1) = avgRGB(1);
showRGB(:,t+1,2) = avgRGB(2);
showRGB(:,t+1,3) = avgRGB(3);
t = t + 1;
end
subplot(311),plot(audio)
subplot(312),plot(log(abs(fft(audio)+1)))
subplot(313),imshow(showRGB)
效果:
图1:振幅-时间图
图2:完整音频频谱图
图3:颜色-时间图