修改渐变排序WAV转PNG代码后,如何调整pngtowav.py实现逆向转换?
问题分析与解决方案
首先得敲个重点:你在WAV转PNG时用了im.putdata(list(sorted(imageRgbArray))),这会把所有音频对应的RGB值按颜色排序,直接打乱了原始音频帧的顺序。这意味着哪怕你完美把每个像素转成音频值,得到的WAV文件的声音顺序也和原文件完全不一样,没法还原出原本的音频。如果你的目标是还原原始声音,要么去掉转PNG代码里的sorted(),要么得把排序的索引存下来,还原时再把顺序改回去。
接下来解决RGB到音频值的正确转换逻辑:
先回顾WAV→PNG的转换步骤
你的转PNG代码里,把音频采样转成RGB的流程是:
- 把范围
-32768 ~ 32767的音频值,转成0 ~ 65535的convertedData(也就是convertedData = int(data[0]) + 32768) - 把这个16位的数拆成3个5位的分量(总15位,剩下1位会被丢掉,对音频还原影响很小):
这里bits = 5 rgbData = tuple([(convertedData>>bits*i)&(2**bits-1) for i in range(3)])i=0对应低5位(R分量),i=1对应中间5位(G分量),i=2对应高5位(B分量) - 每个5位分量左移3位,扩展成0-255之间的8位RGB值(
rgbData = tuple(map(lambda x: x<<3, rgbData)))
PNG→WAV的逆转换逻辑
要还原音频,就得把上面的步骤倒过来,下面是修改后的完整convertPngToWav.py代码:
from PIL import Image import wave, struct, sys, soundfile as Sndfile, numpy as np, math ## # 输入校验 ## if sys.argv[1][-4:] != '.png': sys.exit("First argument should be a .png file") if sys.argv[2][-4:] != '.wav': sys.exit("Second argument should be a .wav file") ## # 转换过程 ## # 打开图片 with Image.open(sys.argv[1]) as pngFile: # 加载像素数据 pngAllPixels = pngFile.load() # 存储音频采样的数组 bitArray = list() # 按行优先遍历所有像素 for y in range(pngFile.size[1]): for x in range(pngFile.size[0]): r, g, b = pngAllPixels[x, y] # 跳过填充的黑色像素(转PNG时补的无效帧) if r == 0 and g == 0 and b == 0: continue # 步骤1:逆左移操作,把8位RGB转回5位分量 r5 = r >> 3 g5 = g >> 3 b5 = b >> 3 # 步骤2:把3个5位分量重组回0~65535的convertedData # B是高5位左移10位,G是中间5位左移5位,R是低5位直接保留 convertedData = (b5 << 10) | (g5 << 5) | r5 # 步骤3:转回原始的16位音频值(-32768 ~ 32767) singleBit = convertedData - 32768 # 添加到音频数组 bitArray.append(singleBit) # 转成numpy数组,符合音频格式要求 bitArrayNp = np.array(bitArray, dtype=np.int16) # 输出WAV文件(这里默认用44100采样率,如果你要和原文件一致,最好把采样率存在PNG元数据或文件名里) Sndfile.write(sys.argv[2], bitArrayNp, 44100, 'PCM_16')
关键修改点说明
- 像素遍历:改成按行优先遍历,和转PNG时的顺序对齐(不过因为你排序了像素,音频顺序还是乱的)
- 逆移位:把每个RGB分量右移3位,恢复成原来的5位数值
- 重组数值:把B(高5位)、G(中5位)、R(低5位)组合回原来的
convertedData - 跳过无效像素:忽略转PNG时填充的黑色像素
关于移位修改的疑问
如果你打算把转PNG代码里的x<<3改成x<<2,那还原时只需要把逆操作改成r>>2、g>>2、b>>2就行,其他逻辑不变。x<<2会把5位数值(031)变成0124,依然在0~255范围内,是可行的。
再次提醒:排序导致的顺序丢失
如果你的目标是还原出和原WAV完全一样的音频,必须解决顺序问题:要么去掉转PNG代码里的sorted(),保持原始帧顺序;要么在转PNG时把排序的索引存到额外文件里,还原时用索引把音频值恢复成原来的顺序。
内容的提问来源于stack exchange,提问作者Jerry Worger
相关产品推荐
相关产品推荐

