Python實(shí)現(xiàn)音頻添加數(shù)字水印的示例詳解
數(shù)字水印技術(shù)可以將隱藏信息嵌入到音頻文件中而不明顯影響音頻質(zhì)量。下面我將介紹幾種在Python中實(shí)現(xiàn)音頻數(shù)字水印的方法。
方法一: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) # 確保是立體聲,如果是單聲道則轉(zhuǎn)換為立體聲 if len(audio_data.shape) == 1: audio_data = np.column_stack((audio_data, audio_data)) # 將水印轉(zhuǎn)換為二進(jìn)制 watermark_bin = ''.join(format(ord(c), '08b') for c in watermark) watermark_bin += '00000000' # 添加結(jié)束標(biāo)記 # 檢查水印是否適合音頻 if len(watermark_bin) > audio_data.size: raise ValueError("水印太大,無(wú)法嵌入到音頻中") # 嵌入水印到最低有效位 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)) # 將比特轉(zhuǎn)換為字節(jié) watermark = '' for i in range(0, len(watermark_bits), 8): byte = ''.join(watermark_bits[i:i+8]) if byte == '00000000': # 遇到結(jié)束標(biāo)記 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) # 如果是立體聲,只使用一個(gè)聲道 if len(audio_data.shape) > 1: audio_data = audio_data[:, 0] # 將水印轉(zhuǎn)換為二進(jìn)制 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("音頻太短,無(wú)法嵌入水印") # 嵌入水印 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') # 修改中頻系數(shù)嵌入水印 coeff_index = 100 # 選擇一個(gè)中頻系數(shù) 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) # 如果是立體聲,只使用一個(gè)聲道 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') # 將比特轉(zhuǎn)換為字符串 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)
方法三:擴(kuò)頻水印
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) # 如果是立體聲,只使用一個(gè)聲道 if len(audio_data.shape) > 1: audio_data = audio_data[:, 0] # 將水印轉(zhuǎn)換為二進(jìn)制 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 # 轉(zhuǎn)換為±1 # 生成偽隨機(jī)序列 pn_length = len(audio_data) // len(watermark_bits) pn_sequence = generate_pn_sequence(pn_length) # 創(chuàng)建擴(kuò)頻水印 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位范圍內(nèi) # 保存帶水印的音頻 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) # 如果是立體聲,只使用一個(gè)聲道 if len(watermarked.shape) > 1: watermarked = watermarked[:, 0] original = original[:, 0] # 計(jì)算差異 diff = watermarked - original # 生成相同的偽隨機(jī)序列 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') # 將比特轉(zhuǎn)換為字符串 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)
注意事項(xiàng)
1. **音頻質(zhì)量**:水印嵌入會(huì)影響音頻質(zhì)量,需要平衡水印強(qiáng)度和音頻質(zhì)量。
2. **魯棒性**:不同方法對(duì)音頻處理的抵抗能力不同:
- LSB方法脆弱但容量大
- DCT方法對(duì)壓縮有一定抵抗能力
- 擴(kuò)頻方法魯棒性最強(qiáng)但容量小
3. **安全性**:可以考慮加密水印內(nèi)容提高安全性
4. **格式支持**:示例中使用WAV格式,因其是無(wú)損格式,其他格式可能需要先解碼
擴(kuò)展建議
1. 添加錯(cuò)誤校正碼提高水印提取的可靠性
2. 實(shí)現(xiàn)盲水印提?。ú恍枰家纛l)
3. 添加同步信號(hào)提高對(duì)裁剪、時(shí)間拉伸的抵抗能力
4. 結(jié)合多種技術(shù)提高水印的魯棒性和隱蔽
這些方法可以根據(jù)具體需求進(jìn)行調(diào)整和組合,以實(shí)現(xiàn)不同場(chǎng)景下的音頻數(shù)字水印需求。
以上就是Python實(shí)現(xiàn)音頻添加數(shù)字水印的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Python音頻添加數(shù)字水印的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python報(bào)錯(cuò)TypeError: ‘NoneType‘ object is not subscriptable的解決
這篇文章主要給大家介紹了關(guān)于python報(bào)錯(cuò)TypeError: ‘NoneType‘ object is not subscriptable的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11淺談Python訪問(wèn)MySQL的正確姿勢(shì)
這篇文章主要介紹了淺談Python訪問(wèn)MySQL的正確姿勢(shì),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Java ExcutorService優(yōu)雅關(guān)閉方式解析
這篇文章主要介紹了Java ExcutorService優(yōu)雅關(guān)閉方式解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05python 實(shí)現(xiàn)查詢Neo4j多節(jié)點(diǎn)的多層關(guān)系
今天小編就為大家分享一篇python 實(shí)現(xiàn)查詢Neo4j多節(jié)點(diǎn)的多層關(guān)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12Python數(shù)據(jù)可視化實(shí)現(xiàn)多種圖例代碼詳解
這篇文章主要介紹了Python數(shù)據(jù)可視化實(shí)現(xiàn)多種圖例代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07python實(shí)現(xiàn)將Excel文件轉(zhuǎn)換為JSON文件
在數(shù)據(jù)處理和分析中,Excel和JSON是兩種常見(jiàn)的數(shù)據(jù)格式,本文將詳細(xì)介紹如何使用Python將Excel文件轉(zhuǎn)換為JSON文件,我們將使用pandas庫(kù),這是一個(gè)強(qiáng)大的數(shù)據(jù)分析工具,能夠方便地讀取和處理各種數(shù)據(jù)格式,需要的朋友可以參考下2024-07-07Django 開(kāi)發(fā)環(huán)境配置過(guò)程詳解
這篇文章主要介紹了Django 開(kāi)發(fā)環(huán)境配置過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07