一、 *实验目的*

了解差分隐私技术的基本特点,设计并实现基于离散傅立叶变换(DFT)的图像差分隐私保护算法。了解差分隐私技术在数字内容保护中的作用,掌握基于差分隐私的内容隐私保护方法。

二、 *实验内容*

本实验实现一种基于离散傅立叶变换的图像差分隐私保护算法,可通过隐私预算控制噪声规模,保证隐私安全性,具体过程如下:

  1. 读入一幅图像,对图像做预处理:如果读入的是彩色图像,将其转换为灰度图像(rgb2gray);在灰度图像中利用差值方式将图像重采样为128*128的标准化图表示(imresize)IM;
  2. 对标准化图像IM进行离散傅立叶变换,得到离散傅立叶变换矩阵FIM;
  3. 对离散傅立叶变换矩阵FIM,选取其前k×k个DFT系数,计算给定隐私预算ε时的拉普拉斯机制的参数λ的最小值,以确定拉普拉斯机制需要添加的噪声;
  4. 对离散傅立叶变换矩阵FIM,采样一组概率p,在参数λ最小时,计算相应的噪声值,以及融合噪声后的FIM’;
  5. 对于FIM和FIM’,分别输入PCA+SVM的人脸识别程序中进行人脸识别分类预测。
  6. 给出整个数据集上,人脸识别分类预测的准确率(Accuracy,测试集中分类器正确分类的样本数与总样本数之比)。
  7. 以LFW中随机80%的图片为训练集,剩余为测试集,分析实验结果。
  8. 关于实验报告

(1)关于ε的选取,是一个经验值,其选取依据是根据测试集的准确率决定,给出选取过程。

(2)关于k的选取,k值越大噪声越大,隐私安全性越强,但对人脸识别任务的鲁棒性会降低,因而需设定合适的k值,以满足隐私保护的人脸图像在识别精度和隐私性之间的折衷,给出选取过程。

三、 *系统整体描述和分功能描述*

*系统整体描述*

img

*分功能描述*

1)图像做预处理

如果是彩色图像,转换为灰度图像

将图像重采样为128×128的标准化图像

用到的函数:def preprocess_image(image)

2)对图像做离散傅立叶变换

对图像做离散傅立叶变换,并将结果移动到中心

选取中心的k×k个系数,并返回它们的幅度和相位

用到的函数:def dft_image(image)

3)生成一个服从标准均匀分布的随机数组

根据拉普拉斯分布的逆变换公式,计算噪声值

用到的函数:def laplace_noise(shape, b)

4)对离散傅立叶变换的系数添加拉普拉斯噪声,并还原图像

根据给定的隐私预算,计算拉普拉斯机制的参数b的最小值

采样一组概率p,决定是否添加噪声

计算相应的噪声值,并添加到幅度上

将幅度和相位合并为复数矩阵

进行逆离散傅立叶变换

取实部作为还原后的图像

用到的函数:def idft_image(magnitude_k, phase_k)

5)读取数据集中的图像,并返回一个列表和一个标签数组

遍历数据集中的每个文件夹,每个文件夹代表一个类别

将文件夹的名字转换为整数作为标签遍历每个文件夹中的每个图像文件

对图像做预处理

将图像添加到列表中

将标签添加到数组中

用到的函数:def read_dataset(path)

6)将图像列表转换为特征矩阵,并返回一个训练集和一个测试集

将图像列表转换为特征矩阵,每个图像的DFT系数作为一行

将幅度矩阵展平为一维数组

利用sklearn的train_test_split函数,按照给定的比例划分训练集和测试集

用到的函数:def split_dataset(images, labels, test_ratio=0.2)

7)利用PCA和SVM进行人脸识别,并返回准确率

利用sklearn的PCA模块,对特征矩阵进行降维,保留95%的方差

利用sklearn的SVM模块,对降维后的特征进行分类,使用线性核函数和默认参数

利用sklearn的metrics模块,计算分类的准确率

用到的函数:def face_recognition(X_train, X_test, y_train, y_test)

四、 *实验步骤、结果及分析*

*实验步骤*

  1. 下载win10虚拟机

img

  1. 开机后安装conda

img

Conda安装好后检查版本

img

配置好conda和pycharm

img

因为环境配置出现了一些问题,没有使用已给的检测模型,自己进行编写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# 导入所需的库
import cv2
import numpy as np
import os

# 定义一些常量
k = 10 # 选取前k×k个DFT系数
p = 0.5 # 采样概率
epsilon = 0.1 # 隐私预算

# 定义一个函数,对图像做预处理
def preprocess_image(image):
# 如果是彩色图像,转换为灰度图像
if len(image.shape) == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 将图像重采样为128×128的标准化图像
image = cv2.resize(image, (128, 128))
return image

# 定义一个函数,对图像做离散傅立叶变换,并选取前k×k个系数
def dft_image(image):
# 对图像做离散傅立叶变换,并将结果移动到中心
f = np.fft.fft2(image)
fshift = np.fft.fftshift(f)
# 选取中心的k×k个系数,并返回它们的幅度和相位
rows, cols = fshift.shape
crow, ccol = rows//2, cols//2
fshift_k = fshift[crow-k//2:crow+k//2, ccol-k//2:ccol+k//2]
magnitude_k = np.abs(fshift_k)
phase_k = np.angle(fshift_k)
return magnitude_k, phase_k

# 定义laplace_noise函数
def laplace_noise(shape, b):
# 生成一个服从标准均匀分布的随机数组
u = np.random.uniform(-0.5, 0.5, size=shape)
# 根据拉普拉斯分布的逆变换公式,计算噪声值
noise = -b * np.sign(u) * np.log(1 - 2 * np.abs(u))
return noise

# 定义一个函数,对离散傅立叶变换的系数添加拉普拉斯噪声,并还原图像
def idft_image(magnitude_k, phase_k):
# 根据给定的隐私预算,计算拉普拉斯机制的参数b的最小值
b_min = magnitude_k.size / epsilon
# 采样一组概率p,决定是否添加噪声
mask = np.random.binomial(1, p, size=magnitude_k.shape)
# 计算相应的噪声值,并添加到幅度上
noise = np.random.laplace(0, b_min, size=magnitude_k.shape)
magnitude_k_noisy = magnitude_k + mask * noise
# 将幅度和相位合并为复数矩阵
complex_k_noisy = magnitude_k_noisy * np.exp(1j * phase_k)
# 进行逆离散傅立叶变换
image_noisy = np.fft.ifft2(complex_k_noisy)
# 取实部作为还原后的图像
image_noisy = np.real(image_noisy)
return image_noisy


# 定义一个函数,读取数据集中的图像,并返回一个列表和一个标签数组
def read_dataset(path):
images = [] # 存储图像的列表
labels = [] # 存储标签的数组
for folder in os.listdir(path): # 遍历数据集中的每个文件夹,每个文件夹代表一个类别
label = int(folder) # 将文件夹的名字转换为整数作为标签
for file in os.listdir(os.path.join(path, folder)): # 遍历每个文件夹中的每个图像文件
image = cv2.imread(os.path.join(path, folder, file)) # 读取图像文件
image = preprocess_image(image) # 对图像做预处理
images.append(image) # 将图像添加到列表中
labels.append(label) # 将标签添加到数组中
return images, np.array(labels)

# 定义一个函数,将图像列表转换为特征矩阵,并返回一个训练集和一个测试集
def split_dataset(images, labels, test_ratio=0.2):
# 将图像列表转换为特征矩阵,每个图像的DFT系数作为一行
features = []
for image in images:
magnitude_k, phase_k = dft_image(image)
feature = magnitude_k.flatten() # 将幅度矩阵展平为一维数组
features.append(feature)
features = np.array(features)
# 利用sklearn的train_test_split函数,按照给定的比例划分训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=test_ratio, random_state=0)
return X_train, X_test, y_train, y_test

# 定义一个函数,利用PCA和SVM进行人脸识别,并返回准确率
def face_recognition(X_train, X_test, y_train, y_test):
# 利用sklearn的PCA模块,对特征矩阵进行降维,保留95%的方差
from sklearn.decomposition import PCA
pca = PCA(n_components=0.95)
pca.fit(X_train)
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
# 利用sklearn的SVM模块,对降维后的特征进行分类,使用线性核函数和默认参数
from sklearn.svm import SVC
svm = SVC(kernel='linear')
svm.fit(X_train_pca, y_train)
y_pred = svm.predict(X_test_pca)
# 利用sklearn的metrics模块,计算分类的准确率
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
return accuracy

# 主程序
if __name__ == '__main__':
import os

# 读取数据集中的图像和标签
images = []
labels = []

dataset_path = r'C:\data\study\second_done\number_safe\exercise4\lfwp\Abel_Pacheco'

for filename in os.listdir(dataset_path):
image_path = os.path.join(dataset_path, filename)
label = filename.split('.')[0] # 使用文件名作为图像标签
image = cv2.imread(image_path) # 读取图像
images.append(image)
labels.append(label)

# 划分训练集和测试集,按照80%和20%的比例
X_train, X_test, y_train, y_test = split_dataset(images, labels, test_ratio=0.2)

# 对测试集中的每个图像,添加拉普拉斯噪声,并还原为图像
images_noisy = []
for i in range(len(X_test)):
image = X_test[i] # 原始图像
magnitude_k, phase_k = dft_image(image) # DFT系数
image_noisy = idft_image(magnitude_k, phase_k) # 带噪声的图像
images_noisy.append(image_noisy)
images_noisy = np.array(images_noisy)

# 划分训练集和测试集,使用带噪声的图像作为测试集,按照80%和20%的比例
X_train_noisy, X_test_noisy, y_train_noisy, y_test_noisy = split_dataset(images_noisy, labels, test_ratio=0.2)

# 进行人脸识别,分别使用原始图像和带噪声的图像,并打印准确率
accuracy_original = face_recognition(X_train, X_test, y_train, y_test)
accuracy_noisy = face_recognition(X_train_noisy, X_test_noisy, y_train_noisy, y_test_noisy)
print('人脸识别分类预测的准确率为:{:.2f}%'.format(accuracy_original * 100))

# # 读取数据集中的图像和标签
# images, labels = read_dataset('dataset')
# # 划分训练集和测试集,按照80%和20%的比例
# X_train, X_test, y_train, y_test = split_dataset(images, labels, test_ratio=0.2)
# # 对测试集中的每个图像,添加拉普拉斯噪声,并还原为图像
# images_noisy = []
# for i in range(len(X_test)):
# image = images[i] # 原始图像
# magnitude_k, phase_k = dft_image(image) # DFT系数
# image_noisy = idft_image(magnitude_k, phase_k) # 带噪声的图像
# images_noisy.append(image_noisy)
# images_noisy = np.array(images_noisy)
# # 划分训练集和测试集,使用带噪声的图像作为测试集,按照80%和20%的比例
# X_train_noisy, X_test_noisy, y_train_noisy, y_test_noisy = split_dataset(images_noisy, labels, test_ratio=0.2)
# # 进行人脸识别,分别使用原始图像和带噪声的图像,并打印准确率
# accuracy_original = face_recognition(X_train, X_test, y_train, y_test)
# accuracy_noisy = face_recognition(X_train_noisy, X_test_noisy, y_train_noisy, y_test_noisy)
# print('原始图像的人脸识别准确率为:{:.2f}%'.format)

实验结果及分析

对检测图片集进行运行

img

运行一段时间后反馈运行结果

img

可以看见反馈结果精准