From 5e02fab2498938868192d5ef75df8e361e578eae Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Wed, 22 Jul 2015 11:29:50 +0800 Subject: [PATCH 01/42] add Host Content-Type add Host Content-Type --- TencentYoutuyun/Youtu.php | 60 +++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 7668f15..3403b2a 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -36,7 +36,9 @@ public static function DetectFace($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -69,7 +71,9 @@ public static function FaceShape($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -111,7 +115,9 @@ public static function FaceCompare($image_path_a, $image_path_b) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -145,7 +151,9 @@ public static function FaceVerify($image_path,$person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -179,7 +187,9 @@ public static function FaceIdentify($image_path,$group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -212,7 +222,9 @@ public static function NewPerson($image_path, $person_id,array $group_ids) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -237,7 +249,9 @@ public static function DelPerson($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -272,7 +286,9 @@ public static function AddFace($person_id,array $image_path_arr) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -298,7 +314,9 @@ public static function DelFace($person_id,array $face_id_arr) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -324,7 +342,9 @@ public static function SetInfo($person_name,$person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -349,7 +369,9 @@ public static function GetInfo($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -373,7 +395,9 @@ public static function GetGroupIds() { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -398,7 +422,9 @@ public static function GetPersonIds($group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -423,7 +449,9 @@ public static function GetFaceIds($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); @@ -448,7 +476,9 @@ public static function GetFaceInfo($face_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization: '.$sign , + 'Content-Type: text/json', + 'Host: api.youtu.qq.com', ), ); $rsp = Http::send($req); From a4f127a3ecef13f5eb79a02c54070be671fb77b0 Mon Sep 17 00:00:00 2001 From: tanguofu Date: Fri, 7 Aug 2015 16:29:42 +0800 Subject: [PATCH 02/42] add some desciption --- README.md | 234 ++++++++++++++++++++++--- TencentYoutuyun/Auth.php | 64 +++---- TencentYoutuyun/Conf.php | 24 ++- TencentYoutuyun/Http.php | 142 +++++++-------- TencentYoutuyun/Youtu.php | 353 +++++++++++++++++++++++++------------- sample.php | 36 ++-- 6 files changed, 584 insertions(+), 269 deletions(-) diff --git a/README.md b/README.md index 4fed07b..1dcb0b4 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,228 @@ # TencentYoutuyun-person-face-service -php sdk for [腾讯优图云人脸服务](http://open.youtu.qq.com/) + +php sdk for [腾讯优图云人脸服务](http://open.YouTu::qq.com/) ## 安装(使用composer获取或者直接下载源码集成) ### 使用composer获取 +``` php composer.phar require TencentYoutuyun/php-sdk -调用请参考示例1 - +``` ### 直接下载源码集成 从github下载源码装入到您的程序中,并加载include.php -调用请参考示例2 -## 修改配置 -修改TencentYoutuyun/Conf.php内的appid等信息为您的配置 +## 名词 -## 人脸对比示例1(使用composer安装后生成的autoload) -```php - -require('./vendor/autoload.php'); -use TencentYoutuyun\Youtu; +## API -//人脸对比 -$uploadRet = YouTu::FaceCompare('you_path_one.jpg', 'you_path_two.jpg'); -var_dump($uploadRet); ``` +// 引入SDK +require('./include.php'); +use TencentYoutuyun\Youtu; +use TencentYoutuyun\Conf; +use TencentYoutuyun\Auth; +``` +### `Conf` +配置项相关 + +#### `Conf::setAppInfo(appid, secretId, secretKey, userid)` + +初始化配置项 + +- 参数 + - `appid` AppId 字符串类型 + - `secretId` SecretId 字符串类型 + - `secretKey` SecretKey 字符串类型 + - `userid` 业务中的用户标识 字符串类型 +- 返回值 无(`undefined`) +#### 其它 + +- `conf::API_YOUTU_END_POINT` 请求的优图服务器地址 默认为 api.youtu.qq.com + +### `Auth` + +接口调用时 计算签名鉴权相关逻辑。 + +#### `Auth::appSign($expired, $userid)` + +获取签名,依赖`conf`中的配置项。 + +- 参数 + - `expired` 过期时间,UNIX时间戳, 计算的签名在过期时间之前有效. + - `userid` 业务中的用户标识 +- 返回值 签名(base64) + +#### 其它 + +- `auth.AUTH_PARAMS_ERROR` 参数错误常量(-1) +- `auth.AUTH_SECRET_ID_KEY_ERROR` 密钥ID或者密钥KEY错误常量(-2) + +### `youtu` + +优图相关API封装,均为同步函数。 + + +#### `YouTu::detectface($image_path, $isbigface)` + +人脸检测,检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性。位置包括(x, y, w, h),面部属性包括性别(gender)、年龄(age) +表情(expression)、眼镜(glass)和姿态(pitch,roll,yaw)。 + +- 参数 + - `$image_path` 图片路径 + - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 + +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + + +#### `YouTu::faceshape($image_path, $isbigface)` + +人脸定位,检测给定图片中人脸的五官。对请求图片进行人脸配准,计算构成人脸轮廓的88个点, +包括眉毛(左右各8点)、眼睛(左右各8点)、鼻子(13点)、嘴巴(22点)、脸型轮廓(21点) + +- 参数 + - `$image_path` 图片路径 + - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + + +#### `YouTu::facecompare($image_path_a, $image_path_b)` + +人脸对比,计算两个Face的相似性以及五官相似度。 + +- 参数 + - `$image_path_a` 第一张图片路径 + - `$image_path_b` 第二张图片路径 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::faceverify($image_path_a, $person_id)` + +人脸验证,给定一个Face和一个Person,返回是否是同一个人的判断以及置信度。 + +- 参数 + - `$image_path_a` 图片路径 + - `$person_id` 待验证的Person +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::faceidentify($image_path_a, $group_id)` + +人脸识别,对于一个待识别的人脸图片,在一个Group中识别出最相似的Top5 Person作为其身份返回,返回的Top5中按照相似度从大到小排列。 + +- 参数 + - `$image_path_a` 图片路径 + - `$group_id` 需要识别的人 所在的组 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::newperson($image_path_a, $person_id, $person_name, $group_ids, $persontag)` + +个体创建,创建一个Person,并将Person放置到$group_ids指定的组当中。 + +- 参数 + - `$image_path_a` 图片路径 + - `$person_id` 个体Person + - `$person_name` 个体Person的名字 + - `$group_ids` 要加入的组的列表(数组) + - `$persontag` 备注信息,用户自解释字段 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::delperson($person_id)` + +删除一个Person + +- 参数 + - `$person_id` 个体Person +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + + +#### `YouTu::addface($person_id, $images, $facetag)` + +添加人脸,在创建一个Person后, 增加person下面的人脸, 可以用于后面的比对。 + +- 参数 + - `$person_id` 个体Person + - `$images` 图片路径(数组) + - `$facetag` 人脸自定义标签 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + + +#### `YouTu::delface($person_id, $face_ids)` + +删除人脸,删除一个person下的face,包括特征,属性和face_id。 + +- 参数 + - `$person_id` 个体Person + - `$face_ids` 要删除的faceId列表(数组) +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::setinfo($person_name, $person_id, $tag)` + +设置Person的信息 + +- 参数 + - `$person_name` 个体Person的name + - `$person_id` 个体Person + - `$tag` 个体Person的tag, 用户自解释字段 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::getinfo($person_id)` + +获取一个Person的信息,包括name、id、$tag、相关的face以及groups等信息。 + +- 参数 + - `$person_id` 个体Person +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::getgroupids()` + +获取一个AppId下所有group列表 + +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::getpersonIds($group_id)` + +获取一个组Group中所有person列表 + +- 参数 + - `$group_id` 组 +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::getfaceIds($person_id)` + +获取一个组person中所有face列表 + +- 参数 + - `$person_id` 个体Person +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +### `YouTu::getfaceinfo($face_id)` + +获取一个face的相关特征信息 + +- 参数 + - `$face_id` 需要获取的faceid +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +### 其他 -## 人脸对比示例2(使用TencentYoutuyun提供的include.php) -```php - 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/detectface'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); - $image_data = file_get_contents($image_path); + $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::APPID, - "image" => base64_encode($image_data) + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + "mode" => $isbigface ); $req = array( @@ -36,33 +68,41 @@ public static function DetectFace($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, + 'Expect: ', ), ); $rsp = Http::send($req); + $ret = json_decode($rsp, true); + return $ret; } - - public static function FaceShape($image_path) { - - $image_path = realpath($image_path); + + /** + * @brief faceshape + * @param $image_path 待检测的路径 + * @param isbigface 是否大脸模式 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function faceshape($image_path, $isbigface) { + + $real_image_path = realpath($image_path); - if (!file_exists($image_path)) + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/faceshape'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); - $image_data = file_get_contents($image_path); + $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::APPID, - "image" => base64_encode($image_data) + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + "mode" => $isbigface ); $req = array( @@ -71,40 +111,46 @@ public static function FaceShape($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, + 'Expect: ', ), ); $rsp = Http::send($req); + $ret = json_decode($rsp, true); return $ret; } - - - public static function FaceCompare($image_path_a, $image_path_b) { - - $image_path_a = realpath($image_path_a); - $image_path_b = realpath($image_path_b); - if (!file_exists($image_path_a)) + + + /** + * @brief facecompare + * @param $image_path_a 待比对的A图片数据 + * @param $image_path_b 待比对的B图片数据 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function facecompare($image_path_a, $image_path_b) { + + $real_image_path_a = realpath($image_path_a); + $real_image_path_b = realpath($image_path_b); + if (!file_exists($real_image_path_a)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path_a.' not exists', 'data' => array()); } - if (!file_exists($image_path_b)) + if (!file_exists($real_image_path_b)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path_b.' not exists', 'data' => array()); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/facecompare'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); - $image_data_a = file_get_contents($image_path_a); - $image_data_b = file_get_contents($image_path_b); + $image_data_a = file_get_contents($real_image_path_a); + $image_data_b = file_get_contents($real_image_path_b); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "imageA" => base64_encode($image_data_a), "imageB" => base64_encode($image_data_b) ); @@ -115,9 +161,8 @@ public static function FaceCompare($image_path_a, $image_path_b) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, + 'Expect: ', ), ); $rsp = Http::send($req); @@ -125,22 +170,28 @@ public static function FaceCompare($image_path_a, $image_path_b) { return $ret; } - public static function FaceVerify($image_path,$person_id) { + /** + * @brief faceverify + * @param person_id 待验证的人脸id + * @param $image_path 待验证的图片路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function faceverify($image_path,$person_id) { - $image_path = realpath($image_path); + $real_image_path = realpath($image_path); - if (!file_exists($image_path)) + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/faceverify'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); - $image_data = file_get_contents($image_path); + $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "image" => base64_encode($image_data), "person_id" =>$person_id, ); @@ -151,9 +202,7 @@ public static function FaceVerify($image_path,$person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -161,22 +210,30 @@ public static function FaceVerify($image_path,$person_id) { return $ret; } - public static function FaceIdentify($image_path,$group_id) { - $image_path = realpath($image_path); + /** + * @brief faceidentify + * @param group_id 识别的组id + * @param $image_path 待识别的图片路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function faceidentify($image_path,$group_id) { + + $real_image_path = realpath($image_path); - if (!file_exists($image_path)) + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/faceidentify'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); - $image_data = file_get_contents($image_path); + $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "image" => base64_encode($image_data), "group_id" =>$group_id, ); @@ -187,9 +244,7 @@ public static function FaceIdentify($image_path,$group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -197,23 +252,36 @@ public static function FaceIdentify($image_path,$group_id) { return $ret; } - public static function NewPerson($image_path, $person_id,array $group_ids) { - $image_path = realpath($image_path); - if (!file_exists($image_path)) + /** + * @brief newperson + * @param person_id 新建的个体id,用户指定,需要保证app_id下的唯一性 + * @param person_name 待验证的图片数据 + * @param group_ids 新建的个体存放的组id,可以指定多个组id,用户指定(组默认创建) + * @param $image_path 包含个体人脸的图片数据 + * @param person_tag 备注信息,用户自解释字段 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function newperson($image_path, $person_id, $person_name, array $group_ids, $person_tag) { + $real_image_path = realpath($image_path); + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/newperson'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); - $image_data = file_get_contents($image_path); + $image_data = file_get_contents($real_image_path); + $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "image" => base64_encode($image_data), "person_id" =>$person_id, - "group_ids" =>$group_ids + "group_ids" =>$group_ids, + "person_name" =>$person_name, + "tag" => $person_tag ); $req = array( @@ -222,9 +290,7 @@ public static function NewPerson($image_path, $person_id,array $group_ids) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -232,14 +298,20 @@ public static function NewPerson($image_path, $person_id,array $group_ids) { return $ret; } - public static function DelPerson($person_id) { + /** + * @brief delperson + * @param person_id 待删除的个体id + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function delperson($person_id) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/delperson'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "person_id" =>$person_id, ); @@ -249,9 +321,7 @@ public static function DelPerson($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -259,25 +329,33 @@ public static function DelPerson($person_id) { return $ret; } - public static function AddFace($person_id,array $image_path_arr) { + + /** + * @brief addface + * @param person_id 新增人脸的个体身份id + * @param image_path_arr 待增加的包含人脸的图片数据,可加入多张(包体大小<2m) + * @param facetag 人脸备注信息,用户自解释字段 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function addface($person_id,array $image_path_arr, $facetag) { $image_data_arr=array(); foreach($image_path_arr as $one_path){ - $image_path = realpath($one_path); - if (!file_exists($image_path)) + if (!file_exists($one_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$one_path.' not exists', 'data' => array()); } - $image_data=file_get_contents($image_path); + $image_data=file_get_contents($one_path); array_push($image_data_arr,base64_encode($image_data)); } $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/addface'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "images" => $image_data_arr, "person_id" =>$person_id, + "tag" => $facetag ); $req = array( @@ -286,9 +364,7 @@ public static function AddFace($person_id,array $image_path_arr) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -296,14 +372,21 @@ public static function AddFace($person_id,array $image_path_arr) { return $ret; } - public static function DelFace($person_id,array $face_id_arr) { + + /** + * @brief delface + * @param person_id 待删除人脸的个体身份id + * @param face_id_arr 待删除的人脸id + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function delface($person_id,array $face_id_arr) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/delface'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "face_ids" => $face_id_arr, "person_id" =>$person_id, ); @@ -314,9 +397,7 @@ public static function DelFace($person_id,array $face_id_arr) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -324,16 +405,25 @@ public static function DelFace($person_id,array $face_id_arr) { return $ret; } - public static function SetInfo($person_name,$person_id) { + + /** + * @brief setinfo + * @param person_id 待设置的个体身份id + * @param person_name 新设置的个体名字 + * @param person_tag 新设置的人备注信息 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function setinfo($person_name,$person_id, $person_tag) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/setinfo'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "person_name" => $person_name, "person_id" =>$person_id, + "tag" => $person_tag ); $req = array( @@ -342,9 +432,7 @@ public static function SetInfo($person_name,$person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -352,14 +440,20 @@ public static function SetInfo($person_name,$person_id) { return $ret; } - public static function GetInfo($person_id) { + + /** + * @brief getinfo + * @param person_id 待查询的个体身份id + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function getinfo($person_id) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getinfo'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "person_id" =>$person_id, ); @@ -369,9 +463,7 @@ public static function GetInfo($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -379,14 +471,19 @@ public static function GetInfo($person_id) { return $ret; } - public static function GetGroupIds() { + /** + * @brief getgroupids + * @param rsp 返回的组列表查询结果,JSON字符串,字段参见API文档 + * @return 0成功 -1失败 + */ + public static function getgroupids() { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getgroupids'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID + "app_id" => Conf::$APPID ); $req = array( @@ -395,9 +492,7 @@ public static function GetGroupIds() { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -405,14 +500,20 @@ public static function GetGroupIds() { return $ret; } - public static function GetPersonIds($group_id) { + /** + * @brief getpersonids + * @param group_id 待查询的组id + * @param rsp 返回的个体列表查询结果,JSON字符串,字段参见API文档 + * @return 0成功 -1失败 + */ + public static function getpersonids($group_id) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getpersonids'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "group_id" =>$group_id, ); @@ -422,9 +523,7 @@ public static function GetPersonIds($group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -432,14 +531,20 @@ public static function GetPersonIds($group_id) { return $ret; } - public static function GetFaceIds($person_id) { + /** + * @brief getfaceids + * @param person_id 待查询的个体id + * @param rsp 返回的人脸列表查询结果,JSON字符串,字段参见API文档 + * @return 0成功 -1失败 + */ + public static function getfaceids($person_id) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getfaceids'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "person_id" =>$person_id, ); @@ -449,9 +554,7 @@ public static function GetFaceIds($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); @@ -459,14 +562,20 @@ public static function GetFaceIds($person_id) { return $ret; } - public static function GetFaceInfo($face_id) { + /** + * @brief getfaceinfo + * @param face_id 待查询的人脸id + * @param rsp 返回的人脸信息查询结果,JSON字符串,字段参见API文档 + * @return 0成功 -1失败 + */ + public static function getfaceinfo($face_id) { $expired = time() + self::EXPIRED_SECONDS; $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getfaceinfo'; - $sign = Auth::appSign($expired,self::USER_ID); + $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::APPID, + "app_id" => Conf::$APPID, "face_id" =>$face_id, ); @@ -476,9 +585,7 @@ public static function GetFaceInfo($face_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign , - 'Content-Type: text/json', - 'Host: api.youtu.qq.com', + 'Authorization: '.$sign, ), ); $rsp = Http::send($req); diff --git a/sample.php b/sample.php index c2e59fc..800f94c 100644 --- a/sample.php +++ b/sample.php @@ -2,22 +2,26 @@ require('./include.php'); use TencentYoutuyun\Youtu; +use TencentYoutuyun\Conf; -#$uploadRet = YouTu::DetectFace('you_path.jpg'); -#$uploadRet = YouTu::NewPerson('you_path.jpg','123456',array('test_groupid','test_groupid2','test_groupid3')); -#$uploadRet = YouTu::FaceVerify('you_path.jpg','123456'); -#$uploadRet = YouTu::FaceIdentify('you_path.jpg','test_groupid'); -#$uploadRet = YouTu::NewPerson('you_path.jpg','123456',array('test_groupid','test_groupid2','test_groupid3')); -#$uploadRet = YouTu::DelPerson('123456'); -#$uploadRet = YouTu::AddFace('123456',array('you_path.jpg')); -#$uploadRet = YouTu::DelFace('123456',array('1027423607359340543')); -#$uploadRet = YouTu::SetInfo('name_groupid','123456'); -#$uploadRet = YouTu::GetInfo('123456'); -#$uploadRet = YouTu::GetGroupIds(); -#$uploadRet = YouTu::GetPersonIds('test_groupid'); -#$uploadRet = YouTu::GetFaceIds('123456'); -#$uploadRet = YouTu::GetFaceInfo('1027425345818656767'); -$uploadRet = YouTu::FaceCompare('you_path_one.jpg', 'you_path_two.jpg'); +// 设置APP 鉴权信息 +$appid=''; +$secretId=''; +$secretKey=''; +$userid=''; + + +Conf::setAppInfo($appid, $secretId, $secretKey, $userid); + + +// 人脸检测 调用列子 +$uploadRet = YouTu::detectface('a.jpg', 1); var_dump($uploadRet); -?> \ No newline at end of file + + +// 人脸定位 调用demo +$uploadRet = YouTu::faceshape('a.jpg', 1); +var_dump($uploadRet); + +?> From 912ea227487325352a6353e89ce3c8125c860523 Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Mon, 17 Aug 2015 14:43:50 +0800 Subject: [PATCH 03/42] modify modify --- TencentYoutuyun/Youtu.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index c6ca617..5f4bd47 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -38,7 +38,7 @@ public static function statusText($status) { /** * @brief detectface - * @param $image_path 待检测的路径 + * @param image_path 待检测的路径 * @param isbigface 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 * @return 返回的结果,JSON字符串,字段参见API文档 */ @@ -81,7 +81,7 @@ public static function detectface($image_path, $isbigface) { /** * @brief faceshape - * @param $image_path 待检测的路径 + * @param image_path 待检测的路径 * @param isbigface 是否大脸模式 * @return 返回的结果,JSON字符串,字段参见API文档 */ @@ -124,8 +124,8 @@ public static function faceshape($image_path, $isbigface) { /** * @brief facecompare - * @param $image_path_a 待比对的A图片数据 - * @param $image_path_b 待比对的B图片数据 + * @param image_path_a 待比对的A图片数据 + * @param image_path_b 待比对的B图片数据 * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function facecompare($image_path_a, $image_path_b) { @@ -173,7 +173,7 @@ public static function facecompare($image_path_a, $image_path_b) { /** * @brief faceverify * @param person_id 待验证的人脸id - * @param $image_path 待验证的图片路径 + * @param image_path 待验证的图片路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function faceverify($image_path,$person_id) { @@ -214,7 +214,7 @@ public static function faceverify($image_path,$person_id) { /** * @brief faceidentify * @param group_id 识别的组id - * @param $image_path 待识别的图片路径 + * @param image_path 待识别的图片路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ @@ -255,14 +255,14 @@ public static function faceidentify($image_path,$group_id) { /** * @brief newperson * @param person_id 新建的个体id,用户指定,需要保证app_id下的唯一性 - * @param person_name 待验证的图片数据 + * @param person_name 个体名字 * @param group_ids 新建的个体存放的组id,可以指定多个组id,用户指定(组默认创建) - * @param $image_path 包含个体人脸的图片数据 + * @param image_path 包含个体人脸的图片数据 * @param person_tag 备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function newperson($image_path, $person_id, $person_name, array $group_ids, $person_tag) { + public static function newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="") { $real_image_path = realpath($image_path); if (!file_exists($real_image_path)) { @@ -474,7 +474,7 @@ public static function getinfo($person_id) { /** * @brief getgroupids * @param rsp 返回的组列表查询结果,JSON字符串,字段参见API文档 - * @return 0成功 -1失败 + * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function getgroupids() { @@ -504,7 +504,7 @@ public static function getgroupids() { * @brief getpersonids * @param group_id 待查询的组id * @param rsp 返回的个体列表查询结果,JSON字符串,字段参见API文档 - * @return 0成功 -1失败 + * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function getpersonids($group_id) { @@ -535,7 +535,7 @@ public static function getpersonids($group_id) { * @brief getfaceids * @param person_id 待查询的个体id * @param rsp 返回的人脸列表查询结果,JSON字符串,字段参见API文档 - * @return 0成功 -1失败 + * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function getfaceids($person_id) { @@ -566,7 +566,7 @@ public static function getfaceids($person_id) { * @brief getfaceinfo * @param face_id 待查询的人脸id * @param rsp 返回的人脸信息查询结果,JSON字符串,字段参见API文档 - * @return 0成功 -1失败 + * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function getfaceinfo($face_id) { From ddd22c04f08234b2953f80dcbabe685a751850b3 Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Wed, 26 Aug 2015 14:47:57 +0800 Subject: [PATCH 04/42] fix auth fix auth --- TencentYoutuyun/Auth.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TencentYoutuyun/Auth.php b/TencentYoutuyun/Auth.php index 35dbe69..ebbc19e 100644 --- a/TencentYoutuyun/Auth.php +++ b/TencentYoutuyun/Auth.php @@ -13,9 +13,9 @@ class Auth * @return string 签名 */ public static function appSign($expired,$userid) { - $secretId = Conf::SECRET_ID; - $secretKey = Conf::SECRET_KEY; - $appid = Conf::APPID; + $secretId = Conf::$SECRET_ID; + $secretKey = Conf::$SECRET_KEY; + $appid = Conf::$APPID; if (empty($secretId) || empty($secretKey)) { return self::AUTH_SECRET_ID_KEY_ERROR; } From 2f2f7c25600944381c2b12e6f02e262a600cc2ee Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Tue, 15 Sep 2015 14:42:55 +0800 Subject: [PATCH 05/42] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1dcb0b4..24a87cc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TencentYoutuyun-person-face-service -php sdk for [腾讯优图云人脸服务](http://open.YouTu::qq.com/) +php sdk for [腾讯优图云人脸服务](http://open.youtu.qq.com/) ## 安装(使用composer获取或者直接下载源码集成) @@ -16,7 +16,7 @@ php composer.phar require TencentYoutuyun/php-sdk - `AppId` 平台添加应用后分配的AppId - `SecretId` 平台添加应用后分配的SecretId - `SecretKey` 平台添加应用后分配的SecretKey -- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 +- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 ## API From eeedec11d7f0429e3a01ba0dd0e4f5c6698d52db Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Mon, 21 Sep 2015 20:29:28 +0800 Subject: [PATCH 06/42] update to 2.0 update to 2.0 --- README.md | 4 +- TencentYoutuyun/Conf.php | 10 +- TencentYoutuyun/Youtu.php | 735 +++++++++++++++++++++++++++++++++++--- test.jpg | Bin 0 -> 130193 bytes 4 files changed, 687 insertions(+), 62 deletions(-) create mode 100644 test.jpg diff --git a/README.md b/README.md index 24a87cc..1dcb0b4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TencentYoutuyun-person-face-service -php sdk for [腾讯优图云人脸服务](http://open.youtu.qq.com/) +php sdk for [腾讯优图云人脸服务](http://open.YouTu::qq.com/) ## 安装(使用composer获取或者直接下载源码集成) @@ -16,7 +16,7 @@ php composer.phar require TencentYoutuyun/php-sdk - `AppId` 平台添加应用后分配的AppId - `SecretId` 平台添加应用后分配的SecretId - `SecretKey` 平台添加应用后分配的SecretKey -- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 +- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 ## API diff --git a/TencentYoutuyun/Conf.php b/TencentYoutuyun/Conf.php index ca311bf..9a30917 100644 --- a/TencentYoutuyun/Conf.php +++ b/TencentYoutuyun/Conf.php @@ -6,6 +6,8 @@ class Conf const PKG_VERSION = '1.0.*'; const API_YOUTU_END_POINT = 'http://api.youtu.qq.com/'; + const API_TENCENTYUN_END_POINT = 'https://youtu.api.qcloud.com/'; + // 请到 open.youtu.qq.com查看您对应的appid相关信息并填充 // 请统一 通过 setAppInfo 设置 @@ -13,6 +15,8 @@ class Conf public static $APPID = ''; public static $SECRET_ID = ''; public static $SECRET_KEY = ''; + public static $END_POINT = ''; + // 开发者 QQ public static $USER_ID = ''; @@ -22,12 +26,16 @@ public static function getUA() { return 'YoutuPHP/'.self::PKG_VERSION.' ('.php_uname().')'; } + + // 初始化 应用信息 - public static function setAppInfo($appid, $secretId, $secretKey, $userid) { + public static function setAppInfo($appid, $secretId, $secretKey, $userid,$end_point) { self::$APPID = $appid; self::$SECRET_ID = $secretId; self::$SECRET_KEY = $secretKey; self::$USER_ID = $userid; + self::$END_POINT = $end_point; + } } diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 5f4bd47..fb84fa6 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -14,28 +14,61 @@ class YouTu */ public static function statusText($status) { - $statusText = 'unkown'; + $statusText = 'UNKOWN'; switch ($status) { + case 0: + $statusText = 'CONNECT_FAIL'; + break; case 200: $statusText = 'HTTP OK'; break; case 400: - $statusText = 'Bad Request'; + $statusText = 'BAD_REQUEST'; break; case 401: - $statusText = 'Unauthorized'; + $statusText = 'UNAUTHORIZED'; break; case 403: - $statusText = 'Forbidden'; + $statusText = 'FORBIDDEN'; + break; + case 404: + $statusText = 'NOTFOUND'; + break; + case 411: + $statusText = 'REQ_NOLENGTH'; + break; + case 423: + $statusText = 'SERVER_NOTFOUND'; + break; + case 424: + $statusText = 'METHOD_NOTFOUND'; + break; + case 425: + $statusText = 'REQUEST_OVERFLOW'; break; case 500: - $statusText = 'Internal Server Error'; + $statusText = 'INTERNAL_SERVER_ERROR'; + break; + case 503: + $statusText = 'SERVICE_UNAVAILABLE'; + break; + case 504: + $statusText = 'GATEWAY_TIME_OUT'; break; } return $statusText; } +/** + * return the status message + */ + public static function getStatusText() { + + $status=Http::info()['http_code']; + return self::statusText($status); + } + /** * @brief detectface * @param image_path 待检测的路径 @@ -52,7 +85,7 @@ public static function detectface($image_path, $isbigface) { } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/detectface'; + $postUrl = Conf::$END_POINT . 'youtu/api/detectface'; $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); @@ -63,7 +96,7 @@ public static function detectface($image_path, $isbigface) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -74,11 +107,54 @@ public static function detectface($image_path, $isbigface) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } - + + /** + * @brief detectfaceurl + * @param url 图片url + * @param isbigface 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function detectfaceurl($url, $isbigface) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/detectface'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "mode" => $isbigface + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + /** * @brief faceshape * @param image_path 待检测的路径 @@ -95,7 +171,7 @@ public static function faceshape($image_path, $isbigface) { } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/faceshape'; + $postUrl = Conf::$END_POINT . 'youtu/api/faceshape'; $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); @@ -106,7 +182,7 @@ public static function faceshape($image_path, $isbigface) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -117,17 +193,59 @@ public static function faceshape($image_path, $isbigface) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } - - /** - * @brief facecompare - * @param image_path_a 待比对的A图片数据 - * @param image_path_b 待比对的B图片数据 - * @return 返回的结果,JSON字符串,字段参见API文档 - */ + /** + * @brief faceshapeurl + * @param url 图片url + * @param isbigface 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function faceshapeurl($url, $isbigface) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/faceshape'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "mode" => $isbigface + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @brief facecompare + * @param image_path_a 待比对的A图片数据 + * @param image_path_b 待比对的B图片数据 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ public static function facecompare($image_path_a, $image_path_b) { $real_image_path_a = realpath($image_path_a); @@ -143,7 +261,7 @@ public static function facecompare($image_path_a, $image_path_b) { } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/facecompare'; + $postUrl = Conf::$END_POINT . 'youtu/api/facecompare'; $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data_a = file_get_contents($real_image_path_a); @@ -156,7 +274,7 @@ public static function facecompare($image_path_a, $image_path_b) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -166,10 +284,53 @@ public static function facecompare($image_path_a, $image_path_b) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief facecompareurl + * @param urlA 待比对的A图片url + * @param urlB 待比对的B图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function facecompareurl($urlA, $urlB) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/facecompare'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "urlA" => $urlA, + "urlB" => $urlB + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } + + /** * @brief faceverify * @param person_id 待验证的人脸id @@ -186,7 +347,7 @@ public static function faceverify($image_path,$person_id) { } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/faceverify'; + $postUrl = Conf::$END_POINT . 'youtu/api/faceverify'; $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); @@ -197,7 +358,43 @@ public static function faceverify($image_path,$person_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief faceverifyurl + * @param person_id 待验证的人脸id + * @param url 待验证的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function faceverifyurl($url,$person_id) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/faceverify'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "person_id" =>$person_id, + ); + + $req = array( + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -206,7 +403,11 @@ public static function faceverify($image_path,$person_id) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -228,7 +429,7 @@ public static function faceidentify($image_path,$group_id) { } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/faceidentify'; + $postUrl = Conf::$END_POINT . 'youtu/api/faceidentify'; $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); @@ -239,7 +440,44 @@ public static function faceidentify($image_path,$group_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief faceidentifyurl + * @param group_id 识别的组id + * @param url 待识别的图片的url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function faceidentifyurl($url,$group_id) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/faceidentify'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "group_id" =>$group_id, + ); + + $req = array( + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -248,7 +486,11 @@ public static function faceidentify($image_path,$group_id) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -270,7 +512,7 @@ public static function newperson($image_path, $person_id, array $group_ids, $per } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/newperson'; + $postUrl = Conf::$END_POINT . 'youtu/api/newperson'; $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); @@ -285,7 +527,50 @@ public static function newperson($image_path, $person_id, array $group_ids, $per ); $req = array( - 'url' => $url, + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief newpersonurl + * @param person_id 新建的个体id,用户指定,需要保证app_id下的唯一性 + * @param person_name 个体名字 + * @param group_ids 新建的个体存放的组id,可以指定多个组id,用户指定(组默认创建) + * @param url 包含个体人脸的图片url + * @param person_tag 备注信息,用户自解释字段 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="") { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/newperson'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "person_id" =>$person_id, + "group_ids" =>$group_ids, + "person_name" =>$person_name, + "tag" => $person_tag + ); + + $req = array( + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -294,7 +579,11 @@ public static function newperson($image_path, $person_id, array $group_ids, $per ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -307,7 +596,7 @@ public static function newperson($image_path, $person_id, array $group_ids, $per public static function delperson($person_id) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/delperson'; + $postUrl = Conf::$END_POINT . 'youtu/api/delperson'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -316,7 +605,7 @@ public static function delperson($person_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -325,7 +614,11 @@ public static function delperson($person_id) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -337,7 +630,7 @@ public static function delperson($person_id) { * @param facetag 人脸备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function addface($person_id,array $image_path_arr, $facetag) { + public static function addface($person_id,array $image_path_arr, $facetag="") { $image_data_arr=array(); foreach($image_path_arr as $one_path){ if (!file_exists($one_path)) @@ -348,7 +641,7 @@ public static function addface($person_id,array $image_path_arr, $facetag) { array_push($image_data_arr,base64_encode($image_data)); } $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/addface'; + $postUrl = Conf::$END_POINT . 'youtu/api/addface'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -359,7 +652,7 @@ public static function addface($person_id,array $image_path_arr, $facetag) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -368,7 +661,49 @@ public static function addface($person_id,array $image_path_arr, $facetag) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief addfaceurl + * @param person_id 新增人脸的个体身份id + * @param url_arr 待增加的包含人脸的图片url,可加入多张(包体大小<2m) + * @param facetag 人脸备注信息,用户自解释字段 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function addfaceurl($person_id,array $url_arr, $facetag="") { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/addface'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "urls" => $url_arr, + "person_id" =>$person_id, + "tag" => $facetag + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -382,7 +717,7 @@ public static function addface($person_id,array $image_path_arr, $facetag) { public static function delface($person_id,array $face_id_arr) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/delface'; + $postUrl = Conf::$END_POINT . 'youtu/api/delface'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -392,7 +727,7 @@ public static function delface($person_id,array $face_id_arr) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -401,7 +736,11 @@ public static function delface($person_id,array $face_id_arr) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -416,7 +755,7 @@ public static function delface($person_id,array $face_id_arr) { public static function setinfo($person_name,$person_id, $person_tag) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/setinfo'; + $postUrl = Conf::$END_POINT . 'youtu/api/setinfo'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -427,7 +766,7 @@ public static function setinfo($person_name,$person_id, $person_tag) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -436,7 +775,11 @@ public static function setinfo($person_name,$person_id, $person_tag) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -449,7 +792,7 @@ public static function setinfo($person_name,$person_id, $person_tag) { public static function getinfo($person_id) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getinfo'; + $postUrl = Conf::$END_POINT . 'youtu/api/getinfo'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -458,7 +801,7 @@ public static function getinfo($person_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -467,7 +810,11 @@ public static function getinfo($person_id) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -479,7 +826,7 @@ public static function getinfo($person_id) { public static function getgroupids() { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getgroupids'; + $postUrl = Conf::$END_POINT . 'youtu/api/getgroupids'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -487,7 +834,7 @@ public static function getgroupids() { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -496,7 +843,11 @@ public static function getgroupids() { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -509,7 +860,7 @@ public static function getgroupids() { public static function getpersonids($group_id) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getpersonids'; + $postUrl = Conf::$END_POINT . 'youtu/api/getpersonids'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -518,7 +869,7 @@ public static function getpersonids($group_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -527,7 +878,11 @@ public static function getpersonids($group_id) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -540,7 +895,7 @@ public static function getpersonids($group_id) { public static function getfaceids($person_id) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getfaceids'; + $postUrl = Conf::$END_POINT . 'youtu/api/getfaceids'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -549,7 +904,7 @@ public static function getfaceids($person_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), @@ -558,7 +913,11 @@ public static function getfaceids($person_id) { ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } return $ret; } @@ -571,7 +930,7 @@ public static function getfaceids($person_id) { public static function getfaceinfo($face_id) { $expired = time() + self::EXPIRED_SECONDS; - $url = Conf::API_YOUTU_END_POINT . 'youtu/api/getfaceinfo'; + $postUrl = Conf::$END_POINT . 'youtu/api/getfaceinfo'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( @@ -580,18 +939,276 @@ public static function getfaceinfo($face_id) { ); $req = array( - 'url' => $url, + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief fuzzydetect + * @param image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function fuzzydetect($image_path) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/fuzzydetect'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @brief fuzzydetecturl + * @param url 图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function fuzzydetecturl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/fuzzydetect'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @brief fooddetect + * @param image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function fooddetect($image_path) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/fooddetect'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @brief fooddetecturl + * @param url 图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function fooddetecturl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/fooddetect'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @brief imagetag + * @param image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function imagetag($image_path) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imagetag'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization: '.$sign, + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @brief imagetagurl + * @param url 图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function imagetagurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imagetag'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + ); + + $req = array( + 'url' => $postUrl, 'method' => 'post', 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( 'Authorization: '.$sign, + 'Expect: ', ), ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; } + + + + } diff --git a/test.jpg b/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d74bd1878121e4bdd08596f54e0913e6a34049a7 GIT binary patch literal 130193 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 literal 0 HcmV?d00001 From 38b80859a69ddd5c4265fdd4d3d36625688314fa Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Fri, 9 Oct 2015 14:59:36 +0800 Subject: [PATCH 07/42] update readme update readme --- README.md | 126 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 1dcb0b4..77b3e09 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,9 @@ php sdk for [腾讯优图云人脸服务](http://open.YouTu::qq.com/) -## 安装(使用composer获取或者直接下载源码集成) +## 安装(直接下载源码集成) + -### 使用composer获取 -``` -php composer.phar require TencentYoutuyun/php-sdk -``` -### 直接下载源码集成 从github下载源码装入到您的程序中,并加载include.php ## 名词 @@ -16,9 +12,9 @@ php composer.phar require TencentYoutuyun/php-sdk - `AppId` 平台添加应用后分配的AppId - `SecretId` 平台添加应用后分配的SecretId - `SecretKey` 平台添加应用后分配的SecretKey -- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 +- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 -## API +## 使用示例 ``` // 引入SDK @@ -26,26 +22,21 @@ require('./include.php'); use TencentYoutuyun\Youtu; use TencentYoutuyun\Conf; use TencentYoutuyun\Auth; -``` -### `Conf` - -配置项相关 - -#### `Conf::setAppInfo(appid, secretId, secretKey, userid)` - -初始化配置项 -- 参数 - - `appid` AppId 字符串类型 - - `secretId` SecretId 字符串类型 - - `secretKey` SecretKey 字符串类型 - - `userid` 业务中的用户标识 字符串类型 -- 返回值 无(`undefined`) -#### 其它 +// 设置APP 鉴权信息 +$appid='your appid'; +$secretId='your secretId '; +$secretKey='your secretKey'; +$userid='your qq'; +//根据你使用的平台选择一种初始化方式 +//优图开放平台初始化 +Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT); +//腾讯云初始化 +Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); +``` -- `conf::API_YOUTU_END_POINT` 请求的优图服务器地址 默认为 api.youtu.qq.com -### `Auth` +### `鉴权` 接口调用时 计算签名鉴权相关逻辑。 @@ -55,26 +46,28 @@ use TencentYoutuyun\Auth; - 参数 - `expired` 过期时间,UNIX时间戳, 计算的签名在过期时间之前有效. - - `userid` 业务中的用户标识 -- 返回值 签名(base64) + - `userid` 业务中的用户标识,填写用户QQ号即可 +- 返回值: 签名 #### 其它 - `auth.AUTH_PARAMS_ERROR` 参数错误常量(-1) - `auth.AUTH_SECRET_ID_KEY_ERROR` 密钥ID或者密钥KEY错误常量(-2) -### `youtu` +### `SDK API介绍` 优图相关API封装,均为同步函数。 #### `YouTu::detectface($image_path, $isbigface)` +#### `YouTu::detectfaceurl($url, $isbigface)` 人脸检测,检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性。位置包括(x, y, w, h),面部属性包括性别(gender)、年龄(age) 表情(expression)、眼镜(glass)和姿态(pitch,roll,yaw)。 - 参数 - - `$image_path` 图片路径 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 - 返回值 @@ -82,57 +75,68 @@ use TencentYoutuyun\Auth; #### `YouTu::faceshape($image_path, $isbigface)` +#### `YouTu::faceshapeurl($url, $isbigface)` 人脸定位,检测给定图片中人脸的五官。对请求图片进行人脸配准,计算构成人脸轮廓的88个点, 包括眉毛(左右各8点)、眼睛(左右各8点)、鼻子(13点)、嘴巴(22点)、脸型轮廓(21点) - 参数 - - `$image_path` 图片路径 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 - 返回值 - 返回的结果,JSON字符串,字段参见API文档 #### `YouTu::facecompare($image_path_a, $image_path_b)` +#### `YouTu::facecompareurl($urlA, $urlB)` 人脸对比,计算两个Face的相似性以及五官相似度。 - 参数 - - `$image_path_a` 第一张图片路径 - - `$image_path_b` 第二张图片路径 + - `$image_path_a` 第一张待检测图片路径 + - `$image_path_b` 第二张待检测图片路径 + - `$urlA` 第一张图片url + - `$urlB` 第二张图片url - 返回值 - 返回的结果,JSON字符串,字段参见API文档 -#### `YouTu::faceverify($image_path_a, $person_id)` +#### `YouTu::faceverify($image_path, $person_id)` +#### `YouTu::faceverifyurl($url,$person_id)` 人脸验证,给定一个Face和一个Person,返回是否是同一个人的判断以及置信度。 - 参数 - - `$image_path_a` 图片路径 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url - `$person_id` 待验证的Person - 返回值 - 返回的结果,JSON字符串,字段参见API文档 -#### `YouTu::faceidentify($image_path_a, $group_id)` - +#### `YouTu::faceidentify($image_path, $group_id)` +#### `YouTu::faceidentifyurl($url,$group_id)` 人脸识别,对于一个待识别的人脸图片,在一个Group中识别出最相似的Top5 Person作为其身份返回,返回的Top5中按照相似度从大到小排列。 - 参数 - - `$image_path_a` 图片路径 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url - `$group_id` 需要识别的人 所在的组 - 返回值 - 返回的结果,JSON字符串,字段参见API文档 -#### `YouTu::newperson($image_path_a, $person_id, $person_name, $group_ids, $persontag)` +#### `YouTu::newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="")` +#### `YouTu::newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="")` 个体创建,创建一个Person,并将Person放置到$group_ids指定的组当中。 - 参数 - - `$image_path_a` 图片路径 - - `$person_id` 个体Person - - `$person_name` 个体Person的名字 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$person_id` 个体id + - `$person_name` 个体的名字 - `$group_ids` 要加入的组的列表(数组) - - `$persontag` 备注信息,用户自解释字段 + - `$person_name` 个体名称 + - `$person_tag` 备注信息,用户自解释字段 - 返回值 - 返回的结果,JSON字符串,字段参见API文档 @@ -147,12 +151,14 @@ use TencentYoutuyun\Auth; #### `YouTu::addface($person_id, $images, $facetag)` +#### `YouTu::addfaceurl($person_id, $url_arr, $facetag="")` 添加人脸,在创建一个Person后, 增加person下面的人脸, 可以用于后面的比对。 - 参数 - `$person_id` 个体Person - - `$images` 图片路径(数组) + - `$images` 待检测图片路径(数组) + - `$url_arr` 图片url(数组) - `$facetag` 人脸自定义标签 - 返回值 - 返回的结果,JSON字符串,字段参见API文档 @@ -213,7 +219,7 @@ use TencentYoutuyun\Auth; - 返回值 - 返回的结果,JSON字符串,字段参见API文档 -### `YouTu::getfaceinfo($face_id)` +#### `YouTu::getfaceinfo($face_id)` 获取一个face的相关特征信息 @@ -221,8 +227,36 @@ use TencentYoutuyun\Auth; - `$face_id` 需要获取的faceid - 返回值 - 返回的结果,JSON字符串,字段参见API文档 - -### 其他 +#### `YouTu::fuzzydetect($image_path)` +#### `YouTu::fuzzydetecturl($url)` + +判断一个图像的模糊程度 + +- 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::fooddetect($image_path)` +#### `YouTu::fooddetecturl($url)` +识别一个图像是否为美食图像 +- 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::imagetag($image_path)` +#### `YouTu::imagetagurl($url)` + +识别一个图像的标签信息,对图像分类 + +- 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url +- 返回值 + - 返回的结果,JSON字符串,字段参见API文档 \ No newline at end of file From 957b696b3d309c3b9d128412253264e8b27e283e Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Fri, 9 Oct 2015 15:04:31 +0800 Subject: [PATCH 08/42] update readme update readme --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 77b3e09..08923eb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TencentYoutuyun-person-face-service -php sdk for [腾讯优图云人脸服务](http://open.YouTu::qq.com/) +php sdk for [腾讯优图云人脸服务](http://open.youtu.qq.com/) ## 安装(直接下载源码集成) @@ -28,11 +28,16 @@ $appid='your appid'; $secretId='your secretId '; $secretKey='your secretKey'; $userid='your qq'; + //根据你使用的平台选择一种初始化方式 //优图开放平台初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT); //腾讯云初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); + +//人脸检测接口调用 +$uploadRet = YouTu::detectface('test.jpg', 1); +var_dump($uploadRet); ``` From 4f39d080cf2d2accd3ac99ba119aaacc0ddbf669 Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Fri, 9 Oct 2015 15:14:30 +0800 Subject: [PATCH 09/42] update readme update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08923eb..401b066 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TencentYoutuyun-person-face-service -php sdk for [腾讯优图云人脸服务](http://open.youtu.qq.com/) +php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) & [腾讯优图开放平台](http://open.youtu.qq.com) ## 安装(直接下载源码集成) From 33b79ace6d52f781246abb51729e2b59867f3d93 Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Thu, 15 Oct 2015 14:13:02 +0800 Subject: [PATCH 10/42] modify comment modify comment --- TencentYoutuyun/Youtu.php | 88 +++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 49 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index fb84fa6..511cd4d 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -957,14 +957,13 @@ public static function getfaceinfo($face_id) { } /** - * @brief fuzzydetect - * @param image_path 待检测的路径 + * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function fuzzydetect($image_path) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -992,22 +991,21 @@ public static function fuzzydetect($image_path) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); - + $ret = json_decode($rsp, true); + if(!$ret){ return self::getStatusText(); - } - + } + if(!$ret){ return self::getStatusText(); } - + return $ret; } - /** - * @brief fuzzydetecturl - * @param url 图片url + /** + * @param $url 图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function fuzzydetecturl($url) { @@ -1033,24 +1031,23 @@ public static function fuzzydetecturl($url) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); - + $ret = json_decode($rsp, true); + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } - /** - * @brief fooddetect - * @param image_path 待检测的路径 + /** + * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function fooddetect($image_path) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -1078,18 +1075,17 @@ public static function fooddetect($image_path) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); - + $ret = json_decode($rsp, true); + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } - /** - * @brief fooddetecturl - * @param url 图片url + /** + * @param $url 图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function fooddetecturl($url) { @@ -1115,24 +1111,23 @@ public static function fooddetecturl($url) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); - + $ret = json_decode($rsp, true); + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } - /** - * @brief imagetag - * @param image_path 待检测的路径 + /** + * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function imagetag($image_path) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -1160,18 +1155,17 @@ public static function imagetag($image_path) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); - + $ret = json_decode($rsp, true); + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } - /** - * @brief imagetagurl - * @param url 图片url + /** + * @param $url 图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function imagetagurl($url) { @@ -1197,18 +1191,14 @@ public static function imagetagurl($url) { ); $rsp = Http::send($req); - $ret = json_decode($rsp, true); - + $ret = json_decode($rsp, true); + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } - - - - } From 0639ad6dea6ed0ad00659a67b10fabbfea3ffbfa Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Fri, 16 Oct 2015 15:43:06 +0800 Subject: [PATCH 11/42] add contentType add contentType --- TencentYoutuyun/Youtu.php | 84 ++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 511cd4d..46580c6 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -101,7 +101,8 @@ public static function detectface($image_path, $isbigface) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -140,7 +141,8 @@ public static function detectfaceurl($url, $isbigface) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -187,7 +189,8 @@ public static function faceshape($image_path, $isbigface) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -225,7 +228,8 @@ public static function faceshapeurl($url, $isbigface) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -279,7 +283,8 @@ public static function facecompare($image_path_a, $image_path_b) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -316,7 +321,8 @@ public static function facecompareurl($urlA, $urlB) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -363,7 +369,8 @@ public static function faceverify($image_path,$person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -399,7 +406,8 @@ public static function faceverifyurl($url,$person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -445,7 +453,8 @@ public static function faceidentify($image_path,$group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -482,7 +491,8 @@ public static function faceidentifyurl($url,$group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -532,7 +542,8 @@ public static function newperson($image_path, $person_id, array $group_ids, $per 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -575,7 +586,8 @@ public static function newpersonurl($url, $person_id, array $group_ids, $person_ 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -610,7 +622,8 @@ public static function delperson($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -657,7 +670,8 @@ public static function addface($person_id,array $image_path_arr, $facetag="") { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -695,7 +709,8 @@ public static function addfaceurl($person_id,array $url_arr, $facetag="") { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -732,7 +747,8 @@ public static function delface($person_id,array $face_id_arr) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -771,7 +787,8 @@ public static function setinfo($person_name,$person_id, $person_tag) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -806,7 +823,8 @@ public static function getinfo($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -839,7 +857,8 @@ public static function getgroupids() { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -874,7 +893,8 @@ public static function getpersonids($group_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -909,7 +929,8 @@ public static function getfaceids($person_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -944,7 +965,8 @@ public static function getfaceinfo($face_id) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', ), ); $rsp = Http::send($req); @@ -985,7 +1007,8 @@ public static function fuzzydetect($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -1025,7 +1048,8 @@ public static function fuzzydetecturl($url) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -1069,7 +1093,8 @@ public static function fooddetect($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -1105,7 +1130,8 @@ public static function fooddetecturl($url) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -1149,7 +1175,8 @@ public static function imagetag($image_path) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); @@ -1185,7 +1212,8 @@ public static function imagetagurl($url) { 'timeout' => 10, 'data' => json_encode($post_data), 'header' => array( - 'Authorization: '.$sign, + 'Authorization:'.$sign, + 'Content-Type:text/json', 'Expect: ', ), ); From 4b931ac0ca438f05e9fa89cc36446f76693deb1d Mon Sep 17 00:00:00 2001 From: tanguofu Date: Wed, 27 Apr 2016 12:53:44 +0800 Subject: [PATCH 12/42] add porn idcard namecard api --- README.md | 37 +++++- TencentYoutuyun/Conf.php | 2 +- TencentYoutuyun/Youtu.php | 262 ++++++++++++++++++++++++++++++++++++++ sample.php | 38 ++++-- 4 files changed, 328 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 401b066..e5bd35c 100644 --- a/README.md +++ b/README.md @@ -264,4 +264,39 @@ var_dump($uploadRet); - `$image_path` 待检测图片路径 - `$url` 待检测图片的url - 返回值 - - 返回的结果,JSON字符串,字段参见API文档 \ No newline at end of file + - 返回的结果,JSON字符串,字段参见API文档 + +#### `YouTu::imageporn($image_path)` +#### `YouTu::imagepornurl($url)` +色情图像检测 +- 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + +``` +``` + +#### `YouTu::idcardocr($image_path, $card_type, $seq = '') ` +#### `YouTu::idcardocrurl($url, $card_type, $seq = '') ` +身份证OCR识别 + +- 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + - `$card_type` 0 代表输入图像是身份证正面, 1代表输入是身份证反面 + +#### `YouTu::namecardocr($image_path, $retimage, $seq = '') ` +#### `YouTu::namecardocrurl($url, $retimage, $seq = '') ` +名片ocr识别 + +- 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + - `$retimage` 0代表不需要返回识别后图像, 1代表需要返回识别后图像 + +``` +``` +更多详情和文档说明参见 +[腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) +[腾讯优图开放平台](http://open.youtu.qq.com) + diff --git a/TencentYoutuyun/Conf.php b/TencentYoutuyun/Conf.php index 9a30917..3f0a977 100644 --- a/TencentYoutuyun/Conf.php +++ b/TencentYoutuyun/Conf.php @@ -29,7 +29,7 @@ public static function getUA() { // 初始化 应用信息 - public static function setAppInfo($appid, $secretId, $secretKey, $userid,$end_point) { + public static function setAppInfo($appid, $secretId, $secretKey, $userid, $end_point = self::API_YOUTU_END_POINT) { self::$APPID = $appid; self::$SECRET_ID = $secretId; diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 46580c6..44d01c7 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1206,6 +1206,268 @@ public static function imagetagurl($url) { "url" => $url, ); + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function imageporn($image_path) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imageporn'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @param $url 图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function imagepornurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imageporn'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + + + /** + * @param $url 图片url + * @param $card_type 身份证照片类型,0 表示身份证正面, 1表示身份证反面 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function idcardocr($image_path, $card_type = 0, $seq = '') { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/idcardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + "seq" => $seq, + "card_type" => $card_type, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @param $url 图片url + * @param $card_type 身份证照片类型,0 表示身份证正面, 1表示身份证反面 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function idcardocrurl($url, $card_type, $seq = '') { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/idcardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "seq" => $seq, + "card_type" => $card_type, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + + /** + * @param $image_path 待检测的路径 + * @param $retimage 是否返回名片图像 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function namecardocr($image_path, $retimage = 1, $seq = '') { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/namecardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + "app_id" => Conf::$APPID, + "image" => base64_encode($image_data), + "seq" => $seq, + "retimage"=> (bool)$retimage + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * @param $url 图片url + * @param $retimage 是否返回名片图像 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function namecardocrurl($url, $retimage = 1, $seq = '') { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/namecardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + "app_id" => Conf::$APPID, + "url" => $url, + "seq" => $seq, + "retimage"=> (bool)$retimage + ); + + $req = array( 'url' => $postUrl, 'method' => 'post', diff --git a/sample.php b/sample.php index 800f94c..f061391 100644 --- a/sample.php +++ b/sample.php @@ -5,23 +5,43 @@ use TencentYoutuyun\Conf; -// 设置APP 鉴权信息 -$appid=''; -$secretId=''; -$secretKey=''; -$userid=''; +// 设置APP 鉴权信息 请在http://open.youtu.qq.com 创建应用 +$appid='10000010'; +$secretId='AKIDOiuFc9M6mTtMUmK8GbWMczOKyWn464Rn'; +$secretKey='mSh3ULXSJ1qMk6gXDEvbLJJwuVP1jelY'; +$userid='267266206'; -Conf::setAppInfo($appid, $secretId, $secretKey, $userid); + +Conf::setAppInfo($appid, $secretId, $secretKey, $userid ); // 人脸检测 调用列子 -$uploadRet = YouTu::detectface('a.jpg', 1); -var_dump($uploadRet); +//$uploadRet = YouTu::detectface('a.jpg', 1); +//var_dump($uploadRet); // 人脸定位 调用demo -$uploadRet = YouTu::faceshape('a.jpg', 1); +//$uploadRet = YouTu::faceshape('a.jpg', 1); +//var_dump($uploadRet); + +//黄图识别 +//$uploadRet = YouTu::imageporn('test.jpg', 1); +//var_dump($uploadRet); +//$uploadRet = YouTu::imagepornurl('http://open.youtu.qq.com/content/img/product/face/face_05.jpg', 1); +//var_dump($uploadRet); + +//身份证ocr + +//$uploadRet = YouTu::idcardocr('test.jpg', 1); +//var_dump($uploadRet); +//$uploadRet = YouTu::idcardocrurl('http://open.youtu.qq.com/content/img/product/face/face_05.jpg', 1); +//var_dump($uploadRet); + +//名片 +$uploadRet = YouTu::namecardocr('test.jpg', 1); +var_dump($uploadRet); +$uploadRet = YouTu::namecardocrurl('http://open.youtu.qq.com/content/img/product/face/face_05.jpg', 1); var_dump($uploadRet); ?> From 22ffc9192357461658bb9b51b9340d5b126d9324 Mon Sep 17 00:00:00 2001 From: tanguofu Date: Thu, 28 Apr 2016 11:39:08 +0800 Subject: [PATCH 13/42] fix bugs --- sample.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sample.php b/sample.php index f061391..4b228d9 100644 --- a/sample.php +++ b/sample.php @@ -7,10 +7,10 @@ // 设置APP 鉴权信息 请在http://open.youtu.qq.com 创建应用 -$appid='10000010'; -$secretId='AKIDOiuFc9M6mTtMUmK8GbWMczOKyWn464Rn'; -$secretKey='mSh3ULXSJ1qMk6gXDEvbLJJwuVP1jelY'; -$userid='267266206'; +$appid='x'; +$secretId='x'; +$secretKey='x'; +$userid='x'; Conf::setAppInfo($appid, $secretId, $secretKey, $userid ); From 6acea3c9246bf58edfbb96766c18cf15aed2a5e8 Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Thu, 2 Jun 2016 17:28:19 +0800 Subject: [PATCH 14/42] change --- TencentYoutuyun/Youtu.php | 132 +++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 46580c6..a920466 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -8,14 +8,14 @@ class YouTu const EXPIRED_SECONDS = 2592000; const HTTP_BAD_REQUEST = 400; const HTTP_SERVER_ERROR = 500; - + /** - * return the status message + * return the status message */ public static function statusText($status) { $statusText = 'UNKOWN'; - + switch ($status) { case 0: $statusText = 'CONNECT_FAIL'; @@ -61,11 +61,11 @@ public static function statusText($status) { } /** - * return the status message + * return the status message */ public static function getStatusText() { - - $status=Http::info()['http_code']; + $info=Http::info(); + $status=$info['http_code']; return self::statusText($status); } @@ -78,7 +78,7 @@ public static function getStatusText() { public static function detectface($image_path, $isbigface) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -109,11 +109,11 @@ public static function detectface($image_path, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } @@ -149,11 +149,11 @@ public static function detectfaceurl($url, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } @@ -166,7 +166,7 @@ public static function detectfaceurl($url, $isbigface) { public static function faceshape($image_path, $isbigface) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -197,13 +197,13 @@ public static function faceshape($image_path, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } - + /** * @brief faceshapeurl * @param url 图片url @@ -236,11 +236,11 @@ public static function faceshapeurl($url, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } @@ -290,13 +290,13 @@ public static function facecompare($image_path_a, $image_path_b) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } - + /** * @brief facecompareurl * @param urlA 待比对的A图片url @@ -328,14 +328,14 @@ public static function facecompareurl($urlA, $urlB) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } - + /** * @brief faceverify @@ -346,7 +346,7 @@ public static function facecompareurl($urlA, $urlB) { public static function faceverify($image_path,$person_id) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -375,10 +375,10 @@ public static function faceverify($image_path,$person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -412,10 +412,10 @@ public static function faceverifyurl($url,$person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -426,11 +426,11 @@ public static function faceverifyurl($url,$person_id) { * @param image_path 待识别的图片路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ - + public static function faceidentify($image_path,$group_id) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -459,10 +459,10 @@ public static function faceidentify($image_path,$group_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -472,7 +472,7 @@ public static function faceidentify($image_path,$group_id) { * @param url 待识别的图片的url * @return 返回的结果,JSON字符串,字段参见API文档 */ - + public static function faceidentifyurl($url,$group_id) { $expired = time() + self::EXPIRED_SECONDS; @@ -497,10 +497,10 @@ public static function faceidentifyurl($url,$group_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -513,7 +513,7 @@ public static function faceidentifyurl($url,$group_id) { * @param person_tag 备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - + public static function newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="") { $real_image_path = realpath($image_path); if (!file_exists($real_image_path)) @@ -526,7 +526,7 @@ public static function newperson($image_path, $person_id, array $group_ids, $per $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); - + $post_data = array( "app_id" => Conf::$APPID, "image" => base64_encode($image_data), @@ -548,10 +548,10 @@ public static function newperson($image_path, $person_id, array $group_ids, $per ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -564,7 +564,7 @@ public static function newperson($image_path, $person_id, array $group_ids, $per * @param person_tag 备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - + public static function newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="") { $expired = time() + self::EXPIRED_SECONDS; @@ -592,10 +592,10 @@ public static function newpersonurl($url, $person_id, array $group_ids, $person_ ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -628,10 +628,10 @@ public static function delperson($person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -676,10 +676,10 @@ public static function addface($person_id,array $image_path_arr, $facetag="") { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -691,7 +691,7 @@ public static function addface($person_id,array $image_path_arr, $facetag="") { * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function addfaceurl($person_id,array $url_arr, $facetag="") { - + $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . 'youtu/api/addface'; $sign = Auth::appSign($expired, Conf::$USER_ID); @@ -715,10 +715,10 @@ public static function addfaceurl($person_id,array $url_arr, $facetag="") { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -753,10 +753,10 @@ public static function delface($person_id,array $face_id_arr) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -793,10 +793,10 @@ public static function setinfo($person_name,$person_id, $person_tag) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -829,10 +829,10 @@ public static function getinfo($person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -863,10 +863,10 @@ public static function getgroupids() { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -899,10 +899,10 @@ public static function getpersonids($group_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -935,10 +935,10 @@ public static function getfaceids($person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -971,10 +971,10 @@ public static function getfaceinfo($face_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } From 51e403087340acb9efb28c839675995567e01031 Mon Sep 17 00:00:00 2001 From: Tencent-Youtu Date: Fri, 3 Jun 2016 10:29:04 +0800 Subject: [PATCH 15/42] change --- TencentYoutuyun/Youtu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 44d01c7..27841c0 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -65,7 +65,8 @@ public static function statusText($status) { */ public static function getStatusText() { - $status=Http::info()['http_code']; + $info=Http::info(); + $status=$info['http_code']; return self::statusText($status); } From 8c9a179c2a45c8ba71d598b43cd0a6d86f0d5908 Mon Sep 17 00:00:00 2001 From: TencentYouTu Date: Tue, 12 Jul 2016 16:51:27 +0800 Subject: [PATCH 16/42] modify --- TencentYoutuyun/Youtu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index a920466..cbf0258 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -63,7 +63,8 @@ public static function statusText($status) { /** * return the status message */ - public static function getStatusText() { + public static function getStatusText() + { $info=Http::info(); $status=$info['http_code']; return self::statusText($status); From 1a7a6aae8685c515b729f0a65011986145d3b475 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 20 Oct 2016 16:23:13 +0800 Subject: [PATCH 17/42] v2 v2 --- TencentYoutuyun/Conf.php | 15 +- TencentYoutuyun/Youtu.php | 558 +++++++++++++++++++++++++------------- 2 files changed, 383 insertions(+), 190 deletions(-) diff --git a/TencentYoutuyun/Conf.php b/TencentYoutuyun/Conf.php index 3f0a977..da79487 100644 --- a/TencentYoutuyun/Conf.php +++ b/TencentYoutuyun/Conf.php @@ -3,21 +3,22 @@ class Conf { - const PKG_VERSION = '1.0.*'; + const PKG_VERSION = '1.0.*'; - const API_YOUTU_END_POINT = 'http://api.youtu.qq.com/'; + const API_YOUTU_END_POINT = 'https://vip-api.youtu.qq.com/'; + const API_YOUTU_CHARGE_END_POINT = 'http://api.youtu.qq.com/'; const API_TENCENTYUN_END_POINT = 'https://youtu.api.qcloud.com/'; // 请到 open.youtu.qq.com查看您对应的appid相关信息并填充 - // 请统一 通过 setAppInfo 设置 + // 请统一 通过 setAppInfo 设置 public static $APPID = ''; public static $SECRET_ID = ''; public static $SECRET_KEY = ''; public static $END_POINT = ''; - + // 开发者 QQ public static $USER_ID = ''; @@ -25,12 +26,12 @@ class Conf public static function getUA() { return 'YoutuPHP/'.self::PKG_VERSION.' ('.php_uname().')'; } - - // 初始化 应用信息 + + // 初始化 应用信息 public static function setAppInfo($appid, $secretId, $secretKey, $userid, $end_point = self::API_YOUTU_END_POINT) { - + self::$APPID = $appid; self::$SECRET_ID = $secretId; self::$SECRET_KEY = $secretKey; diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 27841c0..624522e 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -8,15 +8,14 @@ class YouTu const EXPIRED_SECONDS = 2592000; const HTTP_BAD_REQUEST = 400; const HTTP_SERVER_ERROR = 500; - + /** - * return the status message + * return the status message */ - public static function statusText($status) { - - $statusText = 'UNKOWN'; - - switch ($status) { + public static function statusText($status) + { + switch ($status) + { case 0: $statusText = 'CONNECT_FAIL'; break; @@ -56,12 +55,15 @@ public static function statusText($status) { case 504: $statusText = 'GATEWAY_TIME_OUT'; break; + default: + $statusText =$status; + break; } return $statusText; } -/** - * return the status message + /** + * return the status message */ public static function getStatusText() { @@ -79,7 +81,7 @@ public static function getStatusText() { public static function detectface($image_path, $isbigface) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -91,9 +93,9 @@ public static function detectface($image_path, $isbigface) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "mode" => $isbigface + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'mode' => $isbigface ); $req = array( @@ -110,11 +112,11 @@ public static function detectface($image_path, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } @@ -131,9 +133,9 @@ public static function detectfaceurl($url, $isbigface) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "mode" => $isbigface + 'app_id' => Conf::$APPID, + 'url' => $url, + 'mode' => $isbigface ); $req = array( @@ -150,11 +152,11 @@ public static function detectfaceurl($url, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } @@ -167,7 +169,7 @@ public static function detectfaceurl($url, $isbigface) { public static function faceshape($image_path, $isbigface) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -179,9 +181,9 @@ public static function faceshape($image_path, $isbigface) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "mode" => $isbigface + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'mode' => $isbigface ); $req = array( @@ -198,13 +200,13 @@ public static function faceshape($image_path, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } - + /** * @brief faceshapeurl * @param url 图片url @@ -218,9 +220,9 @@ public static function faceshapeurl($url, $isbigface) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "mode" => $isbigface + 'app_id' => Conf::$APPID, + 'url' => $url, + 'mode' => $isbigface ); $req = array( @@ -237,11 +239,11 @@ public static function faceshapeurl($url, $isbigface) { $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } - + } + return $ret; } @@ -273,9 +275,9 @@ public static function facecompare($image_path_a, $image_path_b) { $image_data_b = file_get_contents($real_image_path_b); $post_data = array( - "app_id" => Conf::$APPID, - "imageA" => base64_encode($image_data_a), - "imageB" => base64_encode($image_data_b) + 'app_id' => Conf::$APPID, + 'imageA' => base64_encode($image_data_a), + 'imageB' => base64_encode($image_data_b) ); $req = array( @@ -291,13 +293,13 @@ public static function facecompare($image_path_a, $image_path_b) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } - + /** * @brief facecompareurl * @param urlA 待比对的A图片url @@ -311,9 +313,9 @@ public static function facecompareurl($urlA, $urlB) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "urlA" => $urlA, - "urlB" => $urlB + 'app_id' => Conf::$APPID, + 'urlA' => $urlA, + 'urlB' => $urlB ); $req = array( @@ -329,14 +331,14 @@ public static function facecompareurl($urlA, $urlB) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } - + /** * @brief faceverify @@ -347,7 +349,7 @@ public static function facecompareurl($urlA, $urlB) { public static function faceverify($image_path,$person_id) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -359,9 +361,9 @@ public static function faceverify($image_path,$person_id) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "person_id" =>$person_id, + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'person_id' =>$person_id, ); $req = array( @@ -376,10 +378,10 @@ public static function faceverify($image_path,$person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -396,9 +398,9 @@ public static function faceverifyurl($url,$person_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "person_id" =>$person_id, + 'app_id' => Conf::$APPID, + 'url' => $url, + 'person_id' =>$person_id, ); $req = array( @@ -413,10 +415,10 @@ public static function faceverifyurl($url,$person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -427,11 +429,11 @@ public static function faceverifyurl($url,$person_id) { * @param image_path 待识别的图片路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ - + public static function faceidentify($image_path,$group_id) { $real_image_path = realpath($image_path); - + if (!file_exists($real_image_path)) { return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); @@ -443,9 +445,9 @@ public static function faceidentify($image_path,$group_id) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "group_id" =>$group_id, + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'group_id' =>$group_id, ); $req = array( @@ -460,10 +462,10 @@ public static function faceidentify($image_path,$group_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -473,7 +475,7 @@ public static function faceidentify($image_path,$group_id) { * @param url 待识别的图片的url * @return 返回的结果,JSON字符串,字段参见API文档 */ - + public static function faceidentifyurl($url,$group_id) { $expired = time() + self::EXPIRED_SECONDS; @@ -481,9 +483,9 @@ public static function faceidentifyurl($url,$group_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "group_id" =>$group_id, + 'app_id' => Conf::$APPID, + 'url' => $url, + 'group_id' =>$group_id, ); $req = array( @@ -498,10 +500,10 @@ public static function faceidentifyurl($url,$group_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -514,8 +516,8 @@ public static function faceidentifyurl($url,$group_id) { * @param person_tag 备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - - public static function newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="") { + + public static function newperson($image_path, $person_id, array $group_ids, $person_name='', $person_tag='') { $real_image_path = realpath($image_path); if (!file_exists($real_image_path)) { @@ -527,14 +529,14 @@ public static function newperson($image_path, $person_id, array $group_ids, $per $sign = Auth::appSign($expired, Conf::$USER_ID); $image_data = file_get_contents($real_image_path); - + $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "person_id" =>$person_id, - "group_ids" =>$group_ids, - "person_name" =>$person_name, - "tag" => $person_tag + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'person_id' =>$person_id, + 'group_ids' =>$group_ids, + 'person_name' =>$person_name, + 'tag' => $person_tag ); $req = array( @@ -549,10 +551,10 @@ public static function newperson($image_path, $person_id, array $group_ids, $per ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -565,20 +567,20 @@ public static function newperson($image_path, $person_id, array $group_ids, $per * @param person_tag 备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - - public static function newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="") { + + public static function newpersonurl($url, $person_id, array $group_ids, $person_name='', $person_tag='') { $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . 'youtu/api/newperson'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "person_id" =>$person_id, - "group_ids" =>$group_ids, - "person_name" =>$person_name, - "tag" => $person_tag + 'app_id' => Conf::$APPID, + 'url' => $url, + 'person_id' =>$person_id, + 'group_ids' =>$group_ids, + 'person_name' =>$person_name, + 'tag' => $person_tag ); $req = array( @@ -593,10 +595,10 @@ public static function newpersonurl($url, $person_id, array $group_ids, $person_ ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -613,8 +615,8 @@ public static function delperson($person_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "person_id" =>$person_id, + 'app_id' => Conf::$APPID, + 'person_id' =>$person_id, ); $req = array( @@ -629,10 +631,10 @@ public static function delperson($person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -644,7 +646,7 @@ public static function delperson($person_id) { * @param facetag 人脸备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function addface($person_id,array $image_path_arr, $facetag="") { + public static function addface($person_id,array $image_path_arr, $facetag='') { $image_data_arr=array(); foreach($image_path_arr as $one_path){ if (!file_exists($one_path)) @@ -659,10 +661,10 @@ public static function addface($person_id,array $image_path_arr, $facetag="") { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "images" => $image_data_arr, - "person_id" =>$person_id, - "tag" => $facetag + 'app_id' => Conf::$APPID, + 'images' => $image_data_arr, + 'person_id' =>$person_id, + 'tag' => $facetag ); $req = array( @@ -677,10 +679,10 @@ public static function addface($person_id,array $image_path_arr, $facetag="") { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -691,17 +693,17 @@ public static function addface($person_id,array $image_path_arr, $facetag="") { * @param facetag 人脸备注信息,用户自解释字段 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function addfaceurl($person_id,array $url_arr, $facetag="") { - + public static function addfaceurl($person_id,array $url_arr, $facetag='') { + $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . 'youtu/api/addface'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "urls" => $url_arr, - "person_id" =>$person_id, - "tag" => $facetag + 'app_id' => Conf::$APPID, + 'urls' => $url_arr, + 'person_id' =>$person_id, + 'tag' => $facetag ); $req = array( @@ -716,10 +718,10 @@ public static function addfaceurl($person_id,array $url_arr, $facetag="") { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -737,9 +739,9 @@ public static function delface($person_id,array $face_id_arr) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "face_ids" => $face_id_arr, - "person_id" =>$person_id, + 'app_id' => Conf::$APPID, + 'face_ids' => $face_id_arr, + 'person_id' =>$person_id, ); $req = array( @@ -754,10 +756,10 @@ public static function delface($person_id,array $face_id_arr) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -776,10 +778,10 @@ public static function setinfo($person_name,$person_id, $person_tag) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "person_name" => $person_name, - "person_id" =>$person_id, - "tag" => $person_tag + 'app_id' => Conf::$APPID, + 'person_name' => $person_name, + 'person_id' =>$person_id, + 'tag' => $person_tag ); $req = array( @@ -794,10 +796,10 @@ public static function setinfo($person_name,$person_id, $person_tag) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -814,8 +816,8 @@ public static function getinfo($person_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "person_id" =>$person_id, + 'app_id' => Conf::$APPID, + 'person_id' =>$person_id, ); $req = array( @@ -830,10 +832,10 @@ public static function getinfo($person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -849,7 +851,7 @@ public static function getgroupids() { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID + 'app_id' => Conf::$APPID ); $req = array( @@ -864,10 +866,10 @@ public static function getgroupids() { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -884,8 +886,8 @@ public static function getpersonids($group_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "group_id" =>$group_id, + 'app_id' => Conf::$APPID, + 'group_id' =>$group_id, ); $req = array( @@ -900,10 +902,10 @@ public static function getpersonids($group_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -920,8 +922,8 @@ public static function getfaceids($person_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "person_id" =>$person_id, + 'app_id' => Conf::$APPID, + 'person_id' =>$person_id, ); $req = array( @@ -936,10 +938,10 @@ public static function getfaceids($person_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -956,8 +958,8 @@ public static function getfaceinfo($face_id) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "face_id" =>$face_id, + 'app_id' => Conf::$APPID, + 'face_id' =>$face_id, ); $req = array( @@ -972,10 +974,10 @@ public static function getfaceinfo($face_id) { ); $rsp = Http::send($req); $ret = json_decode($rsp, true); - + if(!$ret){ return self::getStatusText(); - } + } return $ret; } @@ -998,8 +1000,8 @@ public static function fuzzydetect($image_path) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), ); $req = array( @@ -1039,8 +1041,8 @@ public static function fuzzydetecturl($url) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, + 'app_id' => Conf::$APPID, + 'url' => $url, ); $req = array( @@ -1084,8 +1086,8 @@ public static function fooddetect($image_path) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), ); $req = array( @@ -1121,8 +1123,8 @@ public static function fooddetecturl($url) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, + 'app_id' => Conf::$APPID, + 'url' => $url, ); $req = array( @@ -1166,8 +1168,8 @@ public static function imagetag($image_path) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), ); $req = array( @@ -1203,8 +1205,8 @@ public static function imagetagurl($url) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, + 'app_id' => Conf::$APPID, + 'url' => $url, ); $req = array( @@ -1228,7 +1230,7 @@ public static function imagetagurl($url) { return $ret; } - + /** * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 @@ -1248,8 +1250,8 @@ public static function imageporn($image_path) { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), ); $req = array( @@ -1285,8 +1287,8 @@ public static function imagepornurl($url) { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, + 'app_id' => Conf::$APPID, + 'url' => $url, ); $req = array( @@ -1310,9 +1312,9 @@ public static function imagepornurl($url) { return $ret; } - - - + + + /** * @param $url 图片url * @param $card_type 身份证照片类型,0 表示身份证正面, 1表示身份证反面 @@ -1333,10 +1335,10 @@ public static function idcardocr($image_path, $card_type = 0, $seq = '') { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "seq" => $seq, - "card_type" => $card_type, + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'seq' => $seq, + 'card_type' => $card_type, ); $req = array( @@ -1373,10 +1375,10 @@ public static function idcardocrurl($url, $card_type, $seq = '') { $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "seq" => $seq, - "card_type" => $card_type, + 'app_id' => Conf::$APPID, + 'url' => $url, + 'seq' => $seq, + 'card_type' => $card_type, ); $req = array( @@ -1400,8 +1402,8 @@ public static function idcardocrurl($url, $card_type, $seq = '') { return $ret; } - - + + /** * @param $image_path 待检测的路径 * @param $retimage 是否返回名片图像 @@ -1422,10 +1424,10 @@ public static function namecardocr($image_path, $retimage = 1, $seq = '') { $image_data = file_get_contents($real_image_path); $post_data = array( - "app_id" => Conf::$APPID, - "image" => base64_encode($image_data), - "seq" => $seq, - "retimage"=> (bool)$retimage + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'seq' => $seq, + 'retimage'=> (bool)$retimage ); $req = array( @@ -1455,19 +1457,20 @@ public static function namecardocr($image_path, $retimage = 1, $seq = '') { * @param $retimage 是否返回名片图像 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function namecardocrurl($url, $retimage = 1, $seq = '') { + public static function namecardocrurl($url, $retimage = 1, $seq = '') + { $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . 'youtu/ocrapi/namecardocr'; $sign = Auth::appSign($expired, Conf::$USER_ID); - + $post_data = array( - "app_id" => Conf::$APPID, - "url" => $url, - "seq" => $seq, - "retimage"=> (bool)$retimage + 'app_id' => Conf::$APPID, + 'url' => $url, + 'seq' => $seq, + 'retimage'=> (bool)$retimage ); - + $req = array( 'url' => $postUrl, @@ -1490,6 +1493,195 @@ public static function namecardocrurl($url, $retimage = 1, $seq = '') { return $ret; } -} + public static function livegetfour($seq = '') + { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/openliveapi/livegetfour'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'seq' => $seq + ); + + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + public static function livedetectfour($validate_data,$video_path,$card_path,$compare_card=false,$seq = '') + { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/openliveapi/livedetectfour'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $real_video_path = realpath($video_path); + if (!file_exists($real_video_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$video_path.' not exists', 'data' => array()); + } + + $video_data = file_get_contents($real_video_path); + + if($compare_card) + { + $real_card_path = realpath($card_path); + if (!file_exists($real_card_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$card_path.' not exists', 'data' => array()); + } + + $card_data = file_get_contents($real_card_path); + $post_data = array( + 'app_id' => Conf::$APPID, + 'validate_data' => $validate_data, + 'compare_flag' => true, + 'video' => base64_encode($video_data), + 'card' => base64_encode($card_data), + 'seq' => $seq + ); + } + else + { + $post_data = array( + 'app_id' => Conf::$APPID, + 'validate_data' => $validate_data, + 'compare_flag' => false, + 'video' => base64_encode($video_data), + 'seq' => $seq + ); + } + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + public static function idcardlivedetectfour($idcard_number,$idcard_name,$validate_data,$video_path,$seq = '') + { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/openliveapi/idcardlivedetectfour'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $real_video_path = realpath($video_path); + if (!file_exists($real_video_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$video_path.' not exists', 'data' => array()); + } + + $video_data = file_get_contents($real_video_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'idcard_number' => $idcard_number, + 'idcard_name' => $idcard_name, + 'validate_data' => $validate_data, + 'video' => base64_encode($video_data), + 'seq' => $seq + ); + + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + public static function idcardfacecompare($idcard_number,$idcard_name,$image_path,$seq = '') + { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/openliveapi/idcardfacecompare'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $real_image_path = realpath($image_path); + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'idcard_number' => $idcard_number, + 'idcard_name' => $idcard_name, + 'image' => base64_encode($image_data), + 'seq' => $seq + ); + + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + +} From 3a774f5444209e57483dd8425d1937274c9c05af Mon Sep 17 00:00:00 2001 From: tyronetao Date: Mon, 24 Oct 2016 16:02:42 +0800 Subject: [PATCH 18/42] fix end point --- TencentYoutuyun/Conf.php | 4 ++-- sample.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TencentYoutuyun/Conf.php b/TencentYoutuyun/Conf.php index da79487..6417c7d 100644 --- a/TencentYoutuyun/Conf.php +++ b/TencentYoutuyun/Conf.php @@ -5,8 +5,8 @@ class Conf { const PKG_VERSION = '1.0.*'; - const API_YOUTU_END_POINT = 'https://vip-api.youtu.qq.com/'; - const API_YOUTU_CHARGE_END_POINT = 'http://api.youtu.qq.com/'; + const API_YOUTU_END_POINT = 'http://api.youtu.qq.com/'; + const API_YOUTU_CHARGE_END_POINT = 'https://vip-api.youtu.qq.com/'; const API_TENCENTYUN_END_POINT = 'https://youtu.api.qcloud.com/'; diff --git a/sample.php b/sample.php index 4b228d9..ca8de24 100644 --- a/sample.php +++ b/sample.php @@ -13,7 +13,7 @@ $userid='x'; -Conf::setAppInfo($appid, $secretId, $secretKey, $userid ); +Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT ); // 人脸检测 调用列子 From 4c4358eafb207b50bdeaf954536e503a109daa0c Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 3 Nov 2016 20:03:26 +0800 Subject: [PATCH 19/42] update readme --- README.md | 410 +++++++++++++++++++++------------------ TencentYoutuyun/Conf.php | 2 +- 2 files changed, 217 insertions(+), 195 deletions(-) diff --git a/README.md b/README.md index e5bd35c..0f60444 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,17 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) ## 名词 -- `AppId` 平台添加应用后分配的AppId -- `SecretId` 平台添加应用后分配的SecretId -- `SecretKey` 平台添加应用后分配的SecretKey -- `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 + - `AppId` 平台添加应用后分配的AppId + - `SecretId` 平台添加应用后分配的SecretId + - `SecretKey` 平台添加应用后分配的SecretKey + - `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 + +##说明 +* https://api.youtu.qq.com/ +* df ## 使用示例 -``` // 引入SDK require('./include.php'); use TencentYoutuyun\Youtu; @@ -29,273 +32,292 @@ $secretId='your secretId '; $secretKey='your secretKey'; $userid='your qq'; -//根据你使用的平台选择一种初始化方式 -//优图开放平台初始化 +###根据你使用的平台选择一种初始化方式 +* 优图开放平台初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT); -//腾讯云初始化 + +* 优图开放平台核身服务初始化(**核身服务目前仅支持核身专有接口,需要联系商务开通**) +Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_CHARGE_END_POINT); + +* 腾讯云初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); -//人脸检测接口调用 +//人脸检测接口调用示例 $uploadRet = YouTu::detectface('test.jpg', 1); var_dump($uploadRet); -``` + ### `鉴权` 接口调用时 计算签名鉴权相关逻辑。 -#### `Auth::appSign($expired, $userid)` +* `Auth::appSign($expired, $userid)` -获取签名,依赖`conf`中的配置项。 + 获取签名,依赖`conf`中的配置项。 -- 参数 - - `expired` 过期时间,UNIX时间戳, 计算的签名在过期时间之前有效. - - `userid` 业务中的用户标识,填写用户QQ号即可 + - 参数 + - `expired` 过期时间,UNIX时间戳, 计算的签名在过期时间之前有效. + - `userid` 业务中的用户标识,填写用户QQ号即可 - 返回值: 签名 -#### 其它 - -- `auth.AUTH_PARAMS_ERROR` 参数错误常量(-1) -- `auth.AUTH_SECRET_ID_KEY_ERROR` 密钥ID或者密钥KEY错误常量(-2) +- 其它 + + - `auth.AUTH_PARAMS_ERROR` 参数错误常量(-1) + - `auth.AUTH_SECRET_ID_KEY_ERROR` 密钥ID或者密钥KEY错误常量(-2) ### `SDK API介绍` -优图相关API封装,均为同步函数。 +优图开放平台相关API封装,均为同步函数 + +**** + +* `YouTu::detectface($image_path, $isbigface)` +* `YouTu::detectfaceurl($url, $isbigface)` + 人脸检测,检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性。位置包括(x, y, w, h),面部属性包括性别(gender)、年龄(age) + 表情(expression)、眼镜(glass)和姿态(pitch,roll,yaw)。 -#### `YouTu::detectface($image_path, $isbigface)` -#### `YouTu::detectfaceurl($url, $isbigface)` + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 -人脸检测,检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性。位置包括(x, y, w, h),面部属性包括性别(gender)、年龄(age) -表情(expression)、眼镜(glass)和姿态(pitch,roll,yaw)。 -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url - - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::faceshape($image_path, $isbigface)` +* `YouTu::faceshapeurl($url, $isbigface)` + 人脸定位,检测给定图片中人脸的五官。对请求图片进行人脸配准,计算构成人脸轮廓的88个点, + 包括眉毛(左右各8点)、眼睛(左右各8点)、鼻子(13点)、嘴巴(22点)、脸型轮廓(21点) -#### `YouTu::faceshape($image_path, $isbigface)` -#### `YouTu::faceshapeurl($url, $isbigface)` + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 -人脸定位,检测给定图片中人脸的五官。对请求图片进行人脸配准,计算构成人脸轮廓的88个点, -包括眉毛(左右各8点)、眼睛(左右各8点)、鼻子(13点)、嘴巴(22点)、脸型轮廓(21点) -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url - - `$isbigface` 是否大脸模式 0表示检测所有人脸, 1表示只检测照片最大人脸 适合单人照模式 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::facecompare($image_path_a, $image_path_b)` +* `YouTu::facecompareurl($urlA, $urlB)` + 人脸对比,计算两个Face的相似性以及五官相似度。 -#### `YouTu::facecompare($image_path_a, $image_path_b)` -#### `YouTu::facecompareurl($urlA, $urlB)` + - 参数 + - `$image_path_a` 第一张待检测图片路径 + - `$image_path_b` 第二张待检测图片路径 + - `$urlA` 第一张图片url + - `$urlB` 第二张图片url -人脸对比,计算两个Face的相似性以及五官相似度。 -- 参数 - - `$image_path_a` 第一张待检测图片路径 - - `$image_path_b` 第二张待检测图片路径 - - `$urlA` 第一张图片url - - `$urlB` 第二张图片url -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::faceverify($image_path, $person_id)` +* `YouTu::faceverifyurl($url,$person_id)` -#### `YouTu::faceverify($image_path, $person_id)` -#### `YouTu::faceverifyurl($url,$person_id)` + 人脸验证,给定一个Face和一个Person,返回是否是同一个人的判断以及置信度。 -人脸验证,给定一个Face和一个Person,返回是否是同一个人的判断以及置信度。 + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$person_id` 待验证的Person -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url - - `$person_id` 待验证的Person -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 -#### `YouTu::faceidentify($image_path, $group_id)` -#### `YouTu::faceidentifyurl($url,$group_id)` +* `YouTu::faceidentify($image_path, $group_id)` +* `YouTu::faceidentifyurl($url,$group_id)` 人脸识别,对于一个待识别的人脸图片,在一个Group中识别出最相似的Top5 Person作为其身份返回,返回的Top5中按照相似度从大到小排列。 -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url - - `$group_id` 需要识别的人 所在的组 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$group_id` 需要识别的人 所在的组 + + +* `YouTu::newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="")` +* `YouTu::newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="")` -#### `YouTu::newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="")` -#### `YouTu::newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="")` + 个体创建,创建一个Person,并将Person放置到$group_ids指定的组当中。 -个体创建,创建一个Person,并将Person放置到$group_ids指定的组当中。 + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$person_id` 个体id + - `$person_name` 个体的名字 + - `$group_ids` 要加入的组的列表(数组) + - `$person_name` 个体名称 + - `$person_tag` 备注信息,用户自解释字段 -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url - - `$person_id` 个体id - - `$person_name` 个体的名字 - - `$group_ids` 要加入的组的列表(数组) - - `$person_name` 个体名称 - - `$person_tag` 备注信息,用户自解释字段 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::delperson($person_id)` -#### `YouTu::delperson($person_id)` + 删除一个Person -删除一个Person + - 参数 + - `$person_id` 个体Person -- 参数 - - `$person_id` 个体Person -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::addface($person_id, $images, $facetag)` +* `YouTu::addfaceurl($person_id, $url_arr, $facetag="")` -#### `YouTu::addface($person_id, $images, $facetag)` -#### `YouTu::addfaceurl($person_id, $url_arr, $facetag="")` + 添加人脸,在创建一个Person后, 增加person下面的人脸, 可以用于后面的比对。 -添加人脸,在创建一个Person后, 增加person下面的人脸, 可以用于后面的比对。 + - 参数 + - `$person_id` 个体Person + - `$images` 待检测图片路径(数组) + - `$url_arr` 图片url(数组) + - `$facetag` 人脸自定义标签 -- 参数 - - `$person_id` 个体Person - - `$images` 待检测图片路径(数组) - - `$url_arr` 图片url(数组) - - `$facetag` 人脸自定义标签 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::delface($person_id, $face_ids)` -#### `YouTu::delface($person_id, $face_ids)` + 删除人脸,删除一个person下的face,包括特征,属性和face_id。 -删除人脸,删除一个person下的face,包括特征,属性和face_id。 + - 参数 + - `$person_id` 个体Person + - `$face_ids` 要删除的faceId列表(数组) -- 参数 - - `$person_id` 个体Person - - `$face_ids` 要删除的faceId列表(数组) -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::setinfo($person_name, $person_id, $tag)` -#### `YouTu::setinfo($person_name, $person_id, $tag)` + 设置Person的信息 -设置Person的信息 + - 参数 + - `$person_name` 个体Person的name + - `$person_id` 个体Person + - `$tag` 个体Person的tag, 用户自解释字段 -- 参数 - - `$person_name` 个体Person的name - - `$person_id` 个体Person - - `$tag` 个体Person的tag, 用户自解释字段 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::getinfo($person_id)` -#### `YouTu::getinfo($person_id)` + 获取一个Person的信息,包括name、id、$tag、相关的face以及groups等信息。 -获取一个Person的信息,包括name、id、$tag、相关的face以及groups等信息。 + - 参数 + - `$person_id` 个体Person -- 参数 - - `$person_id` 个体Person -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::getgroupids()` -#### `YouTu::getgroupids()` + 获取一个AppId下所有group列表 -获取一个AppId下所有group列表 + - 返回值 + - 返回的结果,JSON字符串,字段参见API文档 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::getpersonIds($group_id)` -#### `YouTu::getpersonIds($group_id)` + 获取一个组Group中所有person列表 -获取一个组Group中所有person列表 + - 参数 + - `$group_id` 组 -- 参数 - - `$group_id` 组 -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::getfaceIds($person_id)` + + 获取一个组person中所有face列表 -#### `YouTu::getfaceIds($person_id)` + - 参数 + - `$person_id` 个体Person -获取一个组person中所有face列表 +* `YouTu::getfaceinfo($face_id)` + + 获取一个face的相关特征信息 -- 参数 - - `$person_id` 个体Person -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 + - 参数 + - `$face_id` 需要获取的faceid -#### `YouTu::getfaceinfo($face_id)` -获取一个face的相关特征信息 +* `YouTu::fuzzydetect($image_path)` +* `YouTu::fuzzydetecturl($url)` -- 参数 - - `$face_id` 需要获取的faceid -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 + 判断一个图像的模糊程度 -#### `YouTu::fuzzydetect($image_path)` -#### `YouTu::fuzzydetecturl($url)` + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url -判断一个图像的模糊程度 -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::fooddetect($image_path)` +* `YouTu::fooddetecturl($url)` + + 识别一个图像是否为美食图像 -#### `YouTu::fooddetect($image_path)` -#### `YouTu::fooddetecturl($url)` + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url -识别一个图像是否为美食图像 -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 +* `YouTu::imagetag($image_path)` +* `YouTu::imagetagurl($url)` -#### `YouTu::imagetag($image_path)` -#### `YouTu::imagetagurl($url)` + 识别一个图像的标签信息,对图像分类 -识别一个图像的标签信息,对图像分类 + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url +* `YouTu::imageporn($image_path)` +* `YouTu::imagepornurl($url)` -- 参数 - - `$image_path` 待检测图片路径 - - `$url` 待检测图片的url -- 返回值 - - 返回的结果,JSON字符串,字段参见API文档 - -#### `YouTu::imageporn($image_path)` -#### `YouTu::imagepornurl($url)` -色情图像检测 -- 参数 - - `$image_path` 待检测图片路径 - - `$url`待检测图片的url - -``` -``` - -#### `YouTu::idcardocr($image_path, $card_type, $seq = '') ` -#### `YouTu::idcardocrurl($url, $card_type, $seq = '') ` -身份证OCR识别 - -- 参数 - - `$image_path` 待检测图片路径 - - `$url`待检测图片的url - - `$card_type` 0 代表输入图像是身份证正面, 1代表输入是身份证反面 - -#### `YouTu::namecardocr($image_path, $retimage, $seq = '') ` -#### `YouTu::namecardocrurl($url, $retimage, $seq = '') ` -名片ocr识别 - -- 参数 - - `$image_path` 待检测图片路径 - - `$url`待检测图片的url - - `$retimage` 0代表不需要返回识别后图像, 1代表需要返回识别后图像 - -``` -``` + 色情图像检测 + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + + +* `YouTu::idcardocr($image_path, $card_type, $seq = '') ` +* `YouTu::idcardocrurl($url, $card_type, $seq = '') ` + + 身份证OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + - `$card_type` 0 代表输入图像是身份证正面, 1代表输入是身份证反面 + + +* `YouTu::namecardocr($image_path, $retimage, $seq = '') ` +* `YouTu::namecardocrurl($url, $retimage, $seq = '') ` + + 名片ocr识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + - `$retimage` 0代表不需要返回识别后图像, 1代表需要返回识别后图像 + +### `核身SDK API介绍` + +优图开放平台相关核身API封装,均为同步函数,需要联系商务开通 +*** +* `YouTu::livegetfour() ` + + 获取四字唇语 + + - 参数 + - `$image_path` 无 + + +* `YouTu::livedetectfour($validate_data,$video_path,$card_path,$compare_card=false,$seq = '') ` + + 带数据源四字人脸核身 + + - 参数 + - `$validate_data` livegetfour获取的四字唇语 + - `$video_path` 视频的路径 + - `$card_path` 对比照片的路径 + - `$compare_card` 视频与照片是否进行对比,true 对比 false不对比 + + +* `YouTu::idcardlivedetectfour($idcard_number,$idcard_name,$validate_data,$video_path,$seq = '') ` + + 不带数据源四字人脸核身 + + - 参数 + - `$idcard_number` 身份证号码 + - `$idcard_name` 身份证姓名 + - `$validate_data` livegetfour获取的四字唇语 + - `$video_path` 视频的路径 + + + +* `YouTu::idcardfacecompare($idcard_number,$idcard_name,$image_path,$seq = '') ` + + 不带数据源人脸对比 + + - 参数 + - `$idcard_number` 身份证号码 + - `$idcard_name` 身份证姓名 + - `$image_path` 照片的路径 更多详情和文档说明参见 [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) [腾讯优图开放平台](http://open.youtu.qq.com) diff --git a/TencentYoutuyun/Conf.php b/TencentYoutuyun/Conf.php index 6417c7d..13d5785 100644 --- a/TencentYoutuyun/Conf.php +++ b/TencentYoutuyun/Conf.php @@ -5,7 +5,7 @@ class Conf { const PKG_VERSION = '1.0.*'; - const API_YOUTU_END_POINT = 'http://api.youtu.qq.com/'; + const API_YOUTU_END_POINT = 'https://api.youtu.qq.com/'; const API_YOUTU_CHARGE_END_POINT = 'https://vip-api.youtu.qq.com/'; const API_TENCENTYUN_END_POINT = 'https://youtu.api.qcloud.com/'; From d11e6c03369a137f1a33b0caea07cb14aadd3059 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 3 Nov 2016 20:05:05 +0800 Subject: [PATCH 20/42] update readme --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 0f60444..5bc6440 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,7 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) - `SecretKey` 平台添加应用后分配的SecretKey - `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 -##说明 -* https://api.youtu.qq.com/ -* df + ## 使用示例 From 50d7752ddeab204532f8d59e67c78ec7b6ba0abc Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 3 Nov 2016 20:06:25 +0800 Subject: [PATCH 21/42] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5bc6440..2e6b9a8 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,13 @@ $secretKey='your secretKey'; $userid='your qq'; ###根据你使用的平台选择一种初始化方式 -* 优图开放平台初始化 +* 优图开放平台初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT); -* 优图开放平台核身服务初始化(**核身服务目前仅支持核身专有接口,需要联系商务开通**) +* 优图开放平台核身服务初始化(**核身服务目前仅支持核身专有接口,需要联系商务开通**) Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_CHARGE_END_POINT); -* 腾讯云初始化 +* 腾讯云初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); //人脸检测接口调用示例 From 8f9ec3c21edbdd806cc256c0bed96cc284fa09d6 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 3 Nov 2016 20:08:12 +0800 Subject: [PATCH 22/42] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2e6b9a8..d4b0c74 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) ## 使用示例 -// 引入SDK +// 引入SDK require('./include.php'); use TencentYoutuyun\Youtu; use TencentYoutuyun\Conf; use TencentYoutuyun\Auth; -// 设置APP 鉴权信息 +// 设置APP 鉴权信息 $appid='your appid'; $secretId='your secretId '; $secretKey='your secretKey'; @@ -40,7 +40,7 @@ Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_CHARGE_E * 腾讯云初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); -//人脸检测接口调用示例 +//人脸检测接口调用示例 $uploadRet = YouTu::detectface('test.jpg', 1); var_dump($uploadRet); From e92ca2bd6a8ef6ce246fe3df84d887c0918c4769 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 3 Nov 2016 20:14:37 +0800 Subject: [PATCH 23/42] update readme --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d4b0c74..1934713 100644 --- a/README.md +++ b/README.md @@ -18,20 +18,23 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) ## 使用示例 -// 引入SDK +##### 引入SDK require('./include.php'); use TencentYoutuyun\Youtu; use TencentYoutuyun\Conf; use TencentYoutuyun\Auth; -// 设置APP 鉴权信息 +##### 设置APP 鉴权信息 $appid='your appid'; $secretId='your secretId '; $secretKey='your secretKey'; $userid='your qq'; -###根据你使用的平台选择一种初始化方式 -* 优图开放平台初始化 + +##### 根据你使用的平台选择一种初始化方式 + + +* 优图开放平台初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT); * 优图开放平台核身服务初始化(**核身服务目前仅支持核身专有接口,需要联系商务开通**) @@ -40,9 +43,9 @@ Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_CHARGE_E * 腾讯云初始化 Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); -//人脸检测接口调用示例 -$uploadRet = YouTu::detectface('test.jpg', 1); -var_dump($uploadRet); +* 人脸检测接口调用示例 + $uploadRet = YouTu::detectface('test.jpg', 1); + var_dump($uploadRet); From 819e5c521a8d9b0c48ad3e4bfcc2e0d326ee87aa Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 3 Nov 2016 20:16:07 +0800 Subject: [PATCH 24/42] update readme --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1934713..191faa2 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,16 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) ## 使用示例 ##### 引入SDK -require('./include.php'); -use TencentYoutuyun\Youtu; -use TencentYoutuyun\Conf; -use TencentYoutuyun\Auth; +require('./include.php'); +use TencentYoutuyun\Youtu; +use TencentYoutuyun\Conf; +use TencentYoutuyun\Auth; ##### 设置APP 鉴权信息 -$appid='your appid'; -$secretId='your secretId '; -$secretKey='your secretKey'; -$userid='your qq'; +$appid='your appid'; +$secretId='your secretId '; +$secretKey='your secretKey'; +$userid='your qq'; ##### 根据你使用的平台选择一种初始化方式 @@ -44,7 +44,7 @@ Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_CHARGE_E Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); * 人脸检测接口调用示例 - $uploadRet = YouTu::detectface('test.jpg', 1); + $uploadRet = YouTu::detectface('test.jpg', 1); var_dump($uploadRet); From 52ff0c035bc0b3da4e01a70d492a5b812a9e00f3 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Fri, 4 Nov 2016 14:52:39 +0800 Subject: [PATCH 25/42] update readme --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 191faa2..b3a96c8 100644 --- a/README.md +++ b/README.md @@ -319,7 +319,9 @@ Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END - `$idcard_number` 身份证号码 - `$idcard_name` 身份证姓名 - `$image_path` 照片的路径 -更多详情和文档说明参见 -[腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) -[腾讯优图开放平台](http://open.youtu.qq.com) + + +####更多详情和文档说明参见 +* [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) +* [腾讯优图开放平台](http://open.youtu.qq.com) From 628cbcfe9e4e7ed172c0015000ab71881aa0e634 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Fri, 4 Nov 2016 15:22:59 +0800 Subject: [PATCH 26/42] update readme --- README.md | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b3a96c8..25dc363 100644 --- a/README.md +++ b/README.md @@ -19,33 +19,40 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) ## 使用示例 ##### 引入SDK -require('./include.php'); -use TencentYoutuyun\Youtu; -use TencentYoutuyun\Conf; -use TencentYoutuyun\Auth; - +``` +require('./include.php'); +use TencentYoutuyun\Youtu; +use TencentYoutuyun\Conf; +use TencentYoutuyun\Auth; +``` ##### 设置APP 鉴权信息 -$appid='your appid'; -$secretId='your secretId '; -$secretKey='your secretKey'; +``` +$appid='your appid'; +$secretId='your secretId '; +$secretKey='your secretKey'; $userid='your qq'; - +``` ##### 根据你使用的平台选择一种初始化方式 * 优图开放平台初始化 +``` Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT); - +``` * 优图开放平台核身服务初始化(**核身服务目前仅支持核身专有接口,需要联系商务开通**) +``` Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_CHARGE_END_POINT); - +``` * 腾讯云初始化 +``` Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_TENCENTYUN_END_POINT); - +``` * 人脸检测接口调用示例 - $uploadRet = YouTu::detectface('test.jpg', 1); - var_dump($uploadRet); +``` +$uploadRet = YouTu::detectface('test.jpg', 1); +var_dump($uploadRet); +``` From 3305bd432d1b4925ff5f881c7eb76d2f4ebdd57f Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 8 Dec 2016 11:36:52 +0800 Subject: [PATCH 27/42] update readme.md --- README.md | 121 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 25dc363..fa64b17 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,81 @@ var_dump($uploadRet); - `auth.AUTH_PARAMS_ERROR` 参数错误常量(-1) - `auth.AUTH_SECRET_ID_KEY_ERROR` 密钥ID或者密钥KEY错误常量(-2) -### `SDK API介绍` + +*** + #####Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ +*** + +### `核身API介绍` +优图开放平台相关核身API封装,均为同步函数,**需要联系商务开通** +*** +* `YouTu::livegetfour() ` + + 获取四字唇语 + + - 参数 + - `$image_path` 无 + + +* `YouTu::livedetectfour($validate_data,$video_path,$card_path,$compare_card=false,$seq = '') ` + + 带数据源四字人脸核身 + + - 参数 + - `$validate_data` livegetfour获取的四字唇语 + - `$video_path` 视频的路径 + - `$card_path` 对比照片的路径 + - `$compare_card` 视频与照片是否进行对比,true 对比 false不对比 + + +* `YouTu::idcardlivedetectfour($idcard_number,$idcard_name,$validate_data,$video_path,$seq = '') ` + + 不带数据源四字人脸核身 + + - 参数 + - `$idcard_number` 身份证号码 + - `$idcard_name` 身份证姓名 + - `$validate_data` livegetfour获取的四字唇语 + - `$video_path` 视频的路径 + + + +* `YouTu::idcardfacecompare($idcard_number,$idcard_name,$image_path,$seq = '') ` + + 不带数据源人脸对比 + + - 参数 + - `$idcard_number` 身份证号码 + - `$idcard_name` 身份证姓名 + - `$image_path` 照片的路径 + + +* `YouTu::idcardocr($image_path, $card_type, $seq = '') ` +* `YouTu::idcardocrurl($url, $card_type, $seq = '') ` + + 身份证OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + - `$card_type` 0 代表输入图像是身份证正面, 1代表输入是身份证反面 + + +* `YouTu::facecompare($image_path_a, $image_path_b)` +* `YouTu::facecompareurl($urlA, $urlB)` + + 人脸对比,计算两个Face的相似性以及五官相似度。 + + - 参数 + - `$image_path_a` 第一张待检测图片路径 + - `$image_path_b` 第二张待检测图片路径 + - `$urlA` 第一张图片url + - `$urlB` 第二张图片url + + + + +### `开放平台API介绍` 优图开放平台相关API封装,均为同步函数 @@ -283,51 +357,6 @@ var_dump($uploadRet); - `$url`待检测图片的url - `$retimage` 0代表不需要返回识别后图像, 1代表需要返回识别后图像 -### `核身SDK API介绍` - -优图开放平台相关核身API封装,均为同步函数,需要联系商务开通 -*** -* `YouTu::livegetfour() ` - - 获取四字唇语 - - - 参数 - - `$image_path` 无 - - -* `YouTu::livedetectfour($validate_data,$video_path,$card_path,$compare_card=false,$seq = '') ` - - 带数据源四字人脸核身 - - - 参数 - - `$validate_data` livegetfour获取的四字唇语 - - `$video_path` 视频的路径 - - `$card_path` 对比照片的路径 - - `$compare_card` 视频与照片是否进行对比,true 对比 false不对比 - - -* `YouTu::idcardlivedetectfour($idcard_number,$idcard_name,$validate_data,$video_path,$seq = '') ` - - 不带数据源四字人脸核身 - - - 参数 - - `$idcard_number` 身份证号码 - - `$idcard_name` 身份证姓名 - - `$validate_data` livegetfour获取的四字唇语 - - `$video_path` 视频的路径 - - - -* `YouTu::idcardfacecompare($idcard_number,$idcard_name,$image_path,$seq = '') ` - - 不带数据源人脸对比 - - - 参数 - - `$idcard_number` 身份证号码 - - `$idcard_name` 身份证姓名 - - `$image_path` 照片的路径 - - ####更多详情和文档说明参见 * [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) * [腾讯优图开放平台](http://open.youtu.qq.com) From 1c50ea9a0b132176c0caeea5a3e8341ed8e2a79c Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 8 Dec 2016 11:39:40 +0800 Subject: [PATCH 28/42] update readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa64b17..dad70ed 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ var_dump($uploadRet); *** - #####Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ + ##### Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ *** ### `核身API介绍` From 2c473b747384fed3a4d594c23cee93f56504df57 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 8 Dec 2016 11:40:57 +0800 Subject: [PATCH 29/42] update readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dad70ed..b922421 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ var_dump($uploadRet); *** - ##### Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ + Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ *** ### `核身API介绍` From 72a24cee719f178f7412d7db71506bc5fca113b8 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Thu, 8 Dec 2016 11:45:36 +0800 Subject: [PATCH 30/42] update readme.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b922421..536b77d 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ var_dump($uploadRet); *** - Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ +##### Api分为开放平台API和核身API,**核身API访问权限需要联系商务开通**;开放平台API访问域名为https://api.youtu.qq.com/, 核身API访问域名为https://vip-api.youtu.qq.com/ *** ### `核身API介绍` @@ -146,8 +146,7 @@ var_dump($uploadRet); - `$urlB` 第二张图片url - - +*** ### `开放平台API介绍` 优图开放平台相关API封装,均为同步函数 From c084bba2441e43d63857a751ae048daab07a3b34 Mon Sep 17 00:00:00 2001 From: tyronetao Date: Mon, 20 Mar 2017 12:43:35 +0800 Subject: [PATCH 31/42] add validateidcard --- README.md | 9 +++++++++ TencentYoutuyun/Youtu.php | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/README.md b/README.md index 536b77d..10e0f61 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,15 @@ var_dump($uploadRet); - `$image_path` 照片的路径 +* `YouTu::validateidcard($idcard_number,$idcard_name,$seq = '') ` + + 验证身份证信息的有效性 + + - 参数 + - `$idcard_number` 身份证号码 + - `$idcard_name` 身份证姓名 + + * `YouTu::idcardocr($image_path, $card_type, $seq = '') ` * `YouTu::idcardocrurl($url, $card_type, $seq = '') ` diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index a391517..b69c599 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1682,4 +1682,40 @@ public static function idcardfacecompare($idcard_number,$idcard_name,$image_path return $ret; } + public static function validateidcard($idcard_number,$idcard_name,$seq = '') + { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/openliveapi/validateidcard'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + + $post_data = array( + 'app_id' => Conf::$APPID, + 'idcard_number' => $idcard_number, + 'idcard_name' => $idcard_name, + 'seq' => $seq + ); + + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } } From 1505b6e3c423730cd7be30e04bff96f107fdc9ca Mon Sep 17 00:00:00 2001 From: pcxd Date: Thu, 22 Jun 2017 15:09:50 +0800 Subject: [PATCH 32/42] add ocr sdk --- TencentYoutuyun/Youtu.php | 322 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index b69c599..d0d33ef 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1718,4 +1718,326 @@ public static function validateidcard($idcard_number,$idcard_name,$seq = '') } return $ret; } + + /** + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function generalocr($image_path) { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/generalocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function generalocrurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/generalocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function driverlicenseocr($image_path) { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/driverlicenseocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function driverlicenseocrurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . '/youtu/ocrapi/driverlicenseocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function bcocr($image_path) { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/bcocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function bcocrurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . '/youtu/ocrapi/bcocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + /* + public static function creditcardocr($image_path) { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . '/youtu/ocrapi/creditcardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + */ + /** + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + /* + public static function creditcardocrurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . '/youtu/ocrapi/creditcardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + }*/ } From 3a9a5aecdc480edd761e11e28c573e6ac064069a Mon Sep 17 00:00:00 2001 From: pcxd Date: Thu, 22 Jun 2017 15:10:58 +0800 Subject: [PATCH 33/42] add ocr sdk --- TencentYoutuyun/Youtu.php | 82 --------------------------------------- 1 file changed, 82 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index d0d33ef..010a302 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1958,86 +1958,4 @@ public static function bcocrurl($url) { } return $ret; } - - /** - * @param $image_path 待检测的路径 - * @return 返回的结果,JSON字符串,字段参见API文档 - */ - /* - public static function creditcardocr($image_path) { - - $real_image_path = realpath($image_path); - if(!file_exists($real_image_path)) - { - return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); - } - - $expired = time() + self::EXPIRED_SECONDS; - $postUrl = Conf::$END_POINT . '/youtu/ocrapi/creditcardocr'; - $sign = Auth::appSign($expired, Conf::$USER_ID); - - $image_data = file_get_contents($real_image_path); - - $post_data = array( - 'app_id' => Conf::$APPID, - 'image' => base64_encode($image_data) - ); - - $req = array( - 'url' => $postUrl, - 'method' => 'post', - 'timeout' => 10, - 'data' => json_encode($post_data), - 'header' => array( - 'Authorization:'.$sign, - 'Content-Type:text/json', - 'Expect: ', - ), - ); - - $rsp = Http::send($req); - $ret = json_decode($rsp, true); - - if(!$ret){ - return self::getStatusText(); - } - return $ret; - } - */ - /** - * @param $url 待检测的图片url - * @return 返回的结果,JSON字符串,字段参见API文档 - */ - /* - public static function creditcardocrurl($url) { - - $expired = time() + self::EXPIRED_SECONDS; - $postUrl = Conf::$END_POINT . '/youtu/ocrapi/creditcardocr'; - $sign = Auth::appSign($expired, Conf::$USER_ID); - - $post_data = array( - 'app_id' => Conf::$APPID, - 'url' => $url - ); - - $req = array( - 'url' => $postUrl, - 'method' => 'post', - 'timeout' => 10, - 'data' => json_encode($post_data), - 'header' => array( - 'Authorization:'.$sign, - 'Content-Type:text/json', - 'Expect: ', - ), - ); - - $rsp = Http::send($req); - $ret = json_decode($rsp, true); - - if(!$ret){ - return self::getStatusText(); - } - return $ret; - }*/ } From eac6a7808a853112aa3e8c52198d7ff1b171240b Mon Sep 17 00:00:00 2001 From: pcxd Date: Wed, 12 Jul 2017 16:54:47 +0800 Subject: [PATCH 34/42] fix bug for driverlicenseocr --- TencentYoutuyun/Youtu.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 010a302..4be7e96 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1803,7 +1803,7 @@ public static function generalocrurl($url) { * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function driverlicenseocr($image_path) { + public static function driverlicenseocr($image_path, $card_type) { $real_image_path = realpath($image_path); if(!file_exists($real_image_path)) @@ -1819,6 +1819,7 @@ public static function driverlicenseocr($image_path) { $post_data = array( 'app_id' => Conf::$APPID, + 'type' => $card_type, 'image' => base64_encode($image_data) ); @@ -1847,14 +1848,15 @@ public static function driverlicenseocr($image_path) { * @param $url 待检测的图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function driverlicenseocrurl($url) { + public static function driverlicenseocrurl($url, $card_type) { $expired = time() + self::EXPIRED_SECONDS; - $postUrl = Conf::$END_POINT . '/youtu/ocrapi/driverlicenseocr'; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/driverlicenseocr'; $sign = Auth::appSign($expired, Conf::$USER_ID); $post_data = array( 'app_id' => Conf::$APPID, + 'type' => $card_type, 'url' => $url ); From 51a9947a198d290566432d7fad8ea2a1c8b33dcb Mon Sep 17 00:00:00 2001 From: pcxd Date: Tue, 25 Jul 2017 17:15:58 +0800 Subject: [PATCH 35/42] add comment of ocr --- TencentYoutuyun/Youtu.php | 1 + 1 file changed, 1 insertion(+) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 4be7e96..e22d36b 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1801,6 +1801,7 @@ public static function generalocrurl($url) { /** * @param $image_path 待检测的路径 + * @param $card_type 图片类型:行驶证/驾驶证 0/1 * @return 返回的结果,JSON字符串,字段参见API文档 */ public static function driverlicenseocr($image_path, $card_type) { From 18d4d63c6760ea97dd10583f002aad13c45b46a3 Mon Sep 17 00:00:00 2001 From: pcxd Date: Fri, 4 Aug 2017 10:50:27 +0800 Subject: [PATCH 36/42] add ocr interface usage in README.md --- README.md | 32 ++++++++++++++++++++++++++++++++ TencentYoutuyun/Youtu.php | 12 ++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 10e0f61..b14abb1 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,38 @@ var_dump($uploadRet); - `$url`待检测图片的url - `$retimage` 0代表不需要返回识别后图像, 1代表需要返回识别后图像 + +* `YouTu::generalocr($image_path, $seq = '') ` +* `YouTu::generalocrurl($url, $seq = '') ` + + 通用OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + + +* `YouTu::bcocr($image_path, $seq = '') ` +* `YouTu::bcocrurl($url, $seq = '') ` + + 名片OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + + +* `YouTu::driverlicenseocr($image_path, $card_type, $seq = '') ` +* `YouTu::driverlicenseocrurl($url, $card_type, $seq = '') ` + + 行驶证&驾驶证OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + - `$card_type` 0 代表输入图像是行驶证, 1代表输入图像是驾驶证 + + ####更多详情和文档说明参见 * [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) * [腾讯优图开放平台](http://open.youtu.qq.com) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index e22d36b..693c578 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1723,7 +1723,7 @@ public static function validateidcard($idcard_number,$idcard_name,$seq = '') * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function generalocr($image_path) { + public static function generalocr($image_path, $seq='') { $real_image_path = realpath($image_path); if(!file_exists($real_image_path)) @@ -1767,7 +1767,7 @@ public static function generalocr($image_path) { * @param $url 待检测的图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function generalocrurl($url) { + public static function generalocrurl($url, $seq='') { $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . 'youtu/ocrapi/generalocr'; @@ -1804,7 +1804,7 @@ public static function generalocrurl($url) { * @param $card_type 图片类型:行驶证/驾驶证 0/1 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function driverlicenseocr($image_path, $card_type) { + public static function driverlicenseocr($image_path, $card_type, $seq='') { $real_image_path = realpath($image_path); if(!file_exists($real_image_path)) @@ -1849,7 +1849,7 @@ public static function driverlicenseocr($image_path, $card_type) { * @param $url 待检测的图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function driverlicenseocrurl($url, $card_type) { + public static function driverlicenseocrurl($url, $card_type, $seq='') { $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . 'youtu/ocrapi/driverlicenseocr'; @@ -1886,7 +1886,7 @@ public static function driverlicenseocrurl($url, $card_type) { * @param $image_path 待检测的路径 * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function bcocr($image_path) { + public static function bcocr($image_path, $seq='') { $real_image_path = realpath($image_path); if(!file_exists($real_image_path)) @@ -1930,7 +1930,7 @@ public static function bcocr($image_path) { * @param $url 待检测的图片url * @return 返回的结果,JSON字符串,字段参见API文档 */ - public static function bcocrurl($url) { + public static function bcocrurl($url, $seq='') { $expired = time() + self::EXPIRED_SECONDS; $postUrl = Conf::$END_POINT . '/youtu/ocrapi/bcocr'; From cd8523a1825e2fbe9812005ad21e98ede2cb5980 Mon Sep 17 00:00:00 2001 From: pcxd Date: Thu, 21 Sep 2017 10:34:40 +0800 Subject: [PATCH 37/42] update authentication url in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b14abb1..ef3245b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) - `AppId` 平台添加应用后分配的AppId - `SecretId` 平台添加应用后分配的SecretId - `SecretKey` 平台添加应用后分配的SecretKey - - `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 + - `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 From b294474b2d8808cf09fa7003d4b808644e3644ac Mon Sep 17 00:00:00 2001 From: pcxd Date: Fri, 17 Nov 2017 11:14:32 +0800 Subject: [PATCH 38/42] remove namecardocr interface --- README.md | 11 --------- TencentYoutuyun/Youtu.php | 48 --------------------------------------- 2 files changed, 59 deletions(-) diff --git a/README.md b/README.md index ef3245b..cb25365 100644 --- a/README.md +++ b/README.md @@ -347,17 +347,6 @@ var_dump($uploadRet); * `YouTu::idcardocr($image_path, $card_type, $seq = '') ` * `YouTu::idcardocrurl($url, $card_type, $seq = '') ` - 身份证OCR识别 - - - 参数 - - `$image_path` 待检测图片路径 - - `$url`待检测图片的url - - `$card_type` 0 代表输入图像是身份证正面, 1代表输入是身份证反面 - - -* `YouTu::namecardocr($image_path, $retimage, $seq = '') ` -* `YouTu::namecardocrurl($url, $retimage, $seq = '') ` - 名片ocr识别 - 参数 diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 693c578..408f3cb 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -1402,54 +1402,6 @@ public static function idcardocrurl($url, $card_type, $seq = '') { } - /** - * @param $image_path 待检测的路径 - * @param $retimage 是否返回名片图像 - * @return 返回的结果,JSON字符串,字段参见API文档 - */ - public static function namecardocr($image_path, $retimage = 1, $seq = '') { - - $real_image_path = realpath($image_path); - - if (!file_exists($real_image_path)) - { - return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); - } - - $expired = time() + self::EXPIRED_SECONDS; - $postUrl = Conf::$END_POINT . 'youtu/ocrapi/namecardocr'; - $sign = Auth::appSign($expired, Conf::$USER_ID); - - $image_data = file_get_contents($real_image_path); - $post_data = array( - 'app_id' => Conf::$APPID, - 'image' => base64_encode($image_data), - 'seq' => $seq, - 'retimage'=> (bool)$retimage - ); - - $req = array( - 'url' => $postUrl, - 'method' => 'post', - 'timeout' => 10, - 'data' => json_encode($post_data), - 'header' => array( - 'Authorization:'.$sign, - 'Content-Type:text/json', - 'Expect: ', - ), - ); - $rsp = Http::send($req); - - $ret = json_decode($rsp, true); - - if(!$ret){ - return self::getStatusText(); - } - - return $ret; - } - /** * @param $url 图片url * @param $retimage 是否返回名片图像 From 05189ac783d0ee6372cd8c9581e05184275c78c8 Mon Sep 17 00:00:00 2001 From: pcxd Date: Fri, 17 Nov 2017 11:23:19 +0800 Subject: [PATCH 39/42] remove namecardocr interface --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb25365..1fed6ca 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ var_dump($uploadRet); * `YouTu::idcardocr($image_path, $card_type, $seq = '') ` * `YouTu::idcardocrurl($url, $card_type, $seq = '') ` - 名片ocr识别 + 身份证ocr识别 - 参数 - `$image_path` 待检测图片路径 From a7bdb716bcc34dbe0e34b04a9f5ea146f5ab8ada Mon Sep 17 00:00:00 2001 From: TanGuofu <267266206@qq.com> Date: Tue, 6 Feb 2018 17:14:44 +0800 Subject: [PATCH 40/42] Update Conf.php remove endpoint --- TencentYoutuyun/Conf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TencentYoutuyun/Conf.php b/TencentYoutuyun/Conf.php index 13d5785..f538cfb 100644 --- a/TencentYoutuyun/Conf.php +++ b/TencentYoutuyun/Conf.php @@ -7,7 +7,7 @@ class Conf const API_YOUTU_END_POINT = 'https://api.youtu.qq.com/'; const API_YOUTU_CHARGE_END_POINT = 'https://vip-api.youtu.qq.com/'; - const API_TENCENTYUN_END_POINT = 'https://youtu.api.qcloud.com/'; + // 请到 open.youtu.qq.com查看您对应的appid相关信息并填充 From 0e8cab89a12576843c7e5d2cc243d4463bfce628 Mon Sep 17 00:00:00 2001 From: healthyan Date: Wed, 28 Feb 2018 21:18:59 +0800 Subject: [PATCH 41/42] add new interface --- README.md | 56 ++++- TencentYoutuyun/Youtu.php | 509 ++++++++++++++++++++++++++++++++++++++ sample.php | 47 +++- 3 files changed, 604 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1fed6ca..a73f53e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TencentYoutuyun-person-face-service -php sdk for [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) & [腾讯优图开放平台](http://open.youtu.qq.com) +php sdk for [腾讯优图开放平台](http://open.youtu.qq.com) ## 安装(直接下载源码集成) @@ -219,6 +219,17 @@ var_dump($uploadRet); - `$url` 待检测图片的url - `$group_id` 需要识别的人 所在的组 +* `YouTu::multifaceidentify($image_path,$group_id, array $group_ids, $topn=5, $min_size=40)` +* `YouTu::multifaceidentifyurl($url, $group_id, array $group_ids, $topn=5, $min_size=40)` +上传人脸图片,进行多人脸检索。 + - 参数 + - `$image_path` 待检测图片路径 + - `$url` 待检测图片的url + - `$group_id` 需要识别的人 所在的组 + - `$group_ids` 需要识别的人 所在的组的列表(数组) + - `$topn` 候选人脸数量,一般使用默认值5 + - `$min_size` 人脸检测最小尺寸,一般使用默认值40 + * `YouTu::newperson($image_path, $person_id, array $group_ids, $person_name="", $person_tag="")` * `YouTu::newpersonurl($url, $person_id, array $group_ids, $person_name="", $person_tag="")` @@ -335,6 +346,7 @@ var_dump($uploadRet); - 参数 - `$image_path` 待检测图片路径 - `$url` 待检测图片的url + * `YouTu::imageporn($image_path)` * `YouTu::imagepornurl($url)` @@ -343,6 +355,21 @@ var_dump($uploadRet); - `$image_path` 待检测图片路径 - `$url`待检测图片的url +* `YouTu::imageterrorism($image_path)` +* `YouTu::imageterrorismurl($url)` + + 暴恐图片识别 + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + +* `YouTu::carclassify($image_path)` +* `YouTu::carclassifyurl($url)` + + 车辆属性识别 + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url * `YouTu::idcardocr($image_path, $card_type, $seq = '') ` * `YouTu::idcardocrurl($url, $card_type, $seq = '') ` @@ -385,8 +412,33 @@ var_dump($uploadRet); - `$url`待检测图片的url - `$card_type` 0 代表输入图像是行驶证, 1代表输入图像是驾驶证 +* `YouTu::plateocr($image_path, $seq = '') ` +* `YouTu::plateocrurl($url, $seq = '') ` + + 车牌OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + +* `YouTu::creditcardocr($image_path, $seq = '') ` +* `YouTu::creditcardocrurl($url, $seq = '') ` + + 银行卡OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url + +* `YouTu::bizlicenseocr($image_path, $seq = '') ` +* `YouTu::bizlicenseocrurl($url, $seq = '') ` + + 营业执照OCR识别 + + - 参数 + - `$image_path` 待检测图片路径 + - `$url`待检测图片的url ####更多详情和文档说明参见 -* [腾讯云智能优图服务](http://www.qcloud.com/product/fr.html) * [腾讯优图开放平台](http://open.youtu.qq.com) diff --git a/TencentYoutuyun/Youtu.php b/TencentYoutuyun/Youtu.php index 408f3cb..c61bfc9 100644 --- a/TencentYoutuyun/Youtu.php +++ b/TencentYoutuyun/Youtu.php @@ -471,6 +471,7 @@ public static function faceidentify($image_path,$group_id) { /** * @brief faceidentifyurl * @param group_id 识别的组id + * @param group_ids 个体存放的组id,可以指定多个组id,用户指定 * @param url 待识别的图片的url * @return 返回的结果,JSON字符串,字段参见API文档 */ @@ -506,6 +507,102 @@ public static function faceidentifyurl($url,$group_id) { return $ret; } + /** + * @brief multifaceidentify + * @param group_id 识别的组id + * @param group_ids 个体存放的组id,可以指定多个组id,用户指定 + * @param image_path 待识别的图片路径 + * @param topn 候选人脸数量,一般使用默认值5 + * @param min_size 人脸检测最小尺寸,一般使用默认值40 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function multifaceidentify($image_path,$group_id, array $group_ids, $topn=5, $min_size=40) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/multifaceidentify'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + 'group_id' =>$group_id, + 'group_ids' =>$group_ids, + 'topn' =>$topn, + 'min_size' =>$min_size + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * @brief multifaceidentifyurl + * @param group_id 识别的组id + * @param group_ids 个体存放的组id,可以指定多个组id,用户指定 + * @param url 待识别的图片的url + * @param topn 候选人脸数量,一般使用默认值5 + * @param min_size 人脸检测最小尺寸,一般使用默认值40 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + + public static function multifaceidentifyurl($url,$group_id, array $group_ids, $topn=5, $min_size=40) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/api/multifaceidentify'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url, + 'group_id' =>$group_id, + 'group_ids' =>$group_ids, + 'topn' =>$topn, + 'min_size' =>$min_size + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + ), + ); + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + /** * @brief newperson * @param person_id 新建的个体id,用户指定,需要保证app_id下的唯一性 @@ -1311,7 +1408,173 @@ public static function imagepornurl($url) { return $ret; } + /** + * imageterrorism 暴恐图片识别 + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function imageterrorism($image_path) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imageterrorism'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * imageterrorismurl 暴恐图片识别 + * @param $url 图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function imageterrorismurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imageterrorism'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * carclassify 车辆属性识别 + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function carclassify($image_path) { + + $real_image_path = realpath($image_path); + + if (!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/carapi/carclassify'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data), + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + + return $ret; + } + + /** + * carclassifyurl 车辆属性识别 + * @param $url 图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function carclassifyurl($url) { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/imageapi/imageterrorism'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url, + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + $rsp = Http::send($req); + + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } /** * @param $url 图片url @@ -1913,4 +2176,250 @@ public static function bcocrurl($url, $seq='') { } return $ret; } + + /** + * creditcardocr 银行卡OCR识别 + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function creditcardocr($image_path, $seq='') { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/creditcardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * creditcardocrurl 银行卡OCR识别 + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function creditcardocrurl($url, $seq='') { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/creditcardocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * bizlicenseocr 营业执照OCR识别 + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function bizlicenseocr($image_path, $seq='') { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/bizlicenseocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * bizlicenseocrurl 营业执照OCR识别 + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function bizlicenseocrurl($url, $seq='') { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/bizlicenseocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * plateocr 车牌OCR识别 + * @param $image_path 待检测的路径 + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function plateocr($image_path, $seq='') { + + $real_image_path = realpath($image_path); + if(!file_exists($real_image_path)) + { + return array('httpcode' => 0, 'code' => self::HTTP_BAD_REQUEST, 'message' => 'file '.$image_path.' not exists', 'data' => array()); + } + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/plateocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $image_data = file_get_contents($real_image_path); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'image' => base64_encode($image_data) + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } + + /** + * plateocrurl 车牌OCR识别 + * @param $url 待检测的图片url + * @return 返回的结果,JSON字符串,字段参见API文档 + */ + public static function plateocrurl($url, $seq='') { + + $expired = time() + self::EXPIRED_SECONDS; + $postUrl = Conf::$END_POINT . 'youtu/ocrapi/plateocr'; + $sign = Auth::appSign($expired, Conf::$USER_ID); + + $post_data = array( + 'app_id' => Conf::$APPID, + 'url' => $url + ); + + $req = array( + 'url' => $postUrl, + 'method' => 'post', + 'timeout' => 10, + 'data' => json_encode($post_data), + 'header' => array( + 'Authorization:'.$sign, + 'Content-Type:text/json', + 'Expect: ', + ), + ); + + $rsp = Http::send($req); + $ret = json_decode($rsp, true); + + if(!$ret){ + return self::getStatusText(); + } + return $ret; + } } diff --git a/sample.php b/sample.php index ca8de24..3650a44 100644 --- a/sample.php +++ b/sample.php @@ -7,10 +7,10 @@ // 设置APP 鉴权信息 请在http://open.youtu.qq.com 创建应用 -$appid='x'; -$secretId='x'; -$secretKey='x'; -$userid='x'; +$appid=''; +$secretId=''; +$secretKey=''; +$userid=''; Conf::setAppInfo($appid, $secretId, $secretKey, $userid,conf::API_YOUTU_END_POINT ); @@ -39,9 +39,44 @@ //var_dump($uploadRet); //名片 -$uploadRet = YouTu::namecardocr('test.jpg', 1); -var_dump($uploadRet); +// $uploadRet = YouTu::namecardocr('test.jpg', 1); +// var_dump($uploadRet); $uploadRet = YouTu::namecardocrurl('http://open.youtu.qq.com/content/img/product/face/face_05.jpg', 1); var_dump($uploadRet); +// $uploadRet = YouTu::plateocr('plate.jpg'); +// var_dump($uploadRet); +$uploadRet = YouTu::plateocrurl('http://open.youtu.qq.com/app/img/experience/char_general/ocr_license_1.jpg'); +var_dump($uploadRet); + +// $uploadRet = YouTu::bizlicenseocr('biz.jpg'); +// var_dump($uploadRet); +$uploadRet = YouTu::bizlicenseocrurl('http://open.youtu.qq.com/app/img/experience/char_general/ocr_yyzz_01.jpg'); +var_dump($uploadRet); + +// $uploadRet = YouTu::creditcardocr('credit.jpg'); +// var_dump($uploadRet); + +$uploadRet = YouTu::creditcardocrurl('http://open.youtu.qq.com/app/img/experience/char_general/ocr_card_1.jpg'); +var_dump($uploadRet); + +// $uploadRet = YouTu::carclassify('car.jpg'); +// var_dump($uploadRet); + +$uploadRet = YouTu::carclassifyurl('http://open.youtu.qq.com/app/img/experience/car/car_01.jpg'); +var_dump($uploadRet); + +// $uploadRet = YouTu::imageterrorism('terror.jpg'); +// var_dump($uploadRet); + +$uploadRet = YouTu::imageterrorismurl('http://open.youtu.qq.com/app/img/experience/terror/img_terror01.jpg'); +var_dump($uploadRet); + +$group_ids = array(); +// $uploadRet = YouTu::multifaceidentify('terror.jpg', "test", $group_ids, 5, 40); +// var_dump($uploadRet); + +$uploadRet = YouTu::multifaceidentifyurl('http://open.youtu.qq.com/app/img/experience/face_img/face_13.jpg', "test", $group_ids, 5, 40); +var_dump($uploadRet); + ?> From dbce48f90f8ee4c7bc2080a5e84ab44e090e9b23 Mon Sep 17 00:00:00 2001 From: Health Date: Fri, 9 Mar 2018 11:10:56 +0800 Subject: [PATCH 42/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a73f53e..c60f2ce 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ php sdk for [腾讯优图开放平台](http://open.youtu.qq.com) - `AppId` 平台添加应用后分配的AppId - `SecretId` 平台添加应用后分配的SecretId - `SecretKey` 平台添加应用后分配的SecretKey - - `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见 + - `签名` 接口鉴权凭证,由`AppId`、`SecretId`、`SecretKey`等生成,详见