关于用python opencv模拟ai人脸欺诈的探索

——第一期:关于制作简单动态眨眼

一、探索背景

随着人工智能的发展,ai人脸识别已经成为人工智能应用中不可缺少的一部分,各行各业都开始用这个新兴技术,减少审核成本,增加审核效率,可是人工智能毕竟跟人还是有差别的,因为人工智能的对人脸的判断是通过无数算法跟模型训练,才会越来越精确,所以有很多人为看起来非常假的图,人工智能计算后是可以通过的。

比如一张人脸,假设是否是本人人脸的两个判断条件是:1、人脸跟本人身份证照片相似度达90%。2、检测的人是个活体。满足这两个条件ai的判断就是通过,但是这两个条件其实都是可以伪造的,比如说找本人的图片,通过技术手段让眼睛嘴巴动起来,ai就会判断成活体,并且与本人相似度很高,因此就通过了,这种情况我们称为ai人脸欺诈。

所以本期的探索就是通过opencv让静态人脸上的眼睛动起来,从而模仿照片为本人且是活体的效果,模拟ai人脸欺诈。

二、需要用到的第三方依赖库

OpenCV

OpenCV是一个跨平台的计算机视觉库,是开源的,可以应用在主流操作系统上,例如:Linux、windows、Android和Mac os操作系统上。它由一系列的c函数和少量的c++类构成,同时也提供了Python、Ruby、MATLAB等接口,实现了图像处理和计算机视觉方面的很多通用算法。本次的模拟ai人脸欺诈,主要用的就是这个开源库。

Pillow 与PIL

PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。PIL功能非常强大,但API却非常简单易用。 由于PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了许多新特性,因此,我们可以直接安装使用Pillow。

三、环境的搭建

python版本:2.7

版本依赖库:

pip:9.0.1
$brew install pip
安装pillow:5.0.0
$pip install pillow
安装pillow-PIL 0.1dev
$pip install pillow
numpy 1.14.1
$pip install numpy

这里可能会遇到已经安装numpy1.0.8rc1无法卸载的问题,请参考链接: http://blog.csdn.net/hqzxsc2006/article/details/51602654

OpenCV-python 3.3.0.10
$brew install OpenCV

如果遇到Permissiondenied安装失败,请加上sudo重试。 除了以上的版本,还需要一个python编辑器,推荐用pycharm。

亲测在真实环境下搭建环境过程比较繁琐,而且容易遇到各种问题。建议通过pycharm搭建一个虚拟环境来实现。

四、用python实现静态图变动态图

首先附上静图变动图的源码:

#静态图片变动图代码
import os
import numpy
from PIL import Image, ImageDraw
import cv2
left = cv2.imread("/Users/aa/PycharmProjects/untitled1/left.png")
right = Image.open("/Users/aa/PycharmProjects/untitled1/right.png")
classifier = cv2.CascadeClassifier("/Users/aa/PycharmProjects/untitled1/haarcascade_eye.xml")
count = 0
while count > -1:
    img = cv2.imread("/Users/aa/PycharmProjects/untitled1/timg.jpg")
    Face = img[55:136, 170:255]
    eyeRects = classifier.detectMultiScale(img, 1.2, 2, cv2.CASCADE_SCALE_IMAGE, (20, 20))
    key = cv2.waitKey(1)
    if len(eyeRects) > 0:
        for faceRect in eyeRects:
            x, y, w, h = faceRect
            cv2.rectangle(img, (int(x), int(y)), (int(x) + int(w), int(y) + int(h)), (0, 255, 0), 2, 0)
            ex_show=cv2.resize(left,(w,h),interpolation=cv2.INTER_CUBIC)
            #Y1=y+55
            #Y2=(y+h)+55
            #X1=x+170
            #X2=(x+w)+170
            if key == ord('p'):
               #img[ Y1:Y2, X1:X2]=ex_show
               #Face[y:y+h, x:x+w]=ex_show
               img[y:y+h, x:x+w]= ex_show
    cv2.imshow('video', img)
    cv2.resizeWindow('video',1280,720)
    if key == ord('q'):
        break
cv2.destroyAllWindows()

以上内容及代码均基于网上搜索和参考别人的代码,结合我的思考和理解,自己写的代码,下面内容会解析代码每一句代表的意义以及作用,并且我也绘制了一些数学模型图,帮助大家对眼睛识别及替换的原理有更深刻的理解。

首先我们先导入依赖库,用它的image跟ImageDraw包来处理图片

import os

import numpy

from PIL import Image, ImageDraw

import cv2

然后先读取一张主图:

img = cv2.imread("/Users/aa/PycharmProjects/untitled1/timg.png")

格式为:img = cv2.imread("文件路径"),默认是彩色的,如果想要灰色可以这样设置:img=cv2.imread("文件路径",0),后面的参数决定图片的色彩。

然后我们再用:

cv2.imshow('video', img)

来查看图片是否显示正常,显示的结果是这样子的:

34c492850f998791c9c78d0aa34d91fe.png

导入成功,想要眼睛动起来,首先我们得先识别出眼睛所在的区域。这时候可以用一个现成的经过训练的人眼识别xml帮助,文件名字:haarcascade_eye.xml,这个xml在网上也能找到,导入这个xml并建立一个对象。

classifier = cv2.CascadeClassifier("/Users/dingjingjing058/Downloads/haarcascade_eye.xml")

通过对象调用xml的detectMultiScale函数并且赋值给一个变量。

eyeRects = classifier.detectMultiScale(img, 1.2, 2, cv2.CASCADE_SCALE_IMAGE, (20, 20))

这条代码的意思,就是在整张图片中,识别出人眼的区域。

detectMultiScale这个函数的用法我就不详细说了,粗略的说一下每一个参数的意义:

detectMultiScale函数介绍:
参数1:image--待检测图片,一般为灰度图像加快检测速度
参数2:objects--被检测物体的矩形框向量组;
参数3:scaleFactor--表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%;
参数4:minNeighbors--表示构成检测目标的相邻矩形的最小个数(默认为3个)。 如果组成检测目标的小矩形的个数和小于minneighbors - 1 都会被排除。如果minneighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,这种设定值一般用在用户自定义对检测结果的组合程序上;
参数5:flags--flags--要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因此这些区域通常不会是人脸所在区域;
参数6、7:minSize和maxSize用来限制得到的目标区域的范围。

然后就是把识别出来的人眼区域画一个矩形,画矩形的代码是这样的:

cv2.rectangle(img, ((x1,y1) , (X2,Y2), (0, 255, 0), 2, 0)

其中X1,Y1是矩形的左上角坐标,X2,Y2是矩形的右下角坐标。根据这个坐标来绘制一个矩形。

可是我们怎么根据人眼识别的点来画矩形呢?用一个for循环在xml里遍历一下faceRect这个函数,遍历的代码就这样:

 if len(faceRects) > 0:

    for faceRect in eyeRects:

        x, y, w, h = eyeRect

        cv2.rectangle(img, (int(x), int(y)), (int(x) + int(w), int(y) + int(h)), (0, 255, 0), 2, 0)

可能比较抽象,我们就以图画一个坐标,原点为右上角的点,图像的宽为x轴,高为y轴,然后画矩形就是用x跟y轴的坐标。

原理图如下,上述代码就会绘制出来下面的这幅图。


87cd3d2523f3558e06736805437a4960.png

然后我们再来运行后的人眼识别结果,识别成功:


bf77601b1e7ab5f69900a16614f4196b.png

识别成功以后,怎么把这个静态图片变成一个动态的图片呢?这时候我们就需要替换矩形内部的图像,首先先把要换图的区域给定位出来,用这部分代码定位:

img[ y:(y + h), x:(x + w)]

这行代码的意思是把y1=y y2=y+h,x1=x ,X2=x+w,把这四根线重叠的部分给抠出来,如下图黑色阴影部分:


e2fcefdc7aac9e352dd09d9a2ab5a861.png

然后再置换成另外一张图片,我们首先导入要替换眼睛部分的图片,并让图片适应框的大小。

ex_show=cv2.resize(left,(w,h),interpolation=cv2.INTER_CUBIC)

然后把刚刚圈出来的那个区域,替换成这张图片:

img[ y:(y + h), x:(x + w)]=ex_show

然后就大功告成,效果如下图所示:


d4ee1ceae2b75072d16159bb4f9d7f6d.png

然后怎么让这个图动起来呢,我们就设定按键盘某个按键的时候,这张图片才会替换,这样不断按这个按钮,图片就变成动图啦。

if key == ord('p'):

          img[ y:(y + h), x:(x + w)]=ex_show

这样一幅动态识别替换眼睛部分的动图就完成啦,这样就可以用静态图片不断替换眼睛部分以营造是活体的效果,从而瞒过人工智能。

五、识别准确度优化的实现

以上内容是我对源码的思考和理解,以下内容是我在源码的基础上自己写的一些优化代码,让眼部的识别更加精准。

虽然我们成功的完成了人眼识别并替换其他图片,但是我们都发现,上图的识别部分不太准确,有一部分已经识别到腋下去了,那么我们怎么让识别范围更加的准确呢?

小编的想法就是,框定一个区域,比如说人脸,然后让眼睛识别就在这个区域内进行,这样的话准确度会大大的提高。

于是决定先把人脸部分的坐标先抠出来:

Face = img[55:136, 170:255]

然后在抠出来的图里面进行遍历,识别人眼。

if len(faceRects) > 0:

    for faceRect in eyeRects:

        x, y, w, h = faceRect

        cv2.rectangle(Face, (int(x), int(y)), (int(x) + int(w), int(y) + int(h)), (0, 255, 0), 2, 0)

然后再运行一下,我们发现已经把矩形准确的定位到眼睛的部分啦。


f611b7d068c8a40b5ee9470d31fe6c96.png

但是这时候我们发现运行程序,会发现替换图片的时候跑偏了。为什么会跑偏呢?原来我们在抠出来的图中画矩形的时候,矩形已经不是以整个图片为原点,而是以抠出来的图的左上角坐标为原点,这时候的x,y是相对于坐标(55,170)而设置的,再来看我们替换图片的代码:

img[ y:(y + h), x:(x + w)]=ex_show

但是我们替换图片的时候,仍然是以原图为参考的,这时候的x,y识别到的 是以原图左上角为原点,x,y为矩形左上角点的部分。这时候我们得把抠出来的图的坐标再还原到原图上,从而识别替换部分的坐标:


b60bf26acc1f488cf0be97f3ac402845.png

所以替换图片的坐标应该改成这样:

Y1=y+55

Y2=(y+h)+55

X1=x+170

X2=(x+w)+170

if key == ord('p'):

   img[ Y1:Y2, X1:X2]=ex_show

其实还有一种更加简单的方式,没错就是直接把替换区域也改成以抠出来的图为参考:

Face[y:y+h, x:x+w]=ex_show       

这样一幅准确的人眼识别动图就做出来啦!


2b5aa56c9c578d6a6f395339e3dff2a1.png

这段代码中抠出来的人脸坐标是写死的只是为了更便于理解它的精确过程,之后可以换成智能人脸识别,先把人脸识别出来,然后把人脸的部分抠出来再进行人眼识别,其实跟上述的原理一样的,只不过把写死的这个坐标img[55:136,170:255]替换成变量坐标而已。

最后,本期只是做一个特别基本的尝试探索,在这个过程中也遇到了许多问题,环境上,遇到了很多环境搭建的问题,比如说安装了以后仍然无法导入image跟imageview的包,最后通过搭建虚拟环境解决了问题,比如人眼识别不太精准总是识别到其他东西。这期做的只是一个非常简单的人眼识别然后替换的实现,后期会尝试实现人眼蒙版过渡得更自然-接近于真实人眼的睁眼闭眼的模拟,然后让识别更加的精确,不会识别到别的地方。后期会尝试加上嘴巴的识别,让静态图片的嘴巴实现动态张闭,以及静态图摇头的功能的实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 图像和视频分析 原文:Images and Video Analysis 译者:飞龙 协议:CC BY-NC-SA...
    布客飞龙阅读 14,304评论 0 94
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • GitHub 上有一个 Awesome - XXX 系列的资源整理,资源非常丰富,涉及面非常广。awesome-p...
    若与阅读 18,591评论 4 418
  • 堂庭山 招摇山之东三百里为堂庭山,山上有很多棪木、白猿、水玉和黄金。
    司契阅读 142评论 0 0
  • 熊熊的火焰, 烘烤着我的脸。 金色和红色交错着, 直冲我的眼睑。 它闪着刺眼的金光, 它带着炙热的红阳。 它是太阳...
    灯火扰乱阅读 167评论 0 0