可逆的分级加密技术在视频隐私保护中的应用
一、摘要
人脸作为一种典型的图像感兴趣区域,是识别一个人的最关键信息,面向视觉感知的分级区域加密增强了加密的针对性和灵活性。本文基于视频的部分加密算法,提出了一种只对监控中的人脸信息进行分级可逆加密并嵌入关键信息的算法,以达到保护实时监控中个人肖像隐私而不影响对监控对象行为判断的目的。本文针对监控视频的每一帧图像,实现了对人脸区域的两级可逆加密,第一级加密后的保留了少量人脸的感知信息,具有一定可识别性,第二级加密后的人脸区域则不包含任何原图像的感知信息。然后通过结合用户不同的类别,进行密钥管理解密人脸区域,我们构造了一个实用的两级加密视频隐私的安全传输方案。
关键词:视频加密;人脸定位;分级可逆加密;隐私保护;密钥管理
文章目录
二、算法设计
1.嵌入过程
人脸定位用OpenCV
2.分级加密过程
3.分级解密过程
三、嵌入算法:预测差值直方图
详见:https://blog.csdn.net/Harbour_zhang/article/details/109155501?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164897905916780261933360%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164897905916780261933360&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-109155501.142v5pc_search_result_cache,157v4control&utm_term=%E9%A2%84%E6%B5%8B%E5%B7%AE%E5%80%BC%E7%9B%B4%E6%96%B9%E5%9B%BE&spm=1018.2226.3001.4187
嵌入最大信息量约为32500bit(1bit/像素),有时能看出图像变化有时不能。但都不影响人脸的正常识别。
#信息嵌入
def zhifang(img,msg):
m = img.shape[0]
n = img.shape[1]
img_hiding = img.astype(np.float)
#为了方便计算,直接把数组长度设置为嵌入容量
N = m * n
predict_value = np.zeros((1, N,3), np.uint8)#零矩阵
predict_error = np.zeros((1, N,3), np.uint8)#零矩阵
predict_expand = np.zeros((1, N,3), np.uint8)#零矩阵
#一个随机01序列,作为此次信息隐藏的秘密信息
secret_msg = np.zeros((1, N,3), np.uint8)
for i in range(N):
secret_msg[0,i] = msg[0,i]
#嵌入
index = 0
for i in range(1,m,2):
for j in range(1,n-1,2):
# 计算左右两个像素的均值,作为预测值
predict_value[0,index] = np.round((img[i,j-1] + img[i,j+1])/2)
# 得到预测误差
predict_error[0,index] = img[i,j] - predict_value[0,index]
predict_expand[0,index] = predict_error[0,index]
index = index + 1
# 将秘密信息嵌入误差直方图,构成扩展预测误差直方图
#predict_expand = predict_error.copy()
# 选择阈值 T = 5
T = 5
#print(predict_expand.shape)
for i in range(0,N):
if all(predict_error[0,i] >= -1 * T) and all(predict_error[0,i] < T) :
t1 = 2 * predict_error[0,i]
t2 = secret_msg[0,i]
#t2 = secret_msg[i]
predict_expand[0,i] =t1 + t2
#predict_expand[0,i] = 2 * predict_error[0,i] + secret_msg[0,i]
elif all(predict_error[0,i] >= T):
predict_expand[0,i] = predict_error[0,i] + T
else:
predict_expand[0,i] = predict_error[0,i] - T
# 将嵌入秘密信息后的预测误差直方图转移回载体图像
index = 0
for i in range(1,m,2):
for j in range(1,n,2):
img_hiding[i,j] = predict_value[0,index] + predict_expand[0,index]
index = index + 1
CRGB=img_hiding.astype(np.uint8)
#cv2.imshow("insert",CRGB)
#cv2.imwrite(path3, CRGB,[int(cv2.IMWRITE_PNG_COMPRESSION), 9])
return CRGB,secret_msg
#信息提取
def extract(img):
m = img.shape[0]
n = img.shape[1]
img = img.astype(np.float)
# 为了方便计算,直接把数组长度设置为嵌入容量
N = m * n
extract_msg = np.zeros((1, N,3), np.uint8)#零矩阵
predict_value = np.zeros((1, N,3), np.uint8)#零矩阵
predict_error = np.zeros((1, N,3), np.uint8)#零矩阵
predict_expand = np.zeros((1, N,3), np.uint8)#零矩阵
# 先进行同样的预测,得到预测序列
index = 0
for i in range(1,m,2):
for j in range(1,n-1,2):
# 计算左右两个像素的均值,作为预测值
predict_value[0,index] = np.round((img[i,j-1] + img[i,j+1])/2)
# 得到预测误差
predict_expand[0,index] = img[i,j] - predict_value[0,index]
index = index + 1
# 恢复预测误差并提取秘密信息
# 选择阈值 T = 5
T = 5
#print(predict_expand.shape)
for i in range(0,N):
if all(predict_expand[0,i] >= -2 * T) and all(predict_expand[0,i] < 2 * T) :
predict_error[0,i] = np.floor(predict_expand[0,i] / 2)
extract_msg[0,i] = abs(predict_error[0,i] - np.floor(predict_expand[0,i] / 2))
elif all(predict_expand[0,i] >= 2 * T):
predict_error[0,i] = predict_error[0,i] - T
else:
predict_expand[0,i] = predict_error[0,i] + T
# 恢复图像
index = 0
for i in range(1,m,2):
for j in range(1,n,2):
img[i,j] = img[i,j] + predict_error[0,index]
index = index + 1
CRGB=img.astype(np.uint8)
return CRGB,extract_msg
四、第一级加密:Arnold_new变换(原创)
Arnold变换详见:https://blog.csdn.net/qq_41137110/article/details/115664882
由于arnold映射的结果只有迭代次数和位置映射参数有关,本身安全性不是很高,而我们的第一级加密需要保留部分人脸特征,这就导致我们迭代次数和位置映射参数的值偏小,非常容易暴力破解出来。所以我们提出了一种基于arnold的改进算法arnold_new。
从图11的测试集中可以看出,经过第一级加密之后,无法识别具体人像,但保留大部分人脸特征,如嘴巴、鼻子等。
Arnold_new暴力破解测试效果
在d=100的情况下,进行测试,选取a,b以及l取值的最优解。
用已有的arnold加密及解密效果:
用arnold_new对人脸部分进行加密,用arnold反映射进行暴力破解,测试a,b以及l的最优解。部分结果如下。
当l=5时,加解密效果,如下图可以看出没有解密成功。人眼可以辨别出人脸,但是不知道机器可不可以,我们不妨测试一下,绿色框起来的部分为机器识别出的人脸。可知,安全性还是很低。
当l=10时,加解密效果如下图,可以看出没有解密成功,得到的是一张扭曲的人脸。人眼可以辨别出是一张扭曲人脸,不确定机器能不能将它识别出来,我们不妨测试一下,绿色框起来的部分为机器识别出的人脸。但是但从肉眼辨别效果上来说,这次暴力破解是失败的,因为我们无法直接认出这是谁。但这还不是安全的,因为它的人脸特征保留较多,我们仍有可能猜测出这是谁。
当l=16时,加解密效果如下图。可以看出没有解密成功,得到的是一张扭曲且杂乱的人脸。人眼不能辨别这张人脸,不确定机器能不能将它识别出来,我们不妨测试一下,绿色框起来的部分为机器识别出的人脸。识别结果,部分可以被识别出来,部分不行不行。结果很惊讶,它居然还能被识别出来,我们认为这是因为它还有一定的脸型及五官轮廓。但是但从肉眼辨别效果上来说,这次暴力破解是失败的,因为我们无法直接认出这是谁。我们认为这它是安全的,因为它虽然保留了一定客观性的人脸特征,但是我们几乎无法辨认出这是谁了。
综上所述,l在[a,b)区间内,a的最优值是16,约占方阵行数的1/6。同理测试出b的最优值是25,约占方阵行数的1/4。所以l的合理范围是1/6~1/4方阵行数。经过Arnold_new映射算法加密后的Arnold人脸加密区域可以抗暴力攻击,Arnold_new映射算法被暴力破解后,得到的还原视频帧中会有一定数量的像素点错乱,攻击者得到的还原视频帧中不具备人脸所有的面部特征,能阻碍肉眼分辨和机器分辨,实现了抗攻击性。
代码如下:
#arnold 防暴力破解
def new_arnold(img,k1):
r = img.shape[0]
c = img.shape[1]
print(img.shape)
key = []#随机序列
for t in k1:
if t < r :
key.append(t)
k2 = len(key)
#print(key)
#print(k2)
r1 = r - k2
c1 = c - k2
p = np.zeros((r, c,3), np.uint8)#零矩阵
q = np.zeros((r1, c1,3), np.uint8)#零矩阵
w = np.zeros((r1, c1,3), np.uint8)#零矩阵
print(p.shape)
a = 1
b = 1
g = 0
#原图中随机要映射的行列重新合成一个矩阵q
for e in range(r):
h = 0
#print("g==",g)
for f in range(c):
if e not in key and f not in key :
q[g][h] = img[e][f]
#print(f)
h = h + 1
if h == c1:
g = g + 1
#映射
for i in range(r1):
for j in range(c1):
x = (i + b * j) % r1
y = (a * i + (a * b + 1) * j) % c1
w[x, y] = q[i, j]
#合并映射后的像素与没有经过映射的像素
acount_x = 0 #q矩阵已合并像素点位置标记
for e2 in range(r):
acount_y = 0 #q矩阵已合并像素点位置标记
for f2 in range(c):
if e2 not in key and f2 not in key:#映射像素点
p[e2][f2] = w[acount_x][acount_y]
acount_y = acount_y + 1
if acount_y == c1:# q矩阵下一行
acount_x = acount_x + 1
else:#没有映射像素点
p[e2][f2] = img[e2][f2]
return p
def new_de_arnold(img,k1):
r = img.shape[0]
c = img.shape[1]
print(img.shape)
key = []#随机序列
for t in k1:
if t < r :
key.append(t)
k2 = len(key)
#print(key)
#print(k2)
r1 = r - k2
c1 = c - k2
p = np.zeros((r, c,3), np.uint8)#零矩阵
q = np.zeros((r1, c1,3), np.uint8)#零矩阵
w = np.zeros((r1, c1,3), np.uint8)#零矩阵
print(p.shape)
a = 1
b = 1
#分离出经过映射的像素点所构成的矩阵w
acount_x = 0 #w矩阵已合并像素点位置标记
for e2 in range(r):
acount_y = 0 #w矩阵已合并像素点位置标记
print(acount_x)
for f2 in range(c):
if e2 not in key and f2 not in key:#映射过的像素点
w[acount_x][acount_y] = img[e2][f2]
acount_y = acount_y + 1
if acount_y == c1:# w开始矩阵下一行
acount_x = acount_x + 1
#反映射,得到q
for i in range(r1):
for j in range(c1):
x = ((a * b + 1) * i - b * j) % r1
y = (-a * i + j) % c1
q[x,y] = w[i,j]
#合并解密后的像素与没有经过映射的像素
acount_x = 0 #q矩阵已合并像素点位置标记
for e2 in range(r):
acount_y = 0 #q矩阵已合并像素点位置标记
for f2 in range(c):
if e2 not in key and f2 not in key:#映射像素点
p[e2][f2] = q[acount_x][acount_y]
acount_y = acount_y + 1
if acount_y == c1:# q矩阵下一行
acount_x = acount_x + 1
else:#没有映射像素点
p[e2][f2] = img[e2][f2]
return p
五、第二级加密:异或加密
异或加密过程如下:
(1)生成m*n的伪随机序列;
(2)分RGB三通道提取图像矩阵;
(3)对每个分量的所有像素与伪随机序列进行异或;
(4)将异或操作后的三通道合并;
(5)得到加密的图像;
经过第二级加密之后,图像变为噪声图,完全不可辨认,具有较高的安全性,
异或解密过程:
(1)分RGB三通道提取图像矩阵;
(2)对每个分量的所有像素与加密过程中用到的伪随机序列进行异或;
(3)将异或操作后的三通道合并;
(4)得到解密的图像;