SoFunction
Updated on 2025-04-14

Detailed explanation of the example of adding digital watermarks for Python audio

Digital watermarking technology can embed hidden information into audio files without significantly affecting audio quality. Below I will introduce several methods to implement digital watermarking of audio in Python.

Method 1: LSB (lowest significant bit) watermark

import numpy as np
from  import wavfile
def embed_watermark_lsb(audio_path, watermark, output_path):
    # Read audio files    sample_rate, audio_data = (audio_path)    
    # Make sure it is stereo, if it is mono, it will be converted to stereo    if len(audio_data.shape) == 1:
        audio_data = np.column_stack((audio_data, audio_data))   
    # Convert watermark to binary    watermark_bin = ''.join(format(ord(c), '08b') for c in watermark)
    watermark_bin += '00000000' # Add an end tag    # Check whether the watermark is suitable for the audio    if len(watermark_bin) > audio_data.size:
        raise ValueError("The watermark is too big to be embedded in the audio")  
    # Embed the watermark to the lowest significant bit    watermark_index = 0
    for i in range(len(audio_data)):
        for j in range(len(audio_data[i])):
            if watermark_index < len(watermark_bin):
                # Replace the least significant bit                audio_data[i][j] = (audio_data[i][j] & 0xFE) | int(watermark_bin[watermark_index])
                watermark_index += 1
            else:
                break   
    # Save audio with watermark    (output_path, sample_rate, audio_data)
def extract_watermark_lsb(audio_path, watermark_length):
    # Read audio files    sample_rate, audio_data = (audio_path)    
    # Extract the least significant bit    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))   
    # Convert bits to bytes    watermark = ''
    for i in range(0, len(watermark_bits), 8):
        byte = ''.join(watermark_bits[i:i+8])
        if byte == '00000000': # End tag encountered            break
        watermark += chr(int(byte, 2))   
    return watermark[:watermark_length]
#User Exampleembed_watermark_lsb('', 'Secret news', '')
extracted = extract_watermark_lsb('', 4)
print("Extracted watermark:", extracted)

Method 2: Frequency Domain Watermark (DCT Transformation)

import numpy as np
from  import dct, idct
from  import wavfile
def embed_watermark_dct(audio_path, watermark, output_path, alpha=0.01):
    # Read audio    sample_rate, audio_data = (audio_path)  
    # If it is stereo, use only one channel    if len(audio_data.shape) > 1:
        audio_data = audio_data[:, 0]   
    # Convert watermark to binary    watermark_bin = ''.join(format(ord(c), '08b') for c in watermark)
    watermark_bin = [int(b) for b in watermark_bin]    
    # Segmented audio processing    segment_size = 1024
    num_segments = len(audio_data) // segment_size
    watermark_length = len(watermark_bin)   
    if num_segments < watermark_length:
        raise ValueError("The audio is too short to embed the watermark")   
    # Embed watermark    watermarked_audio = (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')       
        # Modify the IF coefficient to embed the watermark        coeff_index = 100 # Select an intermediate frequency coefficient        if watermark_bin[i] == 1:
            dct_coeffs[coeff_index] += alpha * (dct_coeffs[coeff_index])
        else:
            dct_coeffs[coeff_index] -= alpha * (dct_coeffs[coeff_index])      
        # Inverse DCT Transformation        watermarked_segment = idct(dct_coeffs, norm='ortho')
        watermarked_audio[start:end] = watermarked_segment   
    # Save audio with watermark    (output_path, sample_rate, watermarked_audio.astype(np.int16))
def extract_watermark_dct(audio_path, original_path, watermark_length):
    # Read watermarked audio and original audio    sample_rate, watermarked = (audio_path)
    _, original = (original_path)    
    # If it is stereo, use only one channel    if len() > 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')    
    # Convert bits to string    watermark = ''
    for i in range(0, len(watermark_bits), 8):
        byte = ''.join(watermark_bits[i:i+8])
        watermark += chr(int(byte, 2))  
    return watermark
#User Exampleembed_watermark_dct('', 'secret', 'watermarked_dct.wav', 0.02)
extracted = extract_watermark_dct('watermarked_dct.wav', '', 16)
print("Extracted watermark:", extracted)

Method 3: Spread spectrum watermark

import numpy as np
from  import wavfile
def generate_pn_sequence(length, seed=42):
    (seed)
    return ([-1, 1], size=length)
def embed_watermark_spread_spectrum(audio_path, watermark, output_path, alpha=0.01):
    # Read audio    sample_rate, audio_data = (audio_path)    
    # If it is stereo, use only one channel    if len(audio_data.shape) > 1:
        audio_data = audio_data[:, 0]    
    # Convert watermark to binary    watermark_bin = ''.join(format(ord(c), '08b') for c in watermark)
    watermark_bits = ([int(b) for b in watermark_bin])
    watermark_bits = 2 * watermark_bits - 1 # Convert to ±1    # Generate pseudo-random sequences    pn_length = len(audio_data) // len(watermark_bits)
    pn_sequence = generate_pn_sequence(pn_length)   
    # Create a spread spectrum watermark    spread_watermark = (watermark_bits, pn_length)
    spread_watermark = spread_watermark[:len(audio_data)] * pn_sequence[:len(audio_data)]   
    # Embed watermark    watermarked_audio = audio_data + alpha * spread_watermark * (audio_data)
    watermarked_audio = (watermarked_audio, -32768, 32767) # Make sure to be in the 16-bit range    # Save audio with watermark    (output_path, sample_rate, watermarked_audio.astype(np.int16))
def extract_watermark_spread_spectrum(audio_path, original_path, watermark_length, pn_length):
    # Read audio    sample_rate, watermarked = (audio_path)
    _, original = (original_path)   
    # If it is stereo, use only one channel    if len() > 1:
        watermarked = watermarked[:, 0]
        original = original[:, 0]    
    # Calculate the difference    diff = watermarked - original   
    # Generate the same pseudo-random sequence    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 = (segment_diff * segment_pn)
        extracted_bits.append('1' if correlation > 0 else '0')    
    # Convert bits to string    watermark = ''
    for i in range(0, len(extracted_bits), 8):
        byte = ''.join(extracted_bits[i:i+8])
        watermark += chr(int(byte, 2))    
    return watermark
#User Exampleembed_watermark_spread_spectrum('', 'secret', 'watermarked_ss.wav', 0.01)
extracted = extract_watermark_spread_spectrum('watermarked_ss.wav', '', 2, 1000)
print("Extracted watermark:", extracted)

Things to note

1. **Audio Quality**: Watermark embedding will affect the audio quality and need to balance the watermark intensity and audio quality.

2. **Roominess**: Different methods have different resistance to audio processing:

- LSB method is fragile but has a large capacity

- DCT method has certain resistance to compression

- Spread spectrum method has the strongest robustness but small capacity

3. **Security**: You can consider encrypting watermark content to improve security

4. **Format support**: The WAV format is used in the example, because it is a lossless format, other formats may need to be decoded first.

Extension suggestions

1. Add error correction code to improve the reliability of watermark extraction

2. Implement blind watermark extraction (no original audio required)

3. Add synchronization signals to improve resistance to cropping and time stretching

4. Combining multiple technologies to improve the robustness and concealment of watermarks

These methods can be adjusted and combined according to specific needs to achieve audio digital watermarking requirements in different scenarios.

The above is a detailed explanation of the example of adding digital watermarks for Python audio. For more information about adding digital watermarks for Python audio, please pay attention to my other related articles!