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="照片里人物太多了,暫不分析!"
         }
 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM