diff --git a/README.md b/README.md index ae429df..8e90e2a 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,9 @@ pip install HideInfo 说明 - 已支持彩色图片 - 一般情况下,手机/浏览器的预览和点击大图分别使黑色背景和白色背景,因此有"预览和点击是两张不通的图"的效果 -- 短视频:[B站](https://www.bilibili.com/video/BV1DF41117c7/) -- 例子:[example/example_mirage_tank.py](example/example_mirage_tank.py) +- 视频展示:[B站](https://www.bilibili.com/video/BV1DF41117c7/) +- 代码:[example/example_mirage_tank.py](example/example_mirage_tank.py) + ```python from hide_info import mirage_tank @@ -60,13 +61,13 @@ mirage_tank.mirage_tank('图片.png', 'img2.jpeg', '幻影坦克.png') 功能:把文件/文本/bytes 类数据,转换为图片 原理:图片 1 个像素的 1 个通道可以存放 0-255 的数字,也就是一个字节。因此可以用来存放数据。 使用场景: - - 信息隐藏、隐蔽传输 - - 在只能发送图片的场景下(例如社交软件),发送任意信息 +- 信息隐藏、隐蔽传输 +- 在只能发送图片的场景下(例如社交软件),发送任意信息 说明 -- RGB 3个通道都用来存放数据 +- RGB 3个通道都用来存放数据,但不使用透明通道 - 使用前4个字节记录数据的大小,因此要求总的数据量小于 4G -- 可以存放文件、文本、bytes 类数据,把它转化为一张图片 +- 可以存放文件、文本、字节等类型的数据,把它转化为一张图片 - 代码:[example_hide_as_img.py](example/example_hide_as_img.py) ```python @@ -80,16 +81,16 @@ hide_as_img.file_decode(filename='化物为图-解出来的文件.zip', img_file ## hide_in_img:藏物于图 -功能:文件/文本/bytes 类数据,藏进一个 PNG 图片中,并且用肉眼无法看出区别 -原理:(LSB算法)根据信息的二进制,改变像素数据的最低位,肉眼是无法察觉这种改变 +功能:把文件/文本/字节 类数据,藏进一个预先准备好的 PNG 图片中,使其用肉眼无法看出区别 +原理:(LSB算法)根据信息的二进制,改变像素数据的最低位,肉眼是无法察觉这种改变 使用场景: - - 信息隐藏、隐蔽传输 - - 在只能发送图片的场景下(例如某社交软件),发送任意信息 - - 盲水印、图片溯源、版权保护 +- 信息隐藏、隐蔽传输 +- 在只能发送图片的场景下(例如某社交软件),发送任意信息 +- 盲水印、图片溯源、版权保护 说明 -- 解原始数据时,无需原图参与,只看最低位 +- 解原始数据时,无需原图参与 - 使用前4个字节存放数据的大小 - 使用位运算,提高一定的性能 - LSB算法对压缩、转格式等攻击脆弱 @@ -130,6 +131,10 @@ img_watermark.file_decode(img_filename="图片_打入水印.png", wm_extract=" - 例子:[example/example_img_seed.py](example/example_img_seed.py) +原理 +- jpg 的内容结束标志为 FF D9,它不关心之后的内容 +- rar 的内容开始标志为 52 61 71 21,它不关心前面的内容 + ## img_exif:把信息隐藏在图片的EXIF中 功能:把信息隐藏在图片的 EXIF 中,从而获得隐蔽信息、传输隐蔽信息的能力 @@ -176,7 +181,11 @@ hide_as_music.file_decode(filename='化物为音-解出来的文件.zip', wav_fi ## echo_watermark: 回声水印 -回声水印(Echo Watermarking)是一种音频水印技术,通过在原始音频信号中添加回声来嵌入信息。这种技术利用了人耳的心理声学特性,即人耳对于短时间内的回声延迟是不敏感的,因此可以将信息隐藏在音频信号的回声中而不影响听感。 +人类听觉系统(HAS)极为灵敏,音频感知冗余小,音频水印同时满足隐蔽性和鲁棒性有一定难度。同时音频压缩算法如 MP3 有损压缩有出色的压缩率和音质,对音频水印带来很大的挑战。 + +掩蔽效应是 HAS 的一个特点:短时间内高能量部分会掩蔽低能量部分,从而让人耳只能听见高能量部分,掩蔽分为超前掩蔽、同时掩蔽、滞后掩蔽。因此可以将信息隐藏在音频信号的回声中而不影响听感。 + +回声水印(Echo Watermarking)是一种音频水印技术,通过在原始音频信号中添加回声来嵌入信息。 回声水印的实现通常有两个重要参数:回声延迟和回声幅度。延迟时间决定了回声在原始信号之后多久发生,而幅度则影响回声的强度。通过巧妙地调节这两个参数,可以将数字信息(如比特流)编码到音频信号中。 diff --git a/example/example_mirage_tank.py b/example/example_mirage_tank.py index 57b465f..76960a8 100644 --- a/example/example_mirage_tank.py +++ b/example/example_mirage_tank.py @@ -1,3 +1,3 @@ from hide_info import mirage_tank -mirage_tank.mirage_tank('图片.jpg', '图片2.png', '幻影坦克.png') +mirage_tank.mirage_tank('图片.jpg', '图片2.png', './output/幻影坦克.png') diff --git a/hide_info/__init__.py b/hide_info/__init__.py index 124e462..1c98a23 100644 --- a/hide_info/__init__.py +++ b/hide_info/__init__.py @@ -1 +1 @@ -__version__ = '0.1.7' +__version__ = '0.1.9' diff --git a/hide_info/mirage_tank.py b/hide_info/mirage_tank.py index ec64ea5..3b735cf 100644 --- a/hide_info/mirage_tank.py +++ b/hide_info/mirage_tank.py @@ -1,68 +1,39 @@ ''' -原理如下: -- 目标是使得一张PNG图片(带透明涂层),在白色背景下显示图A,在黑色背景下显示图B -- 这样的要求下,可以列出以下方程 - -aP +(1-a)白 = A -aP + (1-a)黑 = B - -已知 白色 = 255,黑色 = 0,代入方程,得到: -a = 1- (A-B) -P = B/a - -因为 a 的取值范围为 [0, 1],因此需要 B 图较暗,A图较亮 +原理:https://www.guofei.site/2023/08/26/hide_info.html ''' import cv2 import numpy as np -# 这个只能输出黑白图 -def mirage_tank2(img_filename1: str, img_filename2: str, output_img_filename: str): - A = cv2.imread(img_filename1, flags=cv2.IMREAD_GRAYSCALE) / 255 - B = cv2.imread(img_filename2, flags=cv2.IMREAD_GRAYSCALE) / 255 - - # 保证两个图片的大小一致 - B = cv2.resize(B, A.shape[::-1]) - a = 1 - (A - B) - a = np.clip(a, 0, 1) - P = B / a - P = np.clip(P, 0, 1) - - # 创建一个带有透明度通道的图像 - image_with_alpha = np.zeros((A.shape[0], A.shape[1], 4), dtype=np.uint8) - image_with_alpha[:, :, 0] = P * 255 - image_with_alpha[:, :, 1] = P * 255 - image_with_alpha[:, :, 2] = P * 255 - image_with_alpha[:, :, 3] = a * 255 - - # 保存带有透明度通道的图像 - cv2.imwrite(output_img_filename, image_with_alpha) +def mirage_tank(img_filename1: str, img_filename2: str, output_img_filename: str, a=0.5, b=None): + img1_rgb = cv2.imread(img_filename1) + img2_grey = cv2.imread(img_filename2, cv2.IMREAD_GRAYSCALE) + # a 越大,img2 越清晰,但是 img1 越可能出现偏差 + assert 0.1 < a < 0.95, "0.1 < a < 0.95" + if b is None: + b = max(img1_rgb.mean() - 255 * a, 10) -def mirage_tank(img_filename1: str, img_filename2: str, output_img_filename: str, a=0.5, b=20): - A = cv2.imread(img_filename1) - B = cv2.imread(img_filename2) + img2_grey = a * img2_grey + b - height, width, _ = A.shape + height, width, _ = img1_rgb.shape # 保证两个图片的大小一致 - B = cv2.resize(B, (width, height)) + img2_grey = cv2.resize(img2_grey, (width, height)) # 计算 alpha 通道 - A_gray = cv2.cvtColor(A, cv2.COLOR_BGR2GRAY) - B_gray = cv2.cvtColor(B, cv2.COLOR_BGR2GRAY) - B_gray = a * B_gray + b # 适当调暗图片B - alpha = 255 - A_gray.astype('int') + B_gray.astype('int') - alpha = np.clip(alpha, 1, 255).reshape(height, width, 1) - # 使用 A 或者 B,决定了彩图来自哪个图 - # P = B / (a / 255) - P = (A - (255 - alpha)) / (alpha / 255) + img1_avg = img1_rgb.mean(axis=2) + + alpha = 255 - img1_avg.astype('int') + img2_grey.astype('int') + alpha = np.clip(alpha, 0, 255).reshape(height, width, 1) + + rgb = (img1_rgb - (255 - alpha)) / (alpha / 255) alpha = alpha.astype('u8') - P = np.clip(P, 0, 255) + rgb = np.clip(rgb, 0, 255) # 带有透明度通道的图像 - image_with_alpha = np.concatenate([P, alpha], axis=2) + image_with_alpha = np.concatenate([rgb, alpha], axis=2) cv2.imwrite(output_img_filename, image_with_alpha)