以下是基于Python实现的自适应图像数字水印算法及性能评估:
```python
import cv2
import numpy as np
import math
# 定义图像块大小和水印长度
block_size = 8
watermark_len = 64
# 读入原始图像和水印
img = cv2.imread('lena.png')
watermark = np.random.randint(0, 2, watermark_len)
# 对原始图像进行分块
h, w, c = img.shape
blocks_h = h // block_size
blocks_w = w // block_size
blocks_num = blocks_h * blocks_w
img_blocks = np.zeros((blocks_num, block_size, block_size, c), dtype=np.uint8)
for i in range(blocks_h):
for j in range(blocks_w):
img_blocks[i * blocks_w + j] = img[i * block_size:(i + 1) * block_size, j * block_size:(j + 1) * block_size]
# 对每个图像块进行变换和嵌入
for i in range(blocks_num):
block = img_blocks[i].astype(np.float32)
# 进行DCT变换
block_dct = cv2.dct(block)
# 获取变换系数的均值和标准差
mean = np.mean(block_dct)
std = np.std(block_dct)
# 确定最佳嵌入位置
max_psnr = 0
best_pos = 0
for pos in range(block_size * block_size - watermark_len):
# 嵌入水印
block_dct_copy = block_dct.copy().reshape((-1,))
block_dct_copy[pos:pos + watermark_len] += (2 * watermark - 1) * std
block_dct_copy[block_dct_copy < mean] = mean
block_dct_copy[block_dct_copy > 255] = 255
# 反变换得到水印图像块
block_watermark = cv2.idct(block_dct_copy.reshape((block_size, block_size)))
block_watermark = np.round(block_watermark).astype(np.uint8)
# 计算PSNR
psnr = cv2.PSNR(block, block_watermark)
if psnr > max_psnr:
max_psnr = psnr
best_pos = pos
# 嵌入水印
block_dct_copy = block_dct.copy().reshape((-1,))
block_dct_copy[best_pos:best_pos + watermark_len] += (2 * watermark - 1) * std
block_dct_copy[block_dct_copy < mean] = mean
block_dct_copy[block_dct_copy > 255] = 255
# 反变换得到含有水印的图像块
img_blocks[i] = cv2.idct(block_dct_copy.reshape((block_size, block_size))).astype(np.uint8)
# 合并图像块得到含有水印的图像
img_watermark = np.zeros((h, w, c), dtype=np.uint8)
for i in range(blocks_h):
for j in range(blocks_w):
img_watermark[i * block_size:(i + 1) * block_size, j * block_size:(j + 1) * block_size] = img_blocks[i * blocks_w + j]
# 显示原始图像和含水印的图像
cv2.imshow('Original Image', img)
cv2.imshow('Watermarked Image', img_watermark)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 测试水印鲁棒性
img_test = cv2.imread('lena.png')
img_test_blocks = np.zeros((blocks_num, block_size, block_size, c), dtype=np.uint8)
for i in range(blocks_h):
for j in range(blocks_w):
img_test_blocks[i * blocks_w + j] = img_test[i * block_size:(i + 1) * block_size, j * block_size:(j + 1) * block_size]
# 对每个图像块进行攻击
attack_types = ['resize', 'rotate', 'blur', 'noise']
for attack_type in attack_types:
for i in range(blocks_num):
block = img_test_blocks[i]
# 对图像块进行攻击
if attack_type == 'resize':
block = cv2.resize(block, (block_size + 2, block_size + 2))
block = block[1:-1, 1:-1]
elif attack_type == 'rotate':
angle = np.random.randint(0, 360)
M = cv2.getRotationMatrix2D((block_size / 2, block_size / 2), angle, 1)
block = cv2.warpAffine(block, M, (block_size, block_size))
elif attack_type == 'blur':
block = cv2.GaussianBlur(block, (3, 3), 0)
elif attack_type == 'noise':
noise = np.random.randint(0, 50, size=(block_size, block_size, c))
block = block.astype(np.int16) + noise
block[block < 0] = 0
block[block > 255] = 255
block = block.astype(np.uint8)
# 进行DCT变换
block_dct = cv2.dct(block.astype(np.float32))
# 获取变换系数的均值和标准差
mean = np.mean(block_dct)
std = np.std(block_dct)
# 检测水印
count = 0
for pos in range(block_size * block_size - watermark_len):
# 提取水印
block_dct_copy = block_dct.copy().reshape((-1,))
block_watermark = np.zeros(watermark_len, dtype=np.int32)
for j in range(watermark_len):
if block_dct_copy[pos + j] > mean:
block_watermark[j] = 1
else:
block_watermark[j] = 0
# 判断提取出的水印是否与原始水印相同
if np.array_equal(block_watermark, watermark):
count += 1
# 计算检测正确率
accuracy = count / (block_size * block_size - watermark_len)
print('Attack Type: {}, Accuracy: {:.2f}%'.format(attack_type, accuracy * 100))
# 测试水印容量
img_capacity = cv2.imread('lena.png')
img_capacity_blocks = np.zeros((blocks_num, block_size, block_size, c), dtype=np.uint8)
for i in range(blocks_h):
for j in range(blocks_w):
img_capacity_blocks[i * blocks_w + j] = img_capacity[i * block_size:(i + 1) * block_size, j * block_size:(j + 1) * block_size]
# 对每个图像块嵌入不同长度的水印
watermark_lens = [16, 32, 64, 128]
for watermark_len in watermark_lens:
capacity = 0
for i in range(blocks_num):
block = img_capacity_blocks[i].astype(np.float32)
# 进行DCT变换
block_dct = cv2.dct(block)
# 获取变换系数的均值和标准差
mean = np.mean(block_dct)
std = np.std(block_dct)
# 确定最佳嵌入位置
max_psnr = 0
best_pos = 0
for pos in range(block_size * block_size - watermark_len):
# 嵌入水印
block_dct_copy = block_dct.copy().reshape((-1,))
block_dct_copy[pos:pos + watermark_len] += (2 * watermark[:watermark_len] - 1) * std
block_dct_copy[block_dct_copy < mean] = mean
block_dct_copy[block_dct_copy > 255] = 255
# 反变换得到含有水印的图像块
img_blocks[i] = cv2.idct(block_dct_copy.reshape((block_size, block_size))).astype(np.uint8)
# 计算水印容量
capacity += watermark_len / (block_size * block_size)
print('Watermark Length: {}, Capacity: {:.2f}%'.format(watermark_len, capacity * 100))
# 测试水印透明性
img_transparency = cv2.imread('lena.png')
img_transparency_blocks = np.zeros((blocks_num, block_size, block_size, c), dtype=np.uint8)
for i in range(blocks_h):
for j in range(blocks_w):
img_transparency_blocks[i * blocks_w + j] = img_transparency[i * block_size:(i + 1) * block_size, j * block_size:(j + 1) * block_size]
# 对每个图像块进行嵌入
for i in range(blocks_num):
block = img_transparency_blocks[i].astype(np.float32)
# 进行DCT变换
block_dct = cv2.dct(block)
# 获取变换系数的均值和标准差
mean = np.mean(block_dct)
std = np.std(block_dct)
# 确定最佳嵌入位置
max_psnr = 0
best_pos = 0
for pos in range(block_size * block_size - watermark_len):
# 嵌入水印
block_dct_copy = block_dct.copy().reshape((-1,))
block_dct_copy[pos:pos + watermark_len] += (2 * watermark