原文: A blind and robust color image watermarking scheme based on DCT and DWT domains
写在前面: 这是一篇拥有 “中科院论文工厂预警” 的 2023 年 SCI 3/4 区论文!无奈相关论文比较少,因此只能硬着头皮读一读。
Evaluation metrics
在数字水印方面必须达到的两个主要目标是:不可感知性和鲁棒性。在本文中,我们使用了两个广泛被采用的指标来评估由所提出的方法获得的含水印图像的质量。这些指标是峰值信噪比 P S N R \mathsf{PSNR} PSNR 和结构相似度 S S I M \mathsf{SSIM} SSIM。除此之外,我们还使用了另外两个指标来评估所提出的方法在遭受各种攻击时的鲁棒性。这些指标是归一化相关 N C \mathsf{NC} NC 和误码率 B E R \mathsf{BER} BER。
1 测量含水印图像的质量
1.1 PSNR 指标
P S N R \mathsf{PSNR} PSNR 指标量化了水印嵌入过程中加入到宿主图像中的噪声量。随着加入噪声的增大, P S N R \mathsf{PSNR} PSNR 值减小,反之亦然。因此,较高的 P S N R \mathsf{PSNR} PSNR 值表示较好的不可感知性。一般来说, P S N R \mathsf{PSNR} PSNR 值达到 30 d B \mathsf{30dB} 30dB 以上意味着含水印图像的透明度与宿主图像相似。
使用以下公式来计算 P S N R \mathsf{PSNR} PSNR,它是以分贝 ( d B ) \mathsf{(dB)} (dB) 为单位测量的:
P S N R = 10 l o g 10 ( 25 5 2 1 3 M N ∑ k = 0 3 − 1 ∑ i = 0 M − 1 ∑ j = 0 N − 1 ( H ( i , j , k ) − W ( i , j , k ) ) 2 ) ( d B ) PSNR=10log_{10}\left(\frac{255^2}{\frac{1}{3MN} {\textstyle \sum_{k=0}^{3-1}} {\textstyle \sum_{i=0}^{M-1}} {\textstyle \sum_{j=0}^{N-1}} (H(i,j,k)-W(i,j,k))^2}\right)\ (\mathrm{dB}) PSNR=10log10(3MN1∑k=03−1∑i=0M−1∑j=0N−1(H(i,j,k)−W(i,j,k))22552) (dB)
其中 H H H 和 W W W 分别代表宿主图像和含水印的图像, M M M 和 N N N 分别代表 H H H 和 W W W 的行和列的大小。
理论上,宿主图像和含水印的图像应该是一样大的。
Python 代码实现
pip install scikit-image
import cv2
from skimage.metrics import peak_signal_noise_ratio
img1 = cv2.imread('original.jpg')
img2 = cv2.imread('watermarked.jpg')
psnr = peak_signal_noise_ratio(img1, img2)
print('PSNR: ', psnr)
1.2 SSIM 指标
S S I M \mathsf{SSIM} SSIM 以类似于人类视觉系统的方式评估两个图像之间的相似程度。 S S I M \mathsf{SSIM} SSIM 值落在 [ − 1 , 1 ] [-1,1] [−1,1] 范围内。 S S I M \mathsf{SSIM} SSIM 的值为 1 1 1 表示被比较的两个图像是相同的,但由于嵌入效应,这是不可能实现的。因此,最接近于 1 1 1 的值是首选的。
使用以下公式来计算 S S I M \mathsf{SSIM} SSIM:
S S I M = ( 2 μ H μ W + C 1 ) ( 2 σ H W + C 2 ) ( μ H 2 + μ W 2 + C 1 ) ( σ H 2 + σ W 2 + C 2 ) SSIM=\frac{(2\mu_H\mu_W+C_1)(2\sigma_{HW}+C_2)}{(\mu_H^2+\mu_W^2+C_1)(\sigma_{H}^2+\sigma_{W}^2+C_2)} SSIM=(μH2+μW2+C1)(σH2+σW2+C2)(2μHμW+C1)(2σHW+C2)
其中 μ H μ_H μH 和 μ W μ_W μW 分别代表 H H H 和 W W W 的局部均值, σ H σ_H σH 和 σ W σ_W σW 分别代表 H H H 和 W W W 的标准差, σ H W σ_{HW} σHW 代表 H H H 和 W W W 之间的互协方差。 C 1 C_1 C1 和 C 2 C_2 C2 是用于避免分母为 0 0 0 的常量,其计算如下: C 1 = ( 0.01 × 255 ) 2 C1=(0.01 × 255)^2 C1=(0.01×255)2 和 C 2 = ( 0.03 × 255 ) 2 C_2=(0.03 × 255)^2 C2=(0.03×255)2。
Python 代码实现
pip install scikit-image
from skimage.metrics import structural_similarity
img1 = cv2.imread('original.jpg')
img2 = cv2.imread('watermarked.jpg')
ssim = structural_similarity(img1, img2, channel_axis=-1)
print('SSIM: ', ssim)
2 测量提取出的水印的质量
2.1 NC 指标
N C \mathsf{NC} NC 指标用于评估原始水印图像和提取出的水印图像之间的相似比。 N C \mathsf{NC} NC 的取值范围在 [ 0 , 1 ] [0,1] [0,1] 之间。当被比较的两个图像完全相同时, N C \mathsf{NC} NC 的值为 1 1 1。随着两个图像之间的差异增大, N C \mathsf{NC} NC 的值减小。当 N C \mathsf{NC} NC 的值为 0 0 0 时表示两个图像完全不同。因此, N C \mathsf{NC} NC 的值越接近于 1 1 1,代表图像的质量和水印方案的鲁棒性越好。
使用以下公式来计算 N C \mathsf{NC} NC:
N C = ∑ i = 0 R − 1 ∑ j = 0 C − 1 ( O W ( i , j ) R W ( i , j ) ) ∑ i = 0 R − 1 ∑ j = 0 C − 1 ( O W ( i , j ) ) 2 ∑ i = 0 R − 1 ∑ j = 0 C − 1 ( R W ( i , j ) ) 2 NC=\frac{
{\textstyle \sum_{i=0}^{R-1}}{\textstyle \sum_{j=0}^{C-1}}(OW(i,j)RW(i,j))}{\sqrt{
{\textstyle \sum_{i=0}^{R-1}}{\textstyle \sum_{j=0}^{C-1}}(OW(i,j))^2}\sqrt{
{\textstyle \sum_{i=0}^{R-1}}{\textstyle \sum_{j=0}^{C-1}}(RW(i,j))^2}} NC=∑i=0R−1∑j=0C−1(OW(i,j))2∑i=0R−1∑j=0C−1(RW(i,j))2∑i=0R−1∑j=0C−1(OW(i,j)RW(i,j))
参考博客中的公式:
ρ X Y = C o v ( X , Y ) D ( X ) D ( Y ) = 1 n ∑ ( X − X ‾ ) ( Y − Y ‾ ) 1 n ∑ ( X − X ‾ ) 2 1 n ∑ ( Y − Y ‾ ) 2 \rho_{XY}=\frac{Cov(X,Y)}{\sqrt{D(X)}\sqrt{D(Y)}}=\frac{\frac{1}{n}\sum_{}^{}(X-\overline{X})(Y-\overline{Y})}{\sqrt{\frac{1}{n}\sum_{}^{}(X-\overline{X})^2}\sqrt{\frac{1}{n}\sum_{}^{}(Y-\overline{Y})^2}} ρXY=D(X)D(Y)Cov(X,Y)=n1∑(X−X)2n1∑(Y−Y)2n1∑(X−X)(Y−Y)
其中 C o v ( X , Y ) Cov(X,Y) Cov(X,Y) 是协方差, D ( X ) D(X) D(X) 和 D ( Y ) D(Y) D(Y) 是方差,取根号后就是标准差。虽然分子分母的 1 n \frac{1}{n} n1 能抵消,但不难看出,原论文给的公式是完全没有考虑均值啊
由于图像是一个二维数据,因此求和号要有两个,但本质上还是两个图像对应位置上的像素进行相乘。
Python 代码实现
import cv2
import numpy as np
def compute_nc(image1, image2):
# 将图像转换为灰度图
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
# 对图像进行resize,保证图像大小一致
gray1 = cv2.resize(gray1, (100, 100))
gray2 = cv2.resize(gray2, (100, 100))
# 计算均值和标准差
mean1 = np.mean(gray1)
mean2 = np.mean(gray2)
std1 = np.std(gray1)
std2 = np.std(gray2)
# 计算归一化相关系数(NC)
nc = np.mean((gray1 - mean1) * (gray2 - mean2)) / (std1 * std2)
return nc
# 读取两个图像
img1 = cv2.imread("original.jpg")
img2 = cv2.imread("watermarked.jpg")
# 计算归一化相关系数(NC)
nc_value = compute_nc(img1, img2)
print("NC值:", nc_value)
参考博客:
2.2 BER 指标
使用以下公式来计算 B E R \mathsf{BER} BER:
B E R = ∑ i = 0 R − 1 ∑ j = 0 C − 1 ( O W ( i , j ) ⊕ R W ( i , j ) ) R × C BER=\frac{
{\textstyle \sum_{i=0}^{R-1}}{\textstyle \sum_{j=0}^{C-1}}(OW(i,j)\oplus RW(i,j))}{R\times C} BER=R×C∑i=0R−1∑j=0C−1(OW(i,j)⊕RW(i,j))
其中 O W OW OW 和 R W RW RW 分别代表原始的水印图像和提取出的水印图像, R R R 和 C C C 分别表示 O W OW OW 和 R W RW RW 的行和列大小, ⊕ \oplus ⊕ 代表按位异或运算符。
B E R \mathsf{BER} BER 被定义为恢复错误的比特数与总嵌入比特数的比值。 B E R \mathsf{BER} BER 的取值范围在 [ 0 , 1 ] [0,1] [0,1] 之间,与 N C \mathsf{NC} NC 的取值范围相同,但两者的作用方向相反。 B E R \mathsf{BER} BER 的值为 0 0 0 表示被比较的两个图像完全相同,而 B E R \mathsf{BER} BER 的值为 1 1 1 表示被比较的两个图像完全不同。因此, B E R \mathsf{BER} BER 的值越接近于 0 0 0,代表水印方案的鲁棒性越好。
Python 代码实现
import numpy as np
def calculate_ber(watermark, watermark_recovered):
# 要求两个矩阵的形状相同
assert watermark.shape == watermark_recovered.shape,\
"Error: matrices must have the same shape."
# 计算错误的比特数
num_errors = np.count_nonzero(watermark != (watermark_recovered > 0.5))
# 计算水印总的比特数
total_bits = watermark.size
# 计算误码率(BER)
ber = num_errors / total_bits
return ber
# 定义原始水印
watermark = np.array([[0, 1, 1, 0],
[1, 0, 1, 1],
[0, 1, 0, 0]])
# 定义提取出的水印
watermark_recovered = np.array([[0.2, 0.8, 0.9, 0.3],
[0.7, 0.4, 0.6, 0.8],
[0.1, 0.6, 0.4, 0.2]])
# 计算误码率(BER)
ber = calculate_ber(watermark, watermark_recovered)
print("Bit error rate:", ber)
其中 watermark_recovered > 0.5
对提取出的水印进行四舍五入,然后再与原始水印进行比对。若对应位置上的值相同,则结果为 F a l s e \mathsf{False} False;若对应位置上的值不相同,则结果为 T r u e \mathsf{True} True。
最后使用 np.count_nonzero
函数计算非零的个数,即 T r u e \mathsf{True} True 的个数,若个数为 0 0 0 则代表误码率为 0 0 0。
文章评论