Python实现音频数字水印方法

数字水印技术可以将隐藏信息嵌入到音频文件中而不明显影响音频质量。下面我将介绍几种在Python中实现音频数字水印的方法。

方法一:LSB (最低有效位) 水印

import numpy as np

from scipy.io import wavfile

def embed_watermark_lsb(audio_path, watermark, output_path):

读取音频文件

sample_rate, audio_data = wavfile.read(audio_path)

确保是立体声,如果是单声道则转换为立体声

if len(audio_data.shape) == 1:

audio_data = np.column_stack((audio_data, audio_data))

将水印转换为二进制

watermark_bin = ''.join(format(ord(c), '08b') for c in watermark)

watermark_bin += '00000000' # 添加结束标记

检查水印是否适合音频

if len(watermark_bin) > audio_data.size:

raise ValueError("水印太大,无法嵌入到音频中")

嵌入水印到最低有效位

watermark_index = 0

for i in range(len(audio_data)):

for j in range(len(audio_datai)):

if watermark_index < len(watermark_bin):

替换最低有效位

audio_dataij = (audio_dataij & 0xFE) | int(watermark_binwatermark_index)

watermark_index += 1

else:

break

保存带水印的音频

wavfile.write(output_path, sample_rate, audio_data)

def extract_watermark_lsb(audio_path, watermark_length):

读取音频文件

sample_rate, audio_data = wavfile.read(audio_path)

提取最低有效位

watermark_bits = \[\]

for i in range(len(audio_data)):

for j in range(len(audio_datai)):

watermark_bits.append(str(audio_dataij & 1))

将比特转换为字节

watermark = ''

for i in range(0, len(watermark_bits), 8):

byte = ''.join(watermark_bitsi:i+8)

if byte == '00000000': # 遇到结束标记

break

watermark += chr(int(byte, 2))

return watermark:watermark_length

使用示例

embed_watermark_lsb('original.wav', '秘密消息', 'watermarked.wav')

extracted = extract_watermark_lsb('watermarked.wav', 4)

print("提取的水印:", extracted)

方法二:频域水印 (DCT变换)

import numpy as np

from scipy.fftpack import dct, idct

from scipy.io import wavfile

def embed_watermark_dct(audio_path, watermark, output_path, alpha=0.01):

读取音频

sample_rate, audio_data = wavfile.read(audio_path)

如果是立体声,只使用一个声道

if len(audio_data.shape) > 1:

audio_data = audio_data:, 0

将水印转换为二进制

watermark_bin = ''.join(format(ord(c), '08b') for c in watermark)

watermark_bin = int(b) for b in watermark_bin

分段处理音频

segment_size = 1024

num_segments = len(audio_data) // segment_size

watermark_length = len(watermark_bin)

if num_segments < watermark_length:

raise ValueError("音频太短,无法嵌入水印")

嵌入水印

watermarked_audio = np.copy(audio_data)

for i in range(watermark_length):

start = i * segment_size

end = start + segment_size

segment = audio_datastart:end

dct_coeffs = dct(segment, norm='ortho')

修改中频系数嵌入水印

coeff_index = 100 # 选择一个中频系数

if watermark_bini == 1:

dct_coeffscoeff_index += alpha * np.abs(dct_coeffscoeff_index)

else:

dct_coeffscoeff_index -= alpha * np.abs(dct_coeffscoeff_index)

逆DCT变换

watermarked_segment = idct(dct_coeffs, norm='ortho')

watermarked_audiostart:end = watermarked_segment

保存带水印的音频

wavfile.write(output_path, sample_rate, watermarked_audio.astype(np.int16))

def extract_watermark_dct(audio_path, original_path, watermark_length):

读取带水印音频和原始音频

sample_rate, watermarked = wavfile.read(audio_path)

_, original = wavfile.read(original_path)

如果是立体声,只使用一个声道

if len(watermarked.shape) > 1:

watermarked = watermarked:, 0

original = original:, 0

segment_size = 1024

watermark_bits = \[\]

for i in range(watermark_length):

start = i * segment_size

end = start + segment_size

wm_segment = watermarkedstart:end

orig_segment = originalstart:end

wm_dct = dct(wm_segment, norm='ortho')

orig_dct = dct(orig_segment, norm='ortho')

coeff_index = 100

if wm_dctcoeff_index > orig_dctcoeff_index:

watermark_bits.append('1')

else:

watermark_bits.append('0')

将比特转换为字符串

watermark = ''

for i in range(0, len(watermark_bits), 8):

byte = ''.join(watermark_bitsi:i+8)

watermark += chr(int(byte, 2))

return watermark

使用示例

embed_watermark_dct('original.wav', '秘密', 'watermarked_dct.wav', 0.02)

extracted = extract_watermark_dct('watermarked_dct.wav', 'original.wav', 16)

print("提取的水印:", extracted)

方法三:扩频水印

import numpy as np

from scipy.io import wavfile

def generate_pn_sequence(length, seed=42):

np.random.seed(seed)

return np.random.choice(-1, 1, size=length)

def embed_watermark_spread_spectrum(audio_path, watermark, output_path, alpha=0.01):

读取音频

sample_rate, audio_data = wavfile.read(audio_path)

如果是立体声,只使用一个声道

if len(audio_data.shape) > 1:

audio_data = audio_data:, 0

将水印转换为二进制

watermark_bin = ''.join(format(ord(c), '08b') for c in watermark)

watermark_bits = np.array(int(b) for b in watermark_bin)

watermark_bits = 2 * watermark_bits - 1 # 转换为±1

生成伪随机序列

pn_length = len(audio_data) // len(watermark_bits)

pn_sequence = generate_pn_sequence(pn_length)

创建扩频水印

spread_watermark = np.repeat(watermark_bits, pn_length)

spread_watermark = spread_watermark:len(audio_data) * pn_sequence:len(audio_data)

嵌入水印

watermarked_audio = audio_data + alpha * spread_watermark * np.abs(audio_data)

watermarked_audio = np.clip(watermarked_audio, -32768, 32767) # 确保在16位范围内

保存带水印的音频

wavfile.write(output_path, sample_rate, watermarked_audio.astype(np.int16))

def extract_watermark_spread_spectrum(audio_path, original_path, watermark_length, pn_length):

读取音频

sample_rate, watermarked = wavfile.read(audio_path)

_, original = wavfile.read(original_path)

如果是立体声,只使用一个声道

if len(watermarked.shape) > 1:

watermarked = watermarked:, 0

original = original:, 0

计算差异

diff = watermarked - original

生成相同的伪随机序列

num_bits = watermark_length * 8

pn_sequence = generate_pn_sequence(pn_length)

extracted_bits = \[\]

for i in range(num_bits):

start = i * pn_length

end = start + pn_length

segment_diff = diffstart:end

segment_pn = pn_sequence:len(segment_diff)

correlation = np.sum(segment_diff * segment_pn)

extracted_bits.append('1' if correlation > 0 else '0')

将比特转换为字符串

watermark = ''

for i in range(0, len(extracted_bits), 8):

byte = ''.join(extracted_bitsi:i+8)

watermark += chr(int(byte, 2))

return watermark

使用示例

embed_watermark_spread_spectrum('original.wav', '秘密', 'watermarked_ss.wav', 0.01)

extracted = extract_watermark_spread_spectrum('watermarked_ss.wav', 'original.wav', 2, 1000)

print("提取的水印:", extracted)

注意事项

  1. **音频质量**:水印嵌入会影响音频质量,需要平衡水印强度和音频质量。

  2. **鲁棒性**:不同方法对音频处理的抵抗能力不同:

  • LSB方法脆弱但容量大

  • DCT方法对压缩有一定抵抗能力

  • 扩频方法鲁棒性最强但容量小

  1. **安全性**:可以考虑加密水印内容提高安全性

  2. **格式支持**:示例中使用WAV格式,因其是无损格式,其他格式可能需要先解码

扩展建议

  1. 添加错误校正码提高水印提取的可靠性

  2. 实现盲水印提取(不需要原始音频)

  3. 添加同步信号提高对裁剪、时间拉伸的抵抗能力

  4. 结合多种技术提高水印的鲁棒性和隐蔽

这些方法可以根据具体需求进行调整和组合,以实现不同场景下的音频数字水印需求。

相关推荐
小江的记录本1 天前
【JVM虚拟机】垃圾回收GC:四种引用类型:强引用、软引用、弱引用、虚引用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
APIshop1 天前
Python 获取 1688 商品采集 API 接口 | 工厂货源自动化对接商品信息 | 无需选品
运维·python·自动化
deepin_sir1 天前
10 - 函数
开发语言·python
charlee441 天前
《GIS基础原理与技术实践》配套案例(Python版)
python·conda·numpy·gis·环境配置
枫叶林FYL1 天前
项目十:事件溯源仓储管理系统(WMS)仿真实现
开发语言·python
君为先-bey1 天前
CogVideoX——Transformer从文本到视频的扩散模型
深度学习·音视频·transformer·扩散模型
Raink老师1 天前
【AI面试临阵磨枪-77】音视频 + AI:实时字幕、翻译、降噪、虚拟人、多模态对话
人工智能·面试·音视频
FrameNotWork1 天前
HarmonyOS 短视频滑动交互实现:打造流畅的上下切换体验
音视频·交互·harmonyos
渣渣xiong1 天前
从零开始:前端转型AI agent直到就业第五十七天-第五十八天
前端·人工智能·python
小L~~~1 天前
基于贪心策略的混合遗传算法求解01背包问题
python·算法