图像缩放攻击
今天在B站上看到一个关于图像缩放攻击的挺有意思的视频。
去他的GitHub上复制了源代码来看了看,原理特别简单,核心就是算出缩放点的位置。
比如说有一个8个元素的列表[1, 1, 1, 1, 1, 1, 1, 1],现在我想把其中的两个元素改成0,而且要求这两个0均匀分布在列表之中。
问题就在于选择哪两个位置进行插入了。
可以很简单地看出,第3个位置和第6个位置的1改成0即可,即[1, 1, 0, 1, 1, 0, 1, 1]。
所以现在问题在于,怎么让计算机得到类似的结果。因为计算机只能计算,不能像人一样“一眼看出”,所以结果的产生还是得依赖于计算。
首先第一步,原本有8个元素,改变2个,直观地想,8/2 = 4,每隔4个位置改变一个元素即可。
所以会变成[0, 1, 1, 1, 0, 1, 1, 1]但可以看到,这样的分布并不均匀,总体看,0的分布过于偏左。
因此可以让0们整体往右移动一些。
这其实就是让每一个点位往后挪一些。
那么挪多少呢,我们可以看出挪1或者挪2个位置会比较合适[1, 0, 1, 1, 1, 0, 1, 1]或者[1, 1, 0, 1, 1, 1, 0, 1]。
如果取2,那么刚好是8/2的一半,于是0的位置的通式可以写为map_x = (i + 0.5)*large_length/small_length。当然因为点位是能是整数,所以这个值实际上还需要取个整。
这也就是计算机中图像缩放近邻法的处理方式了,如果有一张1×8像素的图像,我们把它缩放为1×2像素的图片,那么计算机会只取“0”所在的位置的像素,而直接舍去“1”所在位置的像素,形成一张缩放后的图片。
可以看到和人眼“一眼看出”的结果还是有些差异的。
利用这一特性,我们就可以在缩放后会被保留的点位上篡改一下像素,比如把另一张图片的像素放在这些点位上,于是原图缩小后,就会变成我们加入的这“另一张图片”了
下面是up主在GitHub上留下的源码:
import sys
from PIL import Image
#将small_img中的像素用近邻法嵌入到big_img中
def my_nearest_resize(big_img, small_img):
big_w, big_h = big_img.size
small_w, small_h = small_img.size
dst_im = big_img.copy()
stepx = big_w/small_w
stepy = big_h/small_h
for i in range(0, small_w):
for j in range(0, small_h):
map_x = int( i*stepx + stepx*0.5 )
map_y = int( j*stepy + stepy*0.5 )
if map_x < big_w and map_y < big_h :
# 这里是往大图的缩放点所在位置插入小图的像素点
# 但上面这个判断我是真没看懂有什么必要。
dst_im.putpixel( (map_x, map_y), small_img.getpixel( (i, j) ) )
return dst_im
if __name__ == '__main__':
big_img=Image.open(sys.argv[1]) # 大图
small_img=Image.open(sys.argv[2]) # 小图
dst_im = my_nearest_resize(big_img, small_img)
dst_im.save(sys.argv[3]) # 嵌入小图像素的大图