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

基于Python与OpenCV的图像文本编码实现问询及检测代码说明

用Python + OpenCV实现图像文本编码(隐写)方案

嘿,既然你已经搞定了图像文本检测的代码,那咱们来聊聊怎么把文本直接编码进图像本身——也就是常说的图像隐写。这里我给你推荐用LSB(最低有效位)隐写方案,用OpenCV就能轻松实现,而且图像几乎看不出肉眼可见的变化。

核心原理

LSB隐写的思路特别简单:图像每个像素的RGB通道值都是8位二进制数,最低位的变化对图像亮度、色彩的影响极小,人眼完全察觉不到。我们可以把文本转换成二进制,逐个替换这些最低位,就把文本“藏”进图像里了。

实现步骤(附代码)

1. 文本嵌入(编码)函数

这个函数会把文本转成二进制,然后嵌入到图像的像素中:

import cv2
import numpy as np

def encode_text_to_image(image_path, text, output_path):
    # 读取图像,建议用PNG等无损格式,JPEG压缩会破坏隐写内容
    image = cv2.imread(image_path)
    if image is None:
        raise ValueError("无法读取目标图像文件")
    
    # 给文本加结束标记'\0',方便解码时识别文本边界
    text += '\0'
    # 把每个字符转成8位二进制字符串,拼接成完整的二进制文本
    binary_text = ''.join([format(ord(c), '08b') for c in text])
    text_length = len(binary_text)
    
    # 检查图像容量是否足够容纳文本
    total_available_bits = image.shape[0] * image.shape[1] * 3
    if text_length > total_available_bits:
        raise ValueError("文本太长啦,当前图像的容量不够装下它")
    
    # 遍历像素,逐个嵌入二进制文本位
    bit_index = 0
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            for channel in range(3):  # 遍历RGB三个通道
                if bit_index < text_length:
                    # 替换当前通道的最低位为文本的二进制位
                    current_pixel = format(image[i][j][channel], '08b')
                    new_pixel = current_pixel[:-1] + binary_text[bit_index]
                    image[i][j][channel] = int(new_pixel, 2)
                    bit_index += 1
                else:
                    # 文本嵌入完成,保存图像
                    cv2.imwrite(output_path, image)
                    return

2. 文本提取(解码)函数

如果需要把藏在图像里的文本取出来,用这个函数:

def decode_text_from_image(image_path):
    image = cv2.imread(image_path)
    if image is None:
        raise ValueError("无法读取目标图像文件")
    
    binary_text = ""
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            for channel in range(3):
                # 提取每个通道的最低位
                binary_text += format(image[i][j][channel], '08b')[-1]
                # 每凑够8位就转成字符,检查是否是结束标记'\0'
                if len(binary_text) % 8 == 0:
                    current_char = chr(int(binary_text[-8:], 2))
                    if current_char == '\0':
                        # 找到结束标记,返回去掉标记的文本
                        return ''.join([chr(int(binary_text[k:k+8], 2)) for k in range(0, len(binary_text)-8, 8)])
    
    # 如果没找到结束标记,返回所有能解码的文本
    return ''.join([chr(int(binary_text[k:k+8], 2)) for k in range(0, len(binary_text), 8)])

3. 和你的文本检测代码结合(可选)

如果你想只在检测到的文本区域附近嵌入文本,可以结合你现有的轮廓检测代码,只遍历轮廓对应的矩形区域内的像素:

# 复用你提供的检测代码,提取文本区域的矩形坐标
def get_text_regions(image_path):
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
    dilated = cv2.dilate(thresh, kernel, iterations=13)
    contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    
    # 返回所有文本区域的(x, y, 宽度, 高度)坐标
    text_regions = []
    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour)
        text_regions.append((x, y, w, h))
    return text_regions

# 修改嵌入函数,只在指定文本区域内嵌入
def encode_text_in_regions(image_path, text, regions, output_path):
    image = cv2.imread(image_path)
    text += '\0'
    binary_text = ''.join([format(ord(c), '08b') for c in text])
    text_length = len(binary_text)
    bit_index = 0
    
    for (x, y, w, h) in regions:
        if bit_index >= text_length:
            break
        # 遍历文本区域内的像素
        for i in range(y, y+h):
            for j in range(x, x+w):
                for channel in range(3):
                    if bit_index < text_length:
                        current_pixel = format(image[i][j][channel], '08b')
                        new_pixel = current_pixel[:-1] + binary_text[bit_index]
                        image[i][j][channel] = int(new_pixel, 2)
                        bit_index += 1
                    else:
                        cv2.imwrite(output_path, image)
                        return
    cv2.imwrite(output_path, image)

使用示例

# 基础用法:把文本嵌入整个图像
encode_text_to_image("sample.png", "这是我藏在图像里的小秘密!", "encoded_sample.png")

# 解码提取文本
hidden_text = decode_text_from_image("encoded_sample.png")
print("提取到的隐藏文本:", hidden_text)

# 进阶用法:只在检测到的文本区域嵌入文本
text_regions = get_text_regions("sample.png")
encode_text_in_regions("sample.png", "只在文本区域附近藏的内容", text_regions, "encoded_regions_sample.png")

注意事项

  • 优先使用PNG等无损图像格式,JPEG是有损压缩,会破坏嵌入的文本信息;
  • 嵌入的文本长度不能超过图像总像素数×3(每个像素3个通道,每个通道存1位),如果文本太长,可以先压缩文本或者换用更大的图像。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:26:09