图像哈希1:基于四元数离散傅里叶变换和对数极坐标的鲁棒图像哈希算法,复现论文

图像哈希系列:
图像哈希1:基于四元数离散傅里叶变换和对数极坐标的鲁棒图像哈希算法
图像哈希2:基于环形分区和NMF的鲁棒感知图像哈希(CCF A)
图像哈希3:基于四元数离散余弦变换的鲁棒感知图像哈希研究(性能优于近年一些较好的研究)
图像哈希4:基于四元数 SVD 的奇异值的鲁棒图像哈希
未完待续…
欢迎交流

基于四元数离散傅里叶变换和对数极坐标的鲁棒图像哈希算法

论文:Robust hashing for image authentication using quaternion discrete Fourier transform and log-polar transform 论文链接
doi:https://doi.org/10.1016/j.dsp.2015.03.006
摘要:本文基于四元离散傅里叶变换(QDFT)与对数极性变换的结合,提出了一种用于图像认证的新型鲁棒图像散列方案。QDFT 为联合处理彩色图像的三个通道提供了一种可靠的方法。本方法的主要特点在于:(i) 使用对数极性变换计算二次图像;(ii) 从二次图像中提取低频 QDFT 系数的幅度。根据这些幅度系数的相关性生成最终图像哈希值,并用密钥进行加扰处理,以增强系统的安全性。为了分析和确定所提方法最合适的参数值,并从ROC曲线的角度将其性能与一些参考方法进行比较,我们进行了实验。结果表明,提出的方案对图像攻击的改变具有良好的灵敏度,对常见的攻击操作操作,尤其是大角度旋转操作具有鲁棒性。
关键词: 鲁棒图像哈希,四元离散傅里叶变换,log极性变换,图像认证

介绍

随着复杂图像编辑工具的广泛使用,图像内容很容易被篡改或伪造。因此,在许多应用中,验证图像的真实性是一个重要问题。稳健的图像散列被广泛应用于图像认证中。从原理上讲,图像散列方法提取图像的基本特征,并从中生成一个简短的二进制或实数序列(称为哈希序列)来表示图像内容。这样的哈希值应该对图像内容保护操作具有鲁棒性,同时对恶意篡改操作敏感。由于鲁棒图像散列能捕捉图像的主要特征,因此它在其他应用中也备受关注,如图像取证、图像检索、数字水印等。在图像认证方面,稳健的图像哈希值还应具有良好的抗碰撞(判别)能力,以识别视觉上不同的图像,并具有令人满意的安全级别,使对手很难伪造哈希值。要同时满足这些要求,构建鲁棒图像散列仍是一项具有挑战性的任务。

一般来说,图像哈希的构建基于三个基本步骤,即预处理、图像特征提取和哈希的构建。其中,最关键的当然是图像特征提取步骤。

当应用于彩色图像时,大多数方案都会将三个颜色通道(即红、绿、蓝或 RGB)转换为灰度图像,同时忽略色度信息。然而,利用色度信息不仅可以提高检测性能,而且由于哈希值同时包含亮度和色度信息,还可以增加图像伪造的难度。四元数可以在不放弃色度信息的情况下,为同时处理三个颜色通道提供一种合理的方法。四元数已成功应用于彩色图像配准、图像分析和水印。最近,四元离散傅里叶变换(QDFT)被用于生成图像散列并应用于图像检索 。通过遵循相同的路径,我们提出了一种基于 QDFT 和对数极性变换的新型图像散列方法,用于图像认证。QDFT 可以同时处理彩色图像的三个通道(RGB),而不会丢弃色度信息。与 DFT 相似,QDFT 的低频系数包含图像的主要能量,代表图像的基本特征。此外,QDFT 还可与对数极性变换相结合,从而获得一组旋转不变的特征。因此,我们建议利用这里使用的 QDFT 来构建一种新颖、紧凑的图像哈希算法,它对内容保护操作和几何攻击具有鲁棒性,同时对恶意篡改操作也很敏感。

基础知识

四元数

四元数是复数的泛化,有四个部分:一个实部和三个虚部,可以写成:
q = a + b i + c j + d k q=a+bi+cj+dk q=a+bi+cj+dk
其中 a , b , c 和 d 是实数,i, j 和 k 是服从以下规则的虚部:
i 2 = j 2 = k 2 = − 1 , i j = − j i = k , j k = − k j = i , k i = − i k = j i^2=j^2=k^2=-1,ij=-ji=k,jk=-kj=i,ki=-ik=j i2=j2=k2=1,ij=ji=k,jk=kj=i,ki=ik=j
四元数的乘法规则不是交换式的。四元数 q 的共轭和模数分别定义如下:
q ‾ = a − b i − c j − d k , ∣ q ∣ = a 2 + b 2 + c 2 + d 2 . \overline q=a-bi-cj-dk,\left|q\right|=\sqrt{a^2+b^2+c^2+d^2}. q=abicjdk,q=a2+b2+c2+d2 .
具有零实部的四元数 q 称为纯四元数。空间位置(x, y)上彩色图像f的一个像素有三个分量,可以表示为纯四元数:
f ( x , y ) = f R ( x , y ) i + f G ( x , y ) j + f B ( x , y ) k , f(x,y)=f_R(x,y)i+f_G(x,y)j+f_B(x,y)k, f(x,y)=fR(x,y)i+fG(x,y)j+fB(x,y)k,
f R ( x , y ) , f G ( x , y ) , f B ( x , y ) f_R(x,y),f_G(x,y),f_B(x,y) fR(x,y),fG(x,y),fB(x,y)分别是 f ( x , y ) f(x,y) f(x,y)的RGB分量值。

四元数离散傅里叶变换

Ell首次在图像处理社区中引入四元数或超复傅里叶变换。由于四元数乘法的非交换性质,QDFT有三种不同类型的,即右侧、左侧和两侧。由于右侧 QDFT 可以以与左侧 QDFT 类似的方式处理,左侧 DQFT 或右侧 QDFT 的操作比两侧 QDFT 的操作要容易得多,我们决定使用左侧 QDFT。对于大小为M × M的彩色图像f(x, y), QDFT及其逆变换IQDFT定义如下:
F ( u , v ) = 1 M ∑ x = 0 M − 1 ∑ y = 0 M − 1 e − 2 μ ( u x M + v y M ) f ( x , y ) , f ( x , y ) = 1 M ∑ μ = 0 M − 1 ∑ v = 0 M − 1 e 2 μ π ( u x M + v y M ) F ( u , v ) F(u,v)=\frac1M\sum_{x=0}^{M-1}\sum_{y=0}^{M-1}e^{-2\mu\left(\frac{ux}M+\frac{vy}M\right)}f(x,y),\\f(x,y)=\frac1M\sum_{\mu=0}^{M-1}\sum_{v=0}^{M-1}e^{2\mu\mathrm\pi\left(\frac{\mathrm{ux}}{\mathrm M}+\frac{\mathrm{vy}}{\mathrm M}\right)}F(u,v) F(u,v)=M1x=0M1y=0M1e2μ(Mux+Mvy)f(x,y),f(x,y)=M1μ=0M1v=0M1e2μπ(Mux+Mvy)F(u,v)
其中 μ \mu μ是任何单位纯四元数,可以定义为i、j和k的线性组合.

提出的方案

流程图
方案流程图 方案流程图 方案流程图

预处理

以 Lena 测试图像为例说明了我们使用的预处理程序。这一步将 I0 作为输入图像,首先将其重新缩放为固定大小的 M×M。这一步确保生成的图像哈希值长度固定,同时使其对图像缩放操作具有鲁棒性。本文选择 M = 256。第二步,为了使生成的图像哈希值更加稳健,应用了基于 ak×k 窗口的平滑(即平均滤波)操作。其目的是在去除无关紧要的细节的同时保留基本结构,而不影响图像内容。然后,考虑到图像可以旋转,我们建议只考虑图像内切圆内的平滑像素,如图 2 (d)所示。这可以通过将内切圆外的像素置零来实现。如图 2 (d) 和图 2 (e) 所示,图像及其旋转版本具有相同的像素值。因此,在图像旋转角度较大的情况下,我们可以最大限度地减少信息丢失的影响,尤其是图像边角像素的丢失。
预处理

特征提取

在预处理阶段处理图像缩放的鲁棒性,我们正在寻找的图像特征必须对图像旋转具有鲁棒性。为此,我们建议首先将预处理图像转换为对数极域,然后应用 QDFT。
Log Polar Image

论文里证明了对数极坐标抗旋转,即图像旋转之后的图像哈希序列不变。

哈希构造

把经过选择和扰乱的正方形区域的 p 个 QDFT 幅值系数表示成一个行向量 H G H_G HG
H G = { 1 , i f    z ( i ) − z ( i + 1 ) ≥ 0 0 , i f    z ( i ) − z ( i + 1 ) < 0 i = 1 , . . . , p − 1 H_G=\left\{\begin{array}{l}1,if\;z\left(i\right)-z\left(i+1\right)\geq0\\0,if\;z(i)-z(i+1)<0\end{array}\right.\\i=1,...,p-1 HG={1,ifz(i)z(i+1)00,ifz(i)z(i+1)<0i=1,...,p1
使用归一化汉明距离 D1 来衡量两个散列之间的相似性.

主要代码

import numpy as np    #1.20.3
import quaternion as qt
import cv2
import matplotlib.pyplot as plt
import os
import pandas as pd
def read_images_from_folder(folder_path):
    """
    读取文件夹中所有的图片
    """
    image_list = []
    image_paths = []  # 用于保存图片的文件路径
    # 遍历文件夹中的所有文件
    for filename in os.listdir(folder_path):
        file_path = os.path.join(folder_path, filename)
        # 检查文件是否为图片
        if file_path.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):
            try:
                # 使用OpenCV读取图片
                image = cv2.imread(file_path)
                image_list.append(image)
                image_paths.append(file_path)
            except Exception as e:
                # 处理异常,例如无法读取的文件
                print(f"Error reading image {file_path}: {e}")

    return image_list, image_paths


def preprocessing(image):
    """
    数据预处理
    """
    ###########1.将图像缩放到256x256像素#############
    img_resized = cv2.resize(image, (256, 256))

    ########### 2.应用7x7的平均滤波器#########
    k_size = 7
    img_blurred = cv2.blur(img_resized, (k_size, k_size))

    ########### 3.内切圆 ##########
    # 创建一个黑色图像作为掩码
    mask = np.zeros_like(img_blurred, dtype=np.uint8)
    # 获取图像中心坐标
    center = (img_blurred.shape[1] // 2, img_blurred.shape[0] // 2)
    # 获取内切圆的半径
    radius = min(center[0], center[1])
    # 在掩码上绘制白色的内切圆
    cv2.circle(mask, center, radius, (255, 255, 255), thickness=-1)
    # 将原始图像与掩码进行按位与操作
    img_smoothed = cv2.bitwise_and(img_blurred, mask)

    # 转换颜色通道顺序 BGR -> RGB
    img_smoothed_rgb = cv2.cvtColor(img_smoothed, cv2.COLOR_BGR2RGB)
    return img_smoothed_rgb


####快速傅里叶变换计算####
def exp_quaternion(u):
    """
    四元数的指数运算
    """
    # 手动计算四元数的模,并用它来规范化四元数
    norm_u = np.abs(u)
    v = u / (norm_u+(1e-80))
    # 计算指数形式的指数运算
    exponential_form = np.cos(norm_u) + v * np.sin(norm_u)
    return exponential_form

def fft1D(signal):
    """
    signal:为一维的四元数序列
    return:*
    """
    # 定义单位纯四元数 u = ai + bj + ck,其中 |u| = 1
    # 构建单位纯四元数
    # 第一种四元数论文常用单位四元数
    d1=3**(1/2)
    u_lum = qt.quaternion(0, 1/d1, 1/d1, 1/d1)
    # 第二种单位四元数
    d2=68**(1/2)
    u_perc=qt.quaternion(0, 0, -2/d2, 8/d2)

    N = len(signal)
    if N <= 1:
        return signal
    even = fft1D(signal[0::2])
    odd = fft1D(signal[1::2])
    #一维傅里叶变换公式
    T = [exp_quaternion(-2*u_lum * np.pi * k / N) * odd[k] for k in range(N // 2)]
    # T = [exp_quaternion(-2 * u_perc * np.pi * k / N) * odd[k] for k in range(N // 2)]
    return np.concatenate([even + T, even - T])
def fft2D(image):
    """
    image:四元数矩阵(256*256)
    return:返回经过傅里叶变换后的四元数矩阵
    """
    M, N = image.shape
    if M <= 1 and N <= 1:
        return image
    # FFT along rows
    rows = np.array([fft1D(row) for row in image])
    # FFT along columns
    cols = np.array([fft1D(col) for col in rows.T]).T

    return cols


def QDFT(image,k):
    """
    image:预处理好的图片
    k:提取图片中间K×K大小的振幅系数,从上到下和从左到右的选择序列从正方形区域确定
    return:通过QDFT处理之后的振幅系数
    1.对数极坐标变换(抗旋转)
    2.将图片用四元数表示
    3.对四元数图像进行离散傅里叶变换,然后将低频信号移到图像中间。振幅系数为四元数的绝对值
    4,输出K×K大小的振幅系数
    """
    #1.对数极坐标
    rows, cols,_ = image.shape
    center_row, center_col = (rows // 2)+1, (cols // 2)+1
    log_polar_img = cv2.logPolar(image, (center_row, center_col), 50, cv2.WARP_FILL_OUTLIERS)
    #2.将彩色图像的每个像素用纯四元数表示
    quaternion_array = np.zeros((rows, cols), dtype=np.quaternion)
    # for i in range(rows):
    #     for j in range(cols):
    #         quaternion_array[i, j] = np.quaternion(0, *log_polar_img[i,j])
    #列表推导式提高运行速度
    quaternion_array = np.array([[np.quaternion(0, *log_polar_img[i, j]) for j in range(cols)] for i in range(rows)])
    #3.对四元数图像进行离散傅里叶变换
    fft_image = fft2D(quaternion_array)
    Amplitude_coefficient = np.abs(fft_image)/rows
    f_transformed_shifted = np.fft.fftshift(Amplitude_coefficient)
    # 4.提取K×K的振幅系数
    # print(center_row, center_col)
    # center_row, center_col = 129, 129
    half_k = k // 2
    if k % 2 == 0:
        result = f_transformed_shifted[center_row - half_k:center_row + half_k,
                 center_col - half_k:center_col + half_k]
    else:
        result = f_transformed_shifted[center_row - half_k:center_row + half_k + 1,
                 center_col - half_k:center_col + half_k + 1]

    amplitude_matrix = [result[i][j] for i in range(k) for j in range(k)]
    hash=[1 if amplitude_matrix[i]-amplitude_matrix[i+1]>=0 else 0 for i in range(k*k-1)]
    return hash

def normalized_hamming_distance(hash1,hash2):
    distance=np.count_nonzero(np.array(list(hash1)) != np.array(list(hash2)))
    return distance/len(hash1)

复现的代码中根据论文的公式,使用快速傅里叶变换来优化代码运行效率,结果并没有改变。

复现结果

加粗样式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值