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