• 6805阅读
  • 16回复

Qt封装百度人脸识别+图像识别 [复制链接]

上一主题 下一主题
离线liudianwu
 

图酷模式  只看楼主 倒序阅读 楼主  发表于: 2018-08-13
AI技术的发展在最近几年如火如荼,工资待遇也是水涨船高,应用的前景也是非常广阔,去年火起来的人脸识别,今年全国遍地开花,之前封装了下face++的人脸识别等接口,今年看了下百度的AI,还免费了,效果也是越来越好,活体检测这个算法更是做的吊炸天(只需要传一张图片就能判断图片中的人是翻拍的照片非活体),牛逼的一塌糊涂,我反正是跪了。特意花了半天时间将百度人脸识别+图像识别封装了下,以便后期使用。顺便预测下,百度AI在未来的国内AI市场中,不是第一就是第二,而且会持续保持至少十年。
为了兼容qt4,特意采用了qtscript解析收到的数据
* 1:可识别身份证正面信息+背面信息
* 2:可识别银行卡信息
* 3:可识别驾驶证+行驶证信息
* 4:可进行人脸识别,人脸比对,活体检测
* 5:可设置请求地址+用户密钥+应用密钥
* 6:直接传入图片即可,信号返回,毫秒级极速响应
* 7:通用Qt4-Qt5,windows linux 嵌入式linux
执行文件下载https://pan.baidu.com/s/1pzhQL_YMYZyn4hW94e0QsQ
window.open('http://www.qtcn.org/bbs/attachment/Mon_1808/44_110085_7977beb03cc72e0.jpg?89');" style="max-width:700px;max-height:700px;" onload="if(is_ie6&&this.offsetWidth>700)this.width=700;" >
核心代码:
  1. QByteArray FaceBaiDu::getImageData(const QImage &img)
  2. {
  3.     QImage image = img;
  4.     QByteArray imageData;
  5.     QBuffer buffer(&imageData);
  6.     image.save(&buffer, "jpg");
  7.     return imageData.toBase64();
  8. }
  9. QString FaceBaiDu::getImageData2(const QImage &img)
  10. {
  11.     return QString(getImageData(img));
  12. }
  13. QHttpPart FaceBaiDu::dataToHttpPart(const QByteArray &body, const QString &name)
  14. {
  15.     QHttpPart httpPart;
  16.     httpPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(QString("form-data;name=\"%1\"").arg(name)));
  17.     httpPart.setBody(body);
  18.     return httpPart;
  19. }
  20. void FaceBaiDu::sendData(const QString &url, const QList<QHttpPart> &httpParts)
  21. {
  22.     //初始化消息体
  23.     QHttpMultiPart *httpMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
  24.     //逐个添加消息内容
  25.     foreach (QHttpPart httpPart, httpParts) {
  26.         httpMultiPart->append(httpPart);
  27.     }
  28.     //初始化请求对象
  29.     QNetworkRequest request;
  30.     request.setUrl(QUrl(url));
  31. #ifdef ssl
  32.     //设置openssl签名配置,否则在ARM上会报错
  33.     QSslConfiguration conf = request.sslConfiguration();
  34.     conf.setPeerVerifyMode(QSslSocket::VerifyNone);
  35. #if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
  36.     conf.setProtocol(QSsl::TlsV1_0);
  37. #else
  38.     conf.setProtocol(QSsl::TlsV1);
  39. #endif
  40.     request.setSslConfiguration(conf);
  41. #endif
  42.     //发送请求
  43.     QNetworkReply *reply = manager->post(request, httpMultiPart);
  44.     httpMultiPart->setParent(reply);
  45. }
  46. void FaceBaiDu::finished(QNetworkReply *reply)
  47. {
  48.     QString error = reply->errorString();
  49.     if (!error.isEmpty() && error != "Unknown error") {
  50.         emit receiveError(error);
  51.     }
  52.     if (reply->bytesAvailable() > 0 && reply->error() == QNetworkReply::NoError) {
  53.         QString data = reply->readAll();
  54.         reply->deleteLater();
  55.         //发送接收数据信号
  56.         emit receiveData(data);
  57.         //初始化脚本引擎
  58.         QScriptEngine engine;
  59.         //构建解析对象
  60.         QScriptValue script = engine.evaluate("value=" + data);
  61.         //获取鉴权标识符
  62.         QString token = script.property("access_token").toString();
  63.         if (!token.isEmpty()) {
  64.             tokenFace = token;
  65.             tokenOcr = token;
  66.         }
  67.         //通用返回结果字段
  68.         int code = script.property("error_code").toInt32();
  69.         QString msg = script.property("error_msg").toString();
  70.         emit receiveResult(code, msg);
  71.         //人脸识别部分
  72.         QScriptValue result = script.property("result");
  73.         if (!result.isNull()) {
  74.             //人脸识别
  75.             QScriptValue face_list = result.property("face_list");
  76.             if (face_list.isObject()) {
  77.                 checkFaceList(face_list);
  78.             }
  79.             //人脸比对
  80.             QScriptValue score = result.property("score");
  81.             if (!score.isNull()) {
  82.                 double value = score.toString().toDouble();
  83.                 if (value > 0) {
  84.                     emit receiveFaceCompare(QRect(), QRect(), value);
  85.                 } else {
  86.                     emit receiveFaceCompareFail();
  87.                 }
  88.             }
  89.             //活体检测
  90.             QScriptValue face_liveness = result.property("face_liveness");
  91.             if (!face_liveness.isNull()) {
  92.                 double liveness = face_liveness.toString().toDouble();
  93.                 if (liveness > 0) {
  94.                     emit receiveLive(liveness);
  95.                 }
  96.             }
  97.             //银行卡
  98.             QScriptValue bank_card_number = result.property("bank_card_number");
  99.             if (!bank_card_number.isNull()) {
  100.                 QString card_number = bank_card_number.toString();
  101.                 QString bank_name = result.property("bank_name").toString();
  102.                 if (!card_number.isEmpty()) {
  103.                     emit receiveBankCardInfo(card_number, bank_name);
  104.                 }
  105.             }
  106.         }
  107.         //文字识别部分
  108.         QScriptValue words_result = script.property("words_result");
  109.         if (!words_result.isNull()) {
  110.             //身份证正面
  111.             QScriptValue nation = words_result.property("民族");
  112.             if (nation.isObject()) {
  113.                 checkCardFront(words_result);
  114.             }
  115.             //身份证反面
  116.             QScriptValue issuedby = words_result.property("签发机关");
  117.             if (issuedby.isObject()) {
  118.                 checkCardBack(words_result);
  119.             }
  120.             //驾驶证
  121.             QScriptValue license_number = words_result.property("证号");
  122.             if (license_number.isObject()) {
  123.                 checkDriverLicense(words_result);
  124.             }
  125.             //行驶证
  126.             QScriptValue model = words_result.property("品牌型号");
  127.             if (model.isObject()) {
  128.                 checkRVehicleLicense(words_result);
  129.             }
  130.         }
  131.     }
  132. }
  133. void FaceBaiDu::checkFaceList(const QScriptValue &face_list)
  134. {
  135.     QRect face_rectangle;
  136.     //创建迭代器逐个解析具体值
  137.     QScriptValueIterator it(face_list);
  138.     while (it.hasNext()) {
  139.         it.next();
  140.         QString face_token = it.value().property("face_token").toString();
  141.         if (!face_token.isEmpty()) {
  142.             QScriptValue location = it.value().property("location");
  143.             if (location.isObject()) {
  144.                 face_rectangle.setX(location.property("left").toInt32());
  145.                 face_rectangle.setY(location.property("top").toInt32());
  146.                 face_rectangle.setWidth(location.property("width").toInt32());
  147.                 face_rectangle.setHeight(location.property("height").toInt32());
  148.             }
  149.         }
  150.         it.next();
  151.         if (face_rectangle.width() > 0) {
  152.             emit receiveFaceRect(face_rectangle);
  153.         } else {
  154.             break;
  155.         }
  156.     }
  157. }
  158. void FaceBaiDu::checkCardFront(const QScriptValue &scriptValue)
  159. {
  160.     QScriptValue name = scriptValue.property("姓名");
  161.     QScriptValue address = scriptValue.property("住址");
  162.     QScriptValue birthday = scriptValue.property("出生");
  163.     QScriptValue number = scriptValue.property("公民身份号码");
  164.     QScriptValue sex = scriptValue.property("性别");
  165.     QScriptValue nation = scriptValue.property("民族");
  166.     QString strName = name.property("words").toString();
  167.     QString strAddress = address.property("words").toString();
  168.     QString strBirthday = birthday.property("words").toString();
  169.     QString strNumber = number.property("words").toString();
  170.     QString strSex = sex.property("words").toString();
  171.     QString strNation = nation.property("words").toString();
  172.     emit receiveIDCardInfoFront(strName, strSex, strNumber, strBirthday, strNation, strAddress);
  173. }
  174. void FaceBaiDu::checkCardBack(const QScriptValue &scriptValue)
  175. {
  176.     QScriptValue issuedby = scriptValue.property("签发机关");
  177.     QScriptValue dateStart = scriptValue.property("签发日期");
  178.     QScriptValue dateEnd = scriptValue.property("失效日期");
  179.     QString strIssuedby = issuedby.property("words").toString();
  180.     QString strDataStart = dateStart.property("words").toString();
  181.     QString strDateEnd = dateEnd.property("words").toString();
  182.     QString strDate = QString("%1.%2.%3-%4.%5.%6")
  183.                       .arg(strDataStart.mid(0, 4)).arg(strDataStart.mid(4, 2)).arg(strDataStart.mid(6, 2))
  184.                       .arg(strDateEnd.mid(0, 4)).arg(strDateEnd.mid(4, 2)).arg(strDateEnd.mid(6, 2));
  185.     emit receiveIDCardInfoBack(strDate, strIssuedby);
  186. }
  187. void FaceBaiDu::checkDriverLicense(const QScriptValue &scriptValue)
  188. {
  189.     QScriptValue licenseNumber = scriptValue.property("证号");
  190.     QScriptValue name = scriptValue.property("姓名");
  191.     QScriptValue gender = scriptValue.property("性别");
  192.     QScriptValue nationality = scriptValue.property("国籍");
  193.     QScriptValue address = scriptValue.property("住址");
  194.     QScriptValue birthday = scriptValue.property("出生日期");
  195.     QScriptValue issueDate = scriptValue.property("初次领证日期");
  196.     QScriptValue classType = scriptValue.property("准驾车型");
  197.     QScriptValue validFrom = scriptValue.property("有效起始日期");
  198.     QScriptValue validFor = scriptValue.property("有效期限");
  199.     QString strLicenseNumber = licenseNumber.property("words").toString();
  200.     QString strName = name.property("words").toString();
  201.     QString strGender = gender.property("words").toString();
  202.     QString strNationality = nationality.property("words").toString();
  203.     QString strAddress = address.property("words").toString();
  204.     QString strBirthday = birthday.property("words").toString();
  205.     QString strIssueDate = issueDate.property("words").toString();
  206.     QString strClassType = classType.property("words").toString();
  207.     QString strValidFrom = validFrom.property("words").toString();
  208.     QString strValidFor = validFor.property("words").toString();
  209.     emit receiveDriverInfo(strValidFrom, strGender, "", strIssueDate, strClassType, strLicenseNumber,
  210.                            strValidFor, strBirthday, "1", strAddress, strNationality, strName);
  211. }
  212. void FaceBaiDu::checkRVehicleLicense(const QScriptValue &scriptValue)
  213. {
  214.     QScriptValue plateNo = scriptValue.property("号牌号码");
  215.     QScriptValue vehicleType = scriptValue.property("车辆类型");
  216.     QScriptValue owner = scriptValue.property("所有人");
  217.     QScriptValue address = scriptValue.property("住址");
  218.     QScriptValue useCharacter = scriptValue.property("使用性质");
  219.     QScriptValue model = scriptValue.property("品牌型号");
  220.     QScriptValue vin = scriptValue.property("车辆识别代号");
  221.     QScriptValue engineNo = scriptValue.property("发动机号码");
  222.     QScriptValue registerDate = scriptValue.property("注册日期");
  223.     QScriptValue issueDate = scriptValue.property("发证日期");
  224.     QString strPlateNo = plateNo.property("words").toString();
  225.     QString strCehicleType = vehicleType.property("words").toString();
  226.     QString strOwner = owner.property("words").toString();
  227.     QString strAddress = address.property("words").toString();
  228.     QString strUseCharacter = useCharacter.property("words").toString();
  229.     QString strModel = model.property("words").toString();
  230.     QString strVin = vin.property("words").toString();
  231.     QString strEngineNo = engineNo.property("words").toString();
  232.     QString strRegisterDate = registerDate.property("words").toString();
  233.     QString strIssueDate = issueDate.property("words").toString();
  234.     emit receiveRvehicleInfo(strIssueDate, strCehicleType, "", strVin, strPlateNo, strUseCharacter,
  235.                              strAddress, strOwner, strModel, strRegisterDate, strEngineNo);
  236. }
  237. void FaceBaiDu::sendData(const QString &url, const QString &data, const QString &header)
  238. {
  239.     QNetworkRequest request;
  240.     request.setHeader(QNetworkRequest::ContentTypeHeader, header);
  241.     request.setUrl(QUrl(url));
  242. #ifdef ssl
  243.     //设置openssl签名配置,否则在ARM上会报错
  244.     QSslConfiguration conf = request.sslConfiguration();
  245.     conf.setPeerVerifyMode(QSslSocket::VerifyNone);
  246. #if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
  247.     conf.setProtocol(QSsl::TlsV1_0);
  248. #else
  249.     conf.setProtocol(QSsl::TlsV1);
  250. #endif
  251.     request.setSslConfiguration(conf);
  252. #endif
  253.     manager->post(request, data.toUtf8());
  254. }
  255. void FaceBaiDu::getToken(const QString &client_id, const QString &client_secret)
  256. {
  257.     QStringList list;
  258.     list.append(QString("grant_type=%1").arg("client_credentials"));
  259.     list.append(QString("client_id=%1").arg(client_id));
  260.     list.append(QString("client_secret=%1").arg(client_secret));
  261.     QString data = list.join("&");
  262.     QString url = "https://aip.baidubce.com/oauth/2.0/token";
  263.     sendData(url, data);
  264. }
  265. void FaceBaiDu::detect(const QImage &img)
  266. {
  267.     QStringList list;
  268.     list.append(QString("{\"image\":\"%1\",\"image_type\":\"BASE64\"}").arg(getImageData2(img)));
  269.     QString data = list.join("");
  270.     QString url = QString("https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=%1").arg(tokenFace);
  271.     sendData(url, data);
  272. }
  273. void FaceBaiDu::compare(const QImage &img1, const QImage &img2)
  274. {
  275.     QString imgData1 = getImageData2(img1);
  276.     QString imgData2 = getImageData2(img2);
  277.     //如果需要活体检测则NONE改为LOW NORMAL HIGH
  278.     QStringList list;
  279.     list.append("[");
  280.     list.append(QString("{\"image\":\"%1\",\"image_type\":\"BASE64\",\"liveness_control\":\"NONE\"}").arg(imgData1));
  281.     list.append(",");
  282.     list.append(QString("{\"image\":\"%1\",\"image_type\":\"BASE64\",\"liveness_control\":\"NONE\"}").arg(imgData2));
  283.     list.append("]");
  284.     QString data = list.join("");
  285.     QString url = QString("https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=%1").arg(tokenFace);
  286.     sendData(url, data);
  287. }
  288. void FaceBaiDu::live(const QImage &img)
  289. {
  290.     QList<QImage> imgs;
  291.     if (!img.isNull()) {
  292.         imgs << img;
  293.     }
  294.     live(imgs);
  295. }
  296. void FaceBaiDu::live(const QList<QImage> &imgs)
  297. {
  298.     //记住最后一次处理的时间,限制频繁的调用
  299.     QDateTime now = QDateTime::currentDateTime();
  300.     if (lastTime.msecsTo(now) < 500) {
  301.         return;
  302.     }
  303.     lastTime = now;
  304.     QStringList list;
  305.     list.append("[");
  306.     int count = imgs.count();
  307.     for (int i = 0; i < count; i++) {
  308.         QString imgData = getImageData2(imgs.at(i));
  309.         list.append(QString("{\"image\":\"%1\",\"image_type\":\"BASE64\"}").arg(imgData));
  310.         if (i < count - 1) {
  311.             list.append(",");
  312.         }
  313.     }
  314.     list.append("]");
  315.     QString data = list.join("");
  316.     QString url = QString("https://aip.baidubce.com/rest/2.0/face/v3/faceverify?access_token=%1").arg(tokenFace);
  317.     sendData(url, data);
  318. }
  319. void FaceBaiDu::idmatch(const QString &idcard, const QString &name)
  320. {
  321.     QStringList list;
  322.     list.append(QString("{\"id_card_num\":\"%1\",\"name\":\"%2\"}").arg(idcard).arg(name));
  323.     QString data = list.join("");
  324.     QString url = QString("https://aip.baidubce.com/rest/2.0/face/v3/person/idmatch?access_token=%1").arg(tokenFace);
  325.     sendData(url, data);
  326. }
  327. void FaceBaiDu::idcard(const QImage &img, bool front)
  328. {
  329.     QList<QHttpPart> httpParts;
  330.     httpParts << dataToHttpPart(front ? "front" : "back", "id_card_side");
  331.     httpParts << dataToHttpPart(getImageData(img), "image");
  332.     QString url = QString("https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=%1").arg(tokenOcr);
  333.     sendData(url, httpParts);
  334. }
  335. void FaceBaiDu::bankcard(const QImage &img)
  336. {
  337.     QList<QHttpPart> httpParts;
  338.     httpParts << dataToHttpPart(getImageData(img), "image");
  339.     QString url = QString("https://aip.baidubce.com/rest/2.0/ocr/v1/bankcard?access_token=%1").arg(tokenOcr);
  340.     sendData(url, httpParts);
  341. }
  342. void FaceBaiDu::driverLicense(const QImage &img)
  343. {
  344.     QList<QHttpPart> httpParts;
  345.     httpParts << dataToHttpPart(getImageData(img), "image");
  346.     QString url = QString("https://aip.baidubce.com/rest/2.0/ocr/v1/driving_license?access_token=%1").arg(tokenOcr);
  347.     sendData(url, httpParts);
  348. }
  349. void FaceBaiDu::vehicleLicense(const QImage &img)
  350. {
  351.     QList<QHttpPart> httpParts;
  352.     httpParts << dataToHttpPart(getImageData(img), "image");
  353.     QString url = QString("https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_license?access_token=%1").arg(tokenOcr);
  354.     sendData(url, httpParts);
  355. }




欢迎关注微信公众号:Qt实战/Qt入门和进阶(各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发) QQ:517216493  WX:feiyangqingyun  QQ群:751439350

只看该作者 1楼 发表于: 2018-08-13
刘大神真勤劳,
离线w642833823

只看该作者 2楼 发表于: 2018-08-14
你好,刘大师,可否把你的完整源代码提供一份谢谢,2873878546@qq.com

只看该作者 3楼 发表于: 2018-08-14
回 w642833823 的帖子
w642833823:你好,刘大师,可否把你的完整源代码提供一份谢谢,2873878546@qq.com (2018-08-14 14:55) 

刘大师开源的项目都会带源码的,没带源码的都是赞助开源的
离线wmx菜鸟

只看该作者 4楼 发表于: 2018-08-15
不愧为大神,谢谢分享
离线令狐少侠

只看该作者 5楼 发表于: 2018-08-15
身份证出身日期识别结果不对,没有身份证号码结果
离线令狐少侠

只看该作者 6楼 发表于: 2018-08-15
Face++识别结果比较准,就是住址有点问题
离线liudianwu

只看该作者 7楼 发表于: 2018-08-15
回 令狐少侠 的帖子
令狐少侠:Face++识别结果比较准,就是住址有点问题 (2018-08-15 09:58) 

把你身份证发给我试一下!
欢迎关注微信公众号:Qt实战/Qt入门和进阶(各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发) QQ:517216493  WX:feiyangqingyun  QQ群:751439350
离线llwj0303

只看该作者 8楼 发表于: 2018-08-15
专注C++,专注Qt
离线305750665

只看该作者 9楼 发表于: 2018-08-16
顶刘大师作品
雨田哥: 群号:853086607
QQ: 3246214072

刘典武-feiyangqingyun:专业各种自定义控件编写+UI定制+输入法定制+视频监控+工业控制+仪器仪表+嵌入式linux+各种串口网络通信,童叟无欺,量大从优,欢迎咨询购买定制!QQ:517216493
离线liuchangyin

只看该作者 10楼 发表于: 2018-08-16
功能不错
离线shenmingyi

只看该作者 11楼 发表于: 2018-08-17
楼主 1006714596@qq.com  好人一生平安 分享源码学习一下
离线return

只看该作者 12楼 发表于: 2018-08-20
      
离线pengchengfan

只看该作者 13楼 发表于: 2018-08-20
总感觉调用不难,难得是配置依赖库
离线liudianwu

只看该作者 14楼 发表于: 2018-08-20
回 pengchengfan 的帖子
pengchengfan:总感觉调用不难,难得是配置依赖库[表情]  (2018-08-20 14:50) 

不依赖任何东西,纯QNetworkAccessManager实现!
欢迎关注微信公众号:Qt实战/Qt入门和进阶(各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发) QQ:517216493  WX:feiyangqingyun  QQ群:751439350
离线pengchengfan

只看该作者 15楼 发表于: 2018-08-20
我看官方的SDK里面说需要安装libcurl openssl jsoncpp三个依赖库

只看该作者 16楼 发表于: 2018-09-08
回 pengchengfan 的帖子
pengchengfan:我看官方的SDK里面说需要安装libcurl openssl jsoncpp三个依赖库 (2018-08-20 15:47) 

这些qt都有了
快速回复
限100 字节
 
上一个 下一个