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_data[i])):

            if watermark_index < len(watermark_bin):

                # 替换最低有效位

                audio_data[i][j] = (audio_data[i][j] & 0xFE) | int(watermark_bin[watermark_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_data[i])):

            watermark_bits.append(str(audio_data[i][j] & 1))   

    # 将比特转换为字节

    watermark = ''

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

        byte = ''.join(watermark_bits[i: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_data[start:end]

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

        # 修改中频系数嵌入水印

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

        if watermark_bin[i] == 1:

            dct_coeffs[coeff_index] += alpha * np.abs(dct_coeffs[coeff_index])

        else:

            dct_coeffs[coeff_index] -= alpha * np.abs(dct_coeffs[coeff_index])      

        # 逆DCT变换

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

        watermarked_audio[start: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 = watermarked[start:end]

        orig_segment = original[start:end]        

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

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

        coeff_index = 100

        if wm_dct[coeff_index] > orig_dct[coeff_index]:

            watermark_bits.append('1')

        else:

            watermark_bits.append('0')    

    # 将比特转换为字符串

    watermark = ''

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

        byte = ''.join(watermark_bits[i: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 = diff[start: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_bits[i: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方法对压缩有一定抵抗能力

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

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

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

 扩展建议

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/74079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Altium Designer 24 PCB 走线倒圆弧方法

Altium Designer 24 PCB 走线倒圆弧方法 问题描述解决方法设置倒圆弧参数选择需要优化的走线进行走线优化 优化效果展示 在 PCB 设计中&#xff0c;走线转角过于尖锐不仅影响美观&#xff0c;还可能引起信号完整性问题。本文介绍如何在 Altium Designer 24 中通过倒圆弧优化走线…

Cookie与Token详解及测试需重点关注点

在现代Web应用中&#xff0c;Cookie 和 Token 是两种常见的身份验证与会话管理机制。它们分别在不同的场景下扮演着重要的角色&#xff0c;在性能、灵活性和安全性方面具有各自的特点。作为测试人员&#xff0c;理解它们的工作原理以及如何对其进行有效的测试&#xff0c;是保证…

Unity 2022.3.x部分Android设备播放视频黑屏问题

Android平台视频兼容性问题很多…类似的黑屏问题真的很头大&#xff0c;总结一些常见问题&#xff1a; 1. 视频文件不支持压缩 如果使用AssetBundle加载视频&#xff0c;这个AssetBundle压缩格式要选None。有人可能会说最新版Unity已经支持bundle压缩下播放视频&#xff0c;稳…

Redis - 概述

目录 ​编辑 一、什么是redis 二、redis能做什么&#xff08;有什么特点&#xff09;&#xff1f; 三、redis有什么优势 四、Redis与其他key-value存储有什么不同 五、Redis命令 六、Redis数据结构 1、基础数据结构 2、高级数据结构 一、什么是redis 1、redis&#x…

数据库部署在服务器表不存在解决方案

MySQL 数据库表不存在错误解决方案 MySqlException (0x80004005): Table store.SysLogOperate doesnt exist 服务器用的mysql5.6 用这个表syslogoperate只是全是小写 看起来你在使用 Pomelo.EntityFrameworkCore.MySql 作为 MySQL 数据库的提供程序&#xff0c;并且在初始化…

图灵完备——游戏中进行实践

图灵完备 简述结构一、基本逻辑电路1、低电平2、高电平3、非门4、与门5、三路与门6、或门7、三路或门8、与非门9、或非门10、异或门11、同或门 二、算数运算&&存储器1、二进制速算2、成对的麻烦 简述 这周就要学习计算机组成原理了&#xff0c;为了学起来不那么吃力&am…

踏过强化学习的每一步推导

给定 l [ a n , . . . , a 0 ] l[a_n, ..., a_0] l[an​,...,a0​]&#xff0c;现在 for idx in range(len(l)-2, -1, -1):l[idx] l[idx1] * ld注&#xff1a;这里的ld就是 λ \lambda λ&#xff0c;定义 λ 0 1 \lambda^01 λ01 证明变换后&#xff1a; l [ ∑ i 0 n …

AI小白的第七天:必要的数学知识(概率)

概率 Probability 1. 概率的定义 概率是一个介于 0 和 1 之间的数&#xff0c;表示某个事件发生的可能性&#xff1a; 0&#xff1a;事件不可能发生。1&#xff1a;事件必然发生。0 到 1 之间&#xff1a;事件发生的可能性大小。 例如&#xff0c;掷一枚公平的硬币&#xf…

UE5 + Rider + VsCode 接入腾讯的 Puerts 脚本

学习了一段时间 U&#xff0c;写点啥就得等编译&#xff0c;体验真的是一言难尽。。。。。。 然后就想着给自己找个脚本好了&#xff0c;调研了一下 AngelScript&#xff0c;puerts 的可行性。 AngelScript 看着真的诱人&#xff0c;但是发现连官方提供的都是 UE 的预编译版本…

凸包构造算法—Graham 扫描法

1. 理论原理推导 核心思想 Graham 扫描法基于以下基本思想&#xff1a; 极角排序&#xff1a; 选取一个参考点&#xff08;通常选择 y 坐标最小的点&#xff0c;若存在多个&#xff0c;则选 x 坐标最小的&#xff09;&#xff0c;将其他点按照与该参考点构成的极角进行升序排…

如何在 Windows 上安装与配置 Tomcat

Apache Tomcat 是一个开源的 Servlet 容器和 Web 服务器&#xff0c;广泛用于 Java Web 应用的开发和部署。它是实现 Java EE&#xff08;现称 Jakarta EE&#xff09;规范中的 Servlet 和 JSP 的官方参考实现。在本文中&#xff0c;我们将详细介绍如何在 Windows 系统上安装并…

测试模版15

本篇技术博文摘要 &#x1f31f; 引言 &#x1f4d8; 在这个变幻莫测、快速发展的技术时代&#xff0c;与时俱进是每个IT工程师的必修课。我是盛透侧视攻城狮&#xff0c;一名什么都会一丢丢的网络安全工程师&#xff0c;也是众多技术社区的活跃成员以及多家大厂官方认可人员&a…

拦截、限流,针对场景详细信息(一)

以下是一个基于Java Spring Boot Redis 的完整限流实现案例&#xff0c;针对同一接口前缀&#xff08;如 /one/ &#xff09;的IP访问频率控制&#xff1a; 场景&#xff1a;用户不用登录即可访问接口&#xff0c;网站会有被攻击的风险 URL&#xff1a;one/two/three one/…

计算机视觉算法实战——烟雾检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 1. 烟雾检测领域介绍 烟雾检测是计算机视觉在公共安全领域的重要应用&#xff0c;它通过分析视频或图像序…

MySQL-DCL函数

DCL DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 管理用户 1). 查询用户 use mysql; select * from user; select * from mysql.user; 查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localhost, 仅…

linux 服务器创建服务器启动后服务自启动

1、在/etc/systemd/system/下touch一个文件&#xff1a; touch /etc/systemd/system/your_application.service 2、在文件中写入&#xff1a; [Unit] Descriptionmodules-system Aftersyslog.target[Service] Typeforking Userroot Grouproot ExecStart/bin/bash /usr/loca…

端到端语音识别案例

《DeepSeek大模型高性能核心技术与多模态融合开发&#xff08;人工智能技术丛书&#xff09;》(王晓华)【摘要 书评 试读】- 京东图书 语音识别这一技术正如其名&#xff0c;是通过精密地解析说话人的语音来识别并准确转写出其所说的内容。它不仅仅是一个简单的转录过程&#…

QT——信号和槽

QT是图形化界面&#xff0c;自然是需要与用户进行交互的&#xff0c;但是该如何实现用户与界面或者程序的交互呢。答案是通过信号和槽。 一&#xff0c;什么是信号和槽&#xff1f; 在Linux操作系统里面&#xff0c;我们知道信号是由硬件或者软件产生&#xff0c;但是在QT里面…

Q:如何保证备份的有效性以及备份频率设置的优化方案?

1、如何保障备份数据的一致性 a) 快照 快照通过捕获数据在某一时刻的完整状态来保障备份一致性。在应用层&#xff0c;快照会暂停业务写入或生成事务一致性检查点&#xff08;如数据库的全局读视图&#xff09;&#xff0c;确保备份数据不包含未提交的事务&#xff1b;在存…

Linux实用操作及命令

一、各类小技巧&#xff08;快捷键&#xff09; 1、强制停止&#xff08;ctrlc&#xff09; Linux某些程序的运行&#xff0c;如果想要强制停止它&#xff0c;可以使用快捷键ctrl c 命令输入错误&#xff0c;也可以通过快捷键ctrl c&#xff0c;退出当前输入&#xff0c;重…