You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于LSB算法的图像嵌入视频及解密的Python实现技术问询

Hey there! Let's work through implementing your LSB steganography plan for embedding an image into a video, plus the corresponding extraction method to retrieve the hidden image. First, let's fix some bugs in your existing code, then walk through the full implementation step by step.

1. Fixes for Your Current Code

Your existing code has a few issues that need addressing before moving forward:

  • Incorrect pixel indexing: In the video processing loop, for i in all_pixels: uses all_pixels[i] which is wrong—i is the pixel value (0-255), not an index. Use enumerate() to get both index and value.
  • Image pixel loop error: The image pixel loop for m in range(width): for n in range(3) only iterates over the first width pixels, not all pixels in the image. You need to loop through every pixel's RGB components.
  • Color space mismatch: OpenCV reads video frames in BGR format, while PIL reads images in RGB. We'll standardize to BGR to avoid color shifts.

2. LSB Embedding: Hide Image in Video

Here's how to implement your plan: replace the last 3 bits of each video frame's BGR component with the last 3 bits of the corresponding image's BGR component. We'll process frames sequentially until all image pixels are embedded, then leave remaining frames unchanged.

Key Notes:

  • Ensure the video has enough total pixels (frames × width × height × 3) to fit the image's total pixels (image_width × image_height × 3). If not, the image will be truncated.
  • We'll write the modified frames to a new video file (using cv.VideoWriter).

Full Embedding Code

import numpy as np
import cv2 as cv
from PIL import Image

def embed_image_in_video(video_path, image_path, output_video_path):
    # Load video
    vidcap = cv.VideoCapture(video_path)
    if not vidcap.isOpened():
        print("Error: Could not open video.")
        return
    
    # Get video properties
    fps = vidcap.get(cv.CAP_PROP_FPS)
    frame_width = int(vidcap.get(cv.CAP_PROP_FRAME_WIDTH))
    frame_height = int(vidcap.get(cv.CAP_PROP_FRAME_HEIGHT))
    total_frames = int(vidcap.get(cv.CAP_PROP_FRAME_COUNT))
    
    # Load image and convert to BGR (match OpenCV's format)
    img = Image.open(image_path).convert("RGB")
    img = cv.cvtColor(np.array(img), cv.COLOR_RGB2BGR)
    img_height, img_width = img.shape[:2]
    total_image_pixels = img_width * img_height * 3
    
    # Check if video has enough space
    total_video_pixels = total_frames * frame_width * frame_height * 3
    if total_image_pixels > total_video_pixels:
        print("Error: Video does not have enough pixels to fit the image.")
        vidcap.release()
        return
    
    # Initialize video writer
    fourcc = cv.VideoWriter_fourcc(*'mp4v')
    out = cv.VideoWriter(output_video_path, fourcc, fps, (frame_width, frame_height))
    
    # Flatten image pixels into a 1D array of BGR components
    flat_image = img.flatten()
    img_idx = 0  # Track which image pixel we're embedding
    
    while True:
        ret, frame = vidcap.read()
        if not ret:
            break
        
        # Flatten frame pixels
        flat_frame = frame.flatten()
        
        # Embed image pixels into frame
        for i in range(len(flat_frame)):
            if img_idx >= total_image_pixels:
                break  # Stop once all image pixels are embedded
            
            # Get video pixel's 8-bit binary, keep first 5 bits (mask with 0b11111000)
            video_pixel = flat_frame[i]
            video_high_bits = video_pixel & 0b11111000
            
            # Get image pixel's last 3 bits (mask with 0b00000111)
            image_pixel = flat_image[img_idx]
            image_low_bits = image_pixel & 0b00000111
            
            # Replace video pixel's last 3 bits with image's last 3 bits
            flat_frame[i] = video_high_bits | image_low_bits
            img_idx += 1
        
        # Reshape back to frame and write to output
        modified_frame = flat_frame.reshape(frame_height, frame_width, 3)
        out.write(modified_frame)
        
        # Optional: Display frame for debugging
        cv.imshow('Embedding', modified_frame)
        if cv.waitKey(1) == ord('q'):
            break
    
    # Cleanup
    vidcap.release()
    out.release()
    cv.destroyAllWindows()
    print(f"Image embedded successfully! Output saved to {output_video_path}")

# Run the embedding function
embed_image_in_video("video.mp4", "kiwi.jpg", "stego_video.mp4")

3. LSB Extraction: Retrieve Image from Steganographed Video

To get the hidden image back, we'll extract the last 3 bits from each video frame's BGR component, scale those bits to full 8-bit values (to make the image visible), and reconstruct the original image shape.

Full Extraction Code

import numpy as np
import cv2 as cv
from PIL import Image

def extract_image_from_video(stego_video_path, output_image_path, img_width, img_height):
    # Load steganographed video
    vidcap = cv.VideoCapture(stego_video_path)
    if not vidcap.isOpened():
        print("Error: Could not open steganographed video.")
        return
    
    total_image_pixels = img_width * img_height * 3
    extracted_pixels = []
    pixel_count = 0
    
    while True:
        ret, frame = vidcap.read()
        if not ret or pixel_count >= total_image_pixels:
            break
        
        # Flatten frame pixels
        flat_frame = frame.flatten()
        
        # Extract last 3 bits from each video pixel
        for pixel in flat_frame:
            if pixel_count >= total_image_pixels:
                break
            # Get last 3 bits and scale to full 8-bit range (0-255)
            extracted_low_bits = pixel & 0b00000111
            # Scale 0-7 to 0-252 (closest to full range without exceeding 255)
            full_range_pixel = extracted_low_bits * 36
            extracted_pixels.append(full_range_pixel)
            pixel_count += 1
    
    # Reshape into image (BGR format)
    extracted_image = np.array(extracted_pixels).reshape(img_height, img_width, 3)
    # Convert to RGB for PIL to save correctly
    extracted_image = cv.cvtColor(extracted_image, cv.COLOR_BGR2RGB)
    Image.fromarray(extracted_image).save(output_image_path)
    
    # Cleanup
    vidcap.release()
    cv.destroyAllWindows()
    print(f"Image extracted successfully! Output saved to {output_image_path}")

# Run the extraction function (you need to know the original image's width and height)
extract_image_from_video("stego_video.mp4", "extracted_kiwi.jpg", img_width=500, img_height=500)

Important Notes

  • Image Dimensions: When extracting, you need to know the original image's width and height. For automation, you could embed this metadata in the first few pixels of the video.
  • Quality: Since we're only using the last 3 bits of each pixel, the extracted image will lose some detail. If you want higher quality, use fewer bits per pixel (e.g., 1 bit) but this requires more video pixels to store the full image.
  • Video Format: Ensure the output video codec (fourcc) is compatible with your system—mp4v works for most cases.

内容的提问来源于stack exchange,提问作者Heeya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:57:32