maxc1017 发表于 2018-9-20 06:12:06

golang微信公众平台之人脸识别

  好吧,其实整个都是建立在face++的基础上的,没有任何技术含量,我只是个勤劳的搬运工。
  所能实现的就是简单的,你发送一个图片过来,如果里面是一个人,则告诉你分析出来的年龄、性别;如果是两个人,就告诉你,这两个人眉毛、眼睛、鼻子、嘴巴及整体的相似度。
  微信公众平台,怎么说呢,还是传统的一问一答的形式,你发个信息过来,我收到了处理下,再给你回馈一条信息,就是这么简单。
  简单的你来我往
  先说信息互传的问题,微信公众平台是post过来一个xml,服务器端打包一个xml发回去。
  从最简单的,直接把用户信息返回去搞起吧。
文本消息
  

  

  
1348831860
  

  

  
1234567890123456
  

  

  


参数
描述ToUserName
开发者微信号FromUserName
发送方帐号(一个OpenID)CreateTime
消息创建时间 (整型)MsgType
textContent
文本消息内容MsgId
消息id,64位整型  相应的数据结构也就自然出来了:

type Request struct{  
ToUserName
string  
FromUserName
string  
CreateTime time.Duration
  
MsgType
string  
Content
string  
MsgId
int  
}
  将输入的xml解码:
func decodeRequest(data []byte)(req *Request,err error){  
req
=&Request{}  
err
=xml.Unmarshal(data,req)  

return  
}
  虽然微信服务器是用post方式传递的数据,不过实际还通过url传递过来了三个参数:signature,timestamp,nonce.
  这三个参数可以验证消息是否微信服务器发送过来的。
  取post过来的数据:
func Action(w http.ResponseWriter,r *http.Request){  
postedMsg,err:
=ioutil.ReadAll(r.Body)  

if err!=nil{  
log.Fatal(err)
  
}
  
r.Body.Close()
  
msg,err:
=decodeRequest(postedMsg)  
...
  
}
  接下来就是回复信息

回复文本消息
  

  

  
12345678
  

  

  
0
  

  

  

  参数

描述ToUserName
接收方帐号(收到的OpenID)  FromUserName

开发者微信号CreateTime
消息创建时间  MsgType

textContent
回复的消息内容,长度不超过2048字节FuncFlag
位0x0001被标志时,星标刚收到的消息  简单封装下:

type Response struct{  
XMLName xml.Name `xml:
"xml"`  
ToUserName
string  
FromUserName
string  
CreateTime time.Duration
  
MsgType
string  
Content
string  
FuncFlag
int  
}
  

  
func encodeResponse(resp Response)(data []
byte,err error){  
resp.CreateTime
=time.Second  
data,err
=xml.Marshal(resp)  

return  
}
  将数据发送回去的代码:
var resp Response  
resp.ToUserName
=msg.FromUserName  
resp.FromUserName
=msg.ToUserName  
resp.MsgType
="text"  
resp.Content
=msg.Content  
resp.FuncFlag
=0  

  
respData,err:
=encodeResponse(resp)  
fmt.Fprintf(w,
string(respData))  人脸识别
  这个怎么说,就是用户通过微信发送照片,照片是存到微信服务器的,微信给我发一个图片url,我再把这个url转给face++,face++将分析结果给我发回来,我再把这些数据简单处理下,反馈给微信用户(当然,中间还隔了层微信服务器)。
  整个过程中,我所做的就是简单的json数据处理,什么高端的图像处理什么的都跟我不沾边,哈哈~
  首先当然是到http://cn.faceplusplus.com/注册,获取API_SECRET、API_KEY。
  而后推荐看文档,http://cn.faceplusplus.com/dev/getting-started/api2info/,当然直接跟着我来一遍也行。
  先来个人脸检测吧,检测出性别、年龄、种族。
  看了示例文档后,发现detect调用后返回的json的结构表示出来大概是这样:
type>
Face []struct{  
Attribute
struct{  
Age
struct{  
Range float64
  
Value float64
  
}
  
Gender
struct{  
Confidence float64
  
Value
string  
}
  
Race
struct{  
Confidence float64
  
Vaule
string  
}
  
}
  
Face_id
string  
Position
struct{  
Center
struct{  
X float64
  
Y float64
  
}
  
Eye_left
struct{  
X float64
  
Y float64
  
}
  
Eye_right
struct{  
X float64
  
Y float64
  
}
  
Height float64
  
Mouth_left
struct{  
X float64
  
Y float64
  
}
  
Mouth_right
struct{  
X float64
  
Y float64
  
}
  
Nose
struct{  
X float64
  
Y float64
  
}
  
Width float64
  
}
  
Tag
string  
}
  
Img_height
int  
Img_id
string  
Img_width
int  
Session_id
string  
url
string  
}
  解析json数据:
func DecodeDetect(data []byte)>
var f>
json.Unmarshal(data,&f)  

return f  
}
  接着还是来写个get函数吧:
func get(url string)(b []byte,err error){  
res,e:
=http.Get(url)  

if e!=nil{  
err
=e  

return  
}
  
data,e:
=ioutil.ReadAll(res.Body)  

if e!=nil{  
err
=e  

return  
}
  
res.Body.Close()
  

return data,nil  
}
  调用face++接口并返回相应的数据:
const apiurl="https://apicn.faceplusplus.com"  

  
func DetectionDetect(picurl
string)detection.Faceslice{  
url:
=apiurl+"/v2/detection/detect?url="+picurl+"&api_secret="+apisecret+"&api_key="+apikey  
tmp,_:
=get(url)  

return detection.DecodeDetect(tmp)  
}
  刚刚上面的示例只是简单考虑了文本信息,现在要传递的是图片信息,所以做个简单的修改:
type Request struct{  
ToUserName
string  
FromUserName
string  
CreateTime time.Duration
  
MsgType
string  
Content
string  
PicUrl
string  
MsgId
int  
}
  Action函数里也该有所修改,判定下msg.MsgType,如果是text,则跟刚才一样处理,如果是image,则有新的处理方法。
  我一个就做了两个简单的处理,一个是年龄、性别、种族,还有就是如果照片里是两个人,则给出五官及整体的相似度值。
  相似度的代码直接放下面吧:
package recognition  

  
import(
  

"encoding/json"  
)
  

  
type Compare
struct{  
Component_similarity
struct{  
Eye float64
  
Mouth float64
  
Nose float64
  
Eyebrow float64
  
}
  
Session_id
string  
Similarity float64
  
}
  

  
func DecodeCompare(data []
byte)Compare{  

var c Compare  
json.Unmarshal(data,
&c)  

return c  
}
func RecognitionCompare(face1id,face2id string)recognition.Compare{  
url:
=apiurl+"/v2/recognition/compare?api_secret="+apisecret+"&api_key="+ apikey+"&face_id2="+face2id+"&face_id1="+face1id  
tmp,_:
= get(url)  

return recognition.DecodeCompare(tmp)  
}
  判定图片里有几个人,一个人输出性别、年龄,两个人输出相似度,三个及以上,暂未判定:
if msg.MsgType=="image"{  

var>
faceslice=facepp.DetectionDetect(msg.PicUrl)  

switch len(faceslice.Face){  

case 0:  
resp.Content
="请上传有脸的人物照片!"  
case 1:
  
attribute:=faceslice.Face.Attribute
  
age:=attribute.Age
  
gender:=attribute.Gender

  
var>  
if gender.Value=="Male"{
  
faceGender="男"
  
}else{
  
faceGender="女"
  
}
  
faceAgeValue:=fmt.Sprintf("%d",int(age.Value))
  
faceAgeRange:=fmt.Sprintf("%d",int(age.Range))
  
resp.Content="性别:"+faceGender+"\n"+"年龄:"+faceAgeValue+"(±"+faceAgeRange+")"
  
case 2:
  
face1id:=faceslice.Face.Face_id
  
face2id:=faceslice.Face.Face_id
  
var compare recognition.Compare
  
compare=facepp.RecognitionCompare(face1id,face2id)
  
resp.Content="眼睛相似度:"+fmt.Sprintf("%f",compare.Component_similarity.Eye)+"\n"+"嘴巴相似度:"+fmt.Sprintf("%f",compare.Component_similarity.Mouth)+"\n"+"鼻子相似度:"+fmt.Sprintf("%f",compare.Component_similarity.Nos    e)+"\n"+"眉毛相似度:"+fmt.Sprintf("%f",compare.Component_similarity.Eyebrow)+"\n"+"整体相似度:"+fmt.Sprintf("%f",compare.Similarity)
  
default:
  
resp.Content="照片里人物太多了,暂不分析!"
  
}
  
}


页: [1]
查看完整版本: golang微信公众平台之人脸识别