在AB测试中尝试进行面部蒙太奇
A和B,你更喜欢哪个面孔?
进行A/B测试是指准备了两种不同模式的网页,让真实用户使用并比较其效果的测试。
展示微妙不同版本的页面给数千名访问网站的用户中的一位,然后比较点击率等与通常版本的差异。如果结果比通常版本好,就采用它作为新的通常版本,并进行进一步的微小改动来进行测试…
A/B测试,大致上是这种方法。
这个方法也因奥巴马总统在选举中使用过而出名。
这个与针对大规模用户的一般A/B测试有一点不同,但是通过面部蒙太奇试图做出类似A/B测试的东西就是这个。
AB face是一个在线的网页应用程序的网址,可以通过http://xiidec.appspot.com/abface.html访问。
点击A或B中喜欢的脸。
然后选中的脸将保留,并提供新的选择。
通过连续选择,理想的脸将逐渐形成。
机构组织
那么,现在我们来看一下实际内容吧。
只有150行而已。是的,我们能够做到。
-
- 准备一些眉毛、眼睛、鼻子、嘴巴的图像并给它们编号。
- 随机选择每个部分。
首先是服务器端。使用Python语言编写的代码。
翻译为中文后的句子如下:咖喱汁
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import webapp2
import os
import random
from google.appengine.ext.webapp import template
from google.appengine.api import memcache
class Abface(webapp2.RequestHandler):
def get(self):
self.draw()
def post(self):
if not self.request.get('choice') is None and self.request.get('choice')!="":
memcache.set("face",[int(i) for i in self.request.get('choice').split(",")], 3600)
memcache.set("sel",self.request.get('sel'), 3600)
self.draw()
def draw(self):
face1 = self.makeface()
face2=[i for i in face1]
r=random.randint(0,3)
face2[r] = int(random.choice("12345".replace(str(face2[r]), "")))
if memcache.get("sel")=="B":
face1,face2=face2,face1
template_values={
'brow1':'brow_' + str(face1[0]) + '.jpg',
'eye1':'eye_' + str(face1[1]) + '.jpg',
'nose1':'nose_' + str(face1[2]) + '.jpg',
'mouth1':'mouth_' + str(face1[3]) + '.jpg',
'brow2':'brow_' + str(face2[0]) + '.jpg',
'eye2':'eye_' + str(face2[1]) + '.jpg',
'nose2':'nose_' + str(face2[2]) + '.jpg',
'mouth2':'mouth_' + str(face2[3]) + '.jpg',
'face1':",".join(map(str,face1)),
'face2':",".join(map(str,face2)),
}
path = os.path.join(os.path.dirname(__file__), 'html/abface.html')
self.response.out.write(template.render(path, template_values))
def makeface(self):
face = memcache.get("face")
if face is None:
face = [random.randint(1,5) for i in range(4)]
memcache.set("face", face, 3600)
return face
app = webapp2.WSGIApplication([
('/abface.html', Abface)
], debug=True)
首先,当用户访问时调用的是get()方法。
get()方法会调用draw()方法。结束。
所以,draw()方法的内容。这里是生成页面。
首先在第一行调用makeface()函数。一直被耍来耍去的感觉。
生成表情()。这里的关键是memcache。
时间一过,就会消失的缓存。
“face”关键字当前应该是一个包含最优表情[1,3,4,5]的数组(应该是)。
这个数组表示眉毛为1号,眼睛为3号,鼻子为4号,嘴巴为5号。
数据可能存储了类似的内容…但也可能没有存储。不能保证。
因为memcache是缓存,所以它可能已经消失了。
所以,如果face为空,就随机生成一个表情并保存。寿命为3600秒=1小时。
如果想永久保存,就必须保存在真正的数据库中,但由于这只是个娱乐项目,消失了也没关系。
因此返回draw()。
根据makeface()创建的脸部特征,对眉毛、眼睛、鼻子或嘴巴中的其中一个进行修改。这是另一种选择。
这里又出现了memcache。如果上次选择的脸部是B,那么将脸1和脸2互换。
然后将值设置到模板中,并传递给客户端。
这就是服务器端的脸部显示机制。
最后对post()进行解释。接收来自客户端的AB选择和选择的面部组合,并将其设置到memcache中。
接下来是客户端。
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<title>ABface</title>
<style>
#canv1,#canv2 {
border: solid 3px #000;
border-radius: 25px 25px 25px 25px / 25px 25px 25px 25px;
border-color: #ff0000;
}
#canv2 {
border: solid 3px #000;
border-radius: 25px 25px 25px 25px / 25px 25px 25px 25px;
border-color: #0000ff;
}
#canv1:hover {
box-shadow: 0px 0px 20px 5px #ff0000
}
#canv2:hover {
box-shadow: 0px 0px 20px 5px #0000ff
}
#main {
width: 100%;
text-align : center
}
.hid{
display:none;
}
</style>
</head>
<body>
<div id="main">
<h1><span style="color:#ff0000">A</span> or <span style="color:#0000ff">B</span></h1>
<canvas id="canv1" width="150" height="150"></canvas>
<canvas id="canv2" width="150" height="150"></canvas>
</div>
<form action="/abface.html" method="post" id ="frm">
<input type="text" name="choice" id="choice" value="" style="display:none">
<input type="text" name="sel" id="sel" value="" style="display:none">
</form>
<img src="img/face/{{ brow1 }}" id ="brow_1" class="hid">
<img src="img/face/{{ eye1 }}" id ="eye_1" class="hid">
<img src="img/face/{{ nose1 }}" id ="nose_1" class="hid">
<img src="img/face/{{ mouth1 }}" id ="mouse_1" class="hid">
<img src="img/face/{{ brow2 }}" id ="brow_2" class="hid">
<img src="img/face/{{ eye2 }}" id ="eye_2" class="hid">
<img src="img/face/{{ nose2 }}" id ="nose_2" class="hid">
<img src="img/face/{{ mouth2 }}" id ="mouse_2" class="hid">
<script>
var ctx1 = document.getElementById('canv1').getContext('2d');
var ctx2 = document.getElementById('canv2').getContext('2d');
var face1 = "{{ face1 }}"
var face2 = "{{ face2 }}"
function makeface(){
ctx1.drawImage(document.getElementById('brow_1'), 0, 0)
ctx1.drawImage(document.getElementById('eye_1'), 0, 25)
ctx1.drawImage(document.getElementById('nose_1'), 0, 50)
ctx1.drawImage(document.getElementById('mouse_1'), 0, 110)
ctx2.drawImage(document.getElementById('brow_2'), 0, 0)
ctx2.drawImage(document.getElementById('eye_2'), 0, 25)
ctx2.drawImage(document.getElementById('nose_2'), 0, 50)
ctx2.drawImage(document.getElementById('mouse_2'), 0, 110)
}
window.onload = function(){
makeface()
$("#canv1").bind("click",function(){
ctx1.beginPath();
ctx1.lineWidth = 10;
ctx1.strokeStyle="#ff0000";
ctx1.arc(75, 75, 50, 0, Math.PI*2, false)
ctx1.stroke();
$("#choice").val(face1);
$("#sel").val("A");
$('#frm').submit();
});
$("#canv2").bind("click",function(){
ctx2.beginPath();
ctx2.strokeStyle="#0000ff";
ctx2.lineWidth = 10;
ctx2.arc(75, 75, 50, 0, Math.PI*2, false)
ctx2.stroke();
$("#choice").val(face2);
$("#sel").val("B");
$('#frm').submit();
});
}
</script>
</body>
</html>
首先要看的是makeface()函数。
将图片粘贴在画布上。
将图片粘贴在两个画布上。
IMG元素根据从服务器端接收到的部件编号切换URL。
显示的部分如下。
下面是当点击画布时的事件。
虽然有各种各样的处理,但因为是外观问题,所以可以基本忽略。
最重要的是最后三行。
设置所选组件、设置A或B,然后点击提交。
然后服务器端会调用post()函数。
以上就可以创建类似AB测试的东西了。
总结
如果能够增加零件的种类并选择轮廓、发型和布局等,梦想可能会变得更加广阔。
所有的素材都是用女性的脸来制作的,但最后得到的却是一张张男性的脸。
或许是因为部分的布局平衡问题吧。