from PIL import Image
import numpy as np
from scipy.stats import chi2
def text_to_bin(text):
"""将文本转换为二进制字符串"""
return ''.join(format(ord(c), '08b') for c in text)
def bin_to_text(binary_str):
"""将二进制字符串转换为文本"""
text = ''
for i in range(0, len(binary_str), 8):
byte = binary_str[i:i+8]
text += chr(int(byte, 2))
return text
def hide_lsb(input_img, output_img, secret_text):
"""LSB信息隐藏函数"""
img = Image.open(input_img).convert('RGB')
pixels = np.array(img)
width, height = img.size
binary_secret = text_to_bin(secret_text)
total_bits = len(binary_secret)
max_bits = width * height * 3
if total_bits > max_bits:
raise ValueError("秘密信息过长,无法嵌入到图像中")
# 将二进制字符串转换为索引可迭代形式
bit_idx = 0
for y in range(height):
for x in range(width):
for channel in range(3):
if bit_idx < total_bits:
# 清除最低位并设置秘密比特
pixels[y, x, channel] = (pixels[y, x, channel] & 0xFE) | int(binary_secret[bit_idx])
bit_idx += 1
else:
break
if bit_idx >= total_bits:
break
if bit_idx >= total_bits:
break
Image.fromarray(pixels).save(output_img)
def extract_lsb(input_img, secret_length):
"""LSB信息提取函数"""
img = Image.open(input_img).convert('RGB')
pixels = np.array(img)
width, height = img.size
total_bits = secret_length * 8
bit_list = []
bit_idx = 0
for y in range(height):
for x in range(width):
for channel in range(3):
if bit_idx < total_bits:
bit_list.append(str(pixels[y, x, channel] & 1))
bit_idx += 1
else:
break
if bit_idx >= total_bits:
break
if bit_idx >= total_bits:
break
return bin_to_text(''.join(bit_list))
def chi_square_test(img_path):
"""卡方检测函数"""
img = Image.open(img_path).convert('RGB')
pixels = np.array(img)
histogram = np.zeros(256, dtype=int)
# 统计所有通道的颜色分布
for channel in range(3):
values, counts = np.unique(pixels[:, :, channel], return_counts=True)
for v, c in zip(values, counts):
histogram[v] += c
chi_square = 0.0
for i in range(128):
pair_sum = histogram[2*i] + histogram[2*i+1]
if pair_sum == 0:
continue
expected = pair_sum / 2.0
chi_square += ((histogram[2*i] - expected)**2) / expected
chi_square += ((histogram[2*i+1] - expected)**2) / expected
# 计算p值(自由度为128-1=127)
p_value = 1 - chi2.cdf(chi_square, 127)
return p_value
# 使用示例
if __name__ == "__main__":
# 隐藏信息
hide_lsb('original.png', 'stego.png', 'CQUWATERMASKEXP')
# 提取信息
secret = extract_lsb('stego.png', 14)
print(f"提取的秘密信息: {secret}")
# 卡方检测
p_value = chi_square_test('stego.png')
print(f"卡方检测p值: {p_value:.4f}")
if p_value > 0.05:
print("检测结果: 可能存在LSB隐写")
else:
print("检测结果: 可能不存在LSB隐写")