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

好吧,其实整个都是建立在face++的基础上的,没有任何技术含量,我只是个勤劳的搬运工。

所能实现的就是简单的,你发送一个图片过来,如果里面是一个人,则告诉你分析出来的年龄、性别;如果是两个人,就告诉你,这两个人眉毛、眼睛、鼻子、嘴巴及整体的相似度。

微信公众平台,怎么说呢,还是传统的一问一答的形式,你发个信息过来,我收到了处理下,再给你回馈一条信息,就是这么简单。

简单的你来我往

先说信息互传的问题,微信公众平台是post过来一个xml,服务器端打包一个xml发回去。

从最简单的,直接把用户信息返回去搞起吧。

文本消息
 <xml>
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName> 
 <CreateTime>1348831860</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[this is a test]]></Content>
 <MsgId>1234567890123456</MsgId>
 </xml>
参数 描述
ToUserName 开发者微信号
FromUserName 发送方帐号(一个OpenID)
CreateTime 消息创建时间 (整型)
MsgType text
Content 文本消息内容
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)
     ...
}

接下来就是回复信息

回复文本消息
 <xml>
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName>
 <CreateTime>12345678</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[content]]></Content>
 <FuncFlag>0</FuncFlag>
 </xml>

参数

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

FromUserName

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

MsgType

text
Content 回复的消息内容,长度不超过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 Faceslice struct{
     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) Faceslice{
     var f Faceslice
     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 detection.Faceslice
         faceslice=facepp.DetectionDetect(msg.PicUrl)
         switch len(faceslice.Face){
         case 0:
             resp.Content="请上传有脸的人物照片!"
         case 1:
             attribute:=faceslice.Face[0].Attribute
             age:=attribute.Age
             gender:=attribute.Gender
             var faceGender string
             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[0].Face_id
             face2id:=faceslice.Face[1].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="照片里人物太多了,暂不分析!"
         }
 }
posted @ 2013-06-02 09:25  trirocky  阅读(3923)  评论(0编辑  收藏  举报