# API 期末项目 **Repository Path**: zhou_xin_yu/api---final-project ## Basic Information - **Project Name**: API 期末项目 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-01-16 - **Last Updated**: 2021-01-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 签签APP 产品需求文档 | 发布时间 | 未知 | |------|------------------------| | 产品名称 | 签签 | | 产品描述 | 一款通过高德API获取用户位置并通过人脸识别快速签到的APP| | 产品版本 | 1.0 | | 项目作者 | 周欣雨 | # MVP加/价值主张宣言 ### 产品功能 签签APP通过获取用户手机的摄像和用户的地理位置和用户输入的信息基于人脸识别API及高德API,基于tensorflow机器学习,实现web端人脸识别登陆,完成人脸注册,通过获取用户的位置信息基于静态地图及路径规划API,准确核实用户的地理信息。 ### 问题情景 随着人脸识别技术的快速进步以及市场应用需求的凸显以及资本的热捧,人脸识别在最近一两年显得特别火热。人脸识别技术在应用场景上也有了很大的突破,不再局限于考勤、门禁行业的简单应用,目前随着技术的进一步成熟和社会认同度的提高,其广泛应用于金融、司法、军队、公安、边检、政府、航天、电力、工厂、医疗及众多企事业单位等领域。 - 人工智能概率性考量:此产品将作为辅助用户完成签到助手型APP帮助用户更高效率准确完成签到,不需要用户分散过多的精力,正面影响高于负面影响。 # 问题表述与需求列表 ### 背景 据IDC发布的最新全球识别市场报告显示: - 截至2013年,识别领域已经超过74亿美元 - 至2015年, 预计中国市场规模将达到14亿 - 至2017年, 全球生物识别市场预计达到138.9亿美元 ### 加值宣言 ![加值宣言](https://images.gitee.com/uploads/images/2021/0124/091117_0b6a1fc7_5329181.jpeg "加值宣言.jpg") ![加值](https://images.gitee.com/uploads/images/2021/0124/091211_32704853_5329181.jpeg "jiazhi.jpg") ### 用户情景及用户画像 ![用户画像](https://images.gitee.com/uploads/images/2021/0124/091328_5ba63e08_5329181.jpeg "用户画像.jpg") - 目标用户群体:通过人脸识别和地理位置获取来定制一套准确的考勤系统。 ### 用户痛点 - 审核效率低:传统的远程身份核验,由人工审核完成,人力成本高、审核效率慢、反馈周期长。 - 伪造风险高:人像图片和身份证图片存在P图伪造风险,人证很有可能为「非真实信息」。 - 操作复杂度:用户需要提交各类证件信息,邮寄待审核信息、到线下网点办理、或上传大量审核内容。 | 用户 | 用户痛点 | 用户需求 | 重要程度 | |------|-----------------------------|---------|------| | 学校 | 日常签到中学生存在代签的问题,不能确定签到人的唯一性。 | 确保准确新 | 重要 | | 公司老板 | 员工上班签到存在代签,替签的问题 | 确保唯一且高效 | 重要 | ### 核心价值(最小可行性产品) - 人脸识别的核心系统,具有人脸识别人脸建模等核心功能支持照片检索,视频检索,动态监控告警等功能 ### 需求论证展示利害相关者分析 [智能分析动态人脸识别系统技术需求书](https://www.docin.com/p-2148133661.html) ![利害分析](https://images.gitee.com/uploads/images/2021/0124/093406_adc3e25b_5329181.jpeg "yonghuchangjing.jpg") ### 需求列表与API智能加值 - 防作弊能力强:提供在线、离线两种活体检测方案,有效抵御视频、翻拍、3D模型等活体作弊手段。 - 支持多人同时考勤:人脸识别SDK和人脸抓拍机支持同时捕捉视频流中出现的多张人脸,实现多人同时考勤,提高考勤效率。 - 快速响应:500毫秒快速识别比对,2秒内完成人脸捕捉、考勤全过程 | 优先级(重要性) | 需求(API←→用户需求) | API名称 | 是否是智能加值? | API类型 | 智能加值(如何加值?) | |----------|----------------|---------|----------|-------|------------------------------------| | 最重要 | 用户通过人脸识别完成签到 | 人脸识别API | 是 | 计算机视觉 | 通过人脸检测,特征提取,人脸对比完成人脸识别并成功签到 | | 重要 | 用户通过地里位置比对完成签到 | 高德API | 是 | 高德API | 运用高德开放平台-静态地图API、搜索API、路径规划(步行)API | # 界面流程及关键智能交互 ### 用户体验与旅程分析 - 用户可欲性(Desirability):符合用户快速查询需求,多元方式可供选择。操作简单,学习成本低。 - 技术可行性(Feasibility):基于人脸识别、高德API,着眼于用户对签到准确性的基本需求,通过获取用户手机的摄像和用户的地理位置和用户输入的信息基于人脸识别API及高德API,基于tensorflow机器学习,实现web端人脸识别登陆,完成人脸注册,通过获取用户的位置信息基于静态地图及路径规划API,准确核实用户的地理信息。 - 商业可行性(Feasibility):解决ESG问题,随着人脸识别技术的快速进步以及市场应用需求的凸显以及资本的热捧,在预防犯罪,维持社会稳定,保城市平安带动产业发展 ![难点](https://images.gitee.com/uploads/images/2021/0124/094716_c925e171_5329181.jpeg "nandian.jpg") ### 使用者交互与设计(产品原型) - 交互及界面设计 [交互原型演示](https://modao.cc/app/487dff36d88e01f31562f20e7b0fc9f628d07072?simulator_type=device&sticky) ### 用户体验与旅程分析的基础 - 原型交互流程图 ![主页](https://images.gitee.com/uploads/images/2021/0124/094928_7dc253ff_5329181.jpeg "1.0.jpg") ![1.2](https://images.gitee.com/uploads/images/2021/0124/095018_08e94f1f_5329181.jpeg "1.2.jpg") ![1.3](https://images.gitee.com/uploads/images/2021/0124/095030_aec7d978_5329181.jpeg "1.3.jpg") ![1.4](https://images.gitee.com/uploads/images/2021/0124/095043_e7bc56ec_5329181.jpeg "1.4.jpg") ![1.5](https://images.gitee.com/uploads/images/2021/0124/095055_ebbd8a9a_5329181.jpeg "1.5.jpg") ![1.6](https://images.gitee.com/uploads/images/2021/0124/095108_c976bb2b_5329181.jpeg "1.6.jpg") - 界面流程图 ![界面流程图](https://images.gitee.com/uploads/images/2021/0124/095155_75cfcb1e_5329181.jpeg "界面流程图.jpg") # 解决方案:数据流程及关键智能API使用 ### 智能API数据流程图 ![api](https://images.gitee.com/uploads/images/2021/0124/095243_e8b96119_5329181.jpeg "api数据图.jpg") ### 智能API思路方法: - 商业可行性:软硬结合,提升用户体验,发展服务周边产品,增加收入来源。 - 技术可行性:将签到者,发布签到者,监督签到者整合在一个服务流程中,实现平台的价值。 - 用户可欲性:辅助用户高效便捷签到,帮助用户提高时间观念。 ### API使用水平 - 提交post请求,将uid ugroup pic提交,进行人脸信息保存操作 - 收到请求后将pic进行处理解析为128维向量保存,并跟uid和ugroup保存入库 ,返回数据库插入成功的id - 提交post请求,将ugroup pic提交人脸查询请求,意思为再ugroup中查看与图片pic相似的人脸 - 收到请求后,处理图片解析图片中所有的人脸,进行按库查询,然后与该图片中所有人脸相似的uid和距离(相似度距离) 1. 提前建立数据库 ``` db = mysql.connector.connect(user='root', password='123456', host='127.0.0.1', database='face_data') ``` ``` CREATE TABLE `face_json` ( `id` int(32) NOT NULL AUTO_INCREMENT COMMENT 'id自增', `ugroup` varchar(255) DEFAULT NULL COMMENT '用户群组', `uid` varchar(64) DEFAULT NULL COMMENT '图片用户id', `json` text COMMENT '人脸的向量', `pic_name` varchar(255) DEFAULT NULL COMMENT '图片名称', `date` datetime DEFAULT NULL COMMENT '插入时间', `state` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ``` 2. ``` # -*- coding:utf-8 -*- import mysql.connector import datetime class face_mysql: def __init__(self): pass #设置数据库和密码 def conn_mysql(self): db = mysql.connector.connect(user='root', password='123456', host='127.0.0.1', database='face_data') return db def insert_facejson(self, pic_name, pic_json, uid, ugroup): db = self.conn_mysql() cursor = db.cursor() dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") sql = "insert into face_json(json,pic_name,date,state,uid,ugroup) values('%s' ,'%s','%s','%d','%s','%s') ;" % ( pic_json, pic_name, dt, 1, uid, ugroup) #print("sql=",sql) try: # 执行sql语句 cursor.execute(sql) # 提交到数据库执行 lastid = int(cursor.lastrowid) db.commit() except: # Rollback in case there is any error db.rollback() db.close() return lastid def findall_facejson(self, ugroup): db = self.conn_mysql() cursor = db.cursor() sql = "select * from face_json where state=1 and ugroup= '%s' ;" % (ugroup) try: cursor.execute(sql) results = cursor.fetchall() return results except: print("Error:unable to fecth data") db.close() ``` ``` # -*- coding:utf-8 -*- from flask import Flask, jsonify, abort, make_response, request, url_for from flask_httpauth import HTTPBasicAuth import json import os import ntpath import argparse import face_mysql import tensorflow as tf import src.facenet import src.align.detect_face import numpy as np from scipy import misc import matrix_fun import urllib app = Flask(__name__) # 图片最大为16M app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 auth = HTTPBasicAuth() #设置最大的相似距离,1.22是facenet基于lfw计算得到的 MAX_DISTINCT=1.22 # 设置上传的图片路径和格式 from werkzeug import secure_filename #设置post请求中获取的图片保存的路径 UPLOAD_FOLDER = './pic_tmp/' if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER) else: pass ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg']) app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS with tf.Graph().as_default(): gpu_memory_fraction = 1.0 gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_fraction) sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False)) with sess.as_default(): pnet, rnet, onet = src.align.detect_face.create_mtcnn(sess, None) #训练模型的路径 modelpath = "./models/facenet/20170512-110547" with tf.Graph().as_default(): sess = tf.Session() # src.facenet.load_model(modelpath) # 加载模型 meta_file, ckpt_file = src.facenet.get_model_filenames(modelpath) saver = tf.train.import_meta_graph(os.path.join(modelpath, meta_file)) saver.restore(sess, os.path.join(modelpath, ckpt_file)) # Get input and output tensors images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") # 进行人脸识别,加载 print('Creating networks and loading parameters') #获取post中的图片并执行插入到库 返回数据库中保存的id @app.route('/face/insert', methods=['POST']) def face_insert(): #分别获取post请求中的uid 和ugroup作为图片信息 uid = request.form['uid'] ugroup = request.form['ugroup'] upload_files = request.files['imagefile'] #从post请求图片保存到本地路径中 file = upload_files if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) print(image_path) #opencv读取图片,开始进行人脸识别 img = misc.imread(os.path.expanduser(image_path), mode='RGB') # 设置默认插入时 detect_multiple_faces =Flase只检测图中的一张人脸,True则检测人脸中的多张 #一般入库时只检测一张人脸,查询时检测多张人脸 images = image_array_align_data(img, image_path, pnet, rnet, onet, detect_multiple_faces=False) feed_dict = {images_placeholder: images, phase_train_placeholder: False} #emb_array保存的是经过facenet转换的128维的向量 emb_array = sess.run(embeddings, feed_dict=feed_dict) filename_base, file_extension = os.path.splitext(image_path) id_list = [] #存入数据库 for j in range(0, len(emb_array)): face_mysql_instant = face_mysql.face_mysql() last_id = face_mysql_instant.insert_facejson(filename_base + "_" + str(j), ",".join(str(li) for li in emb_array[j].tolist()), uid, ugroup) id_list.append(str(last_id)) #设置返回类型 request_result = {} request_result['id'] = ",".join(id_list) if len(id_list) > 0: request_result['state'] = 'sucess' else: request_result['state'] = 'error' print(request_result) return json.dumps(request_result) @app.route('/face/query', methods=['POST']) def face_query(): #获取查询条件 在ugroup中查找相似的人脸 ugroup = request.form['ugroup'] upload_files = request.files['imagefile'] #获取post请求的图片到本地 file = upload_files if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) print(image_path) #读取本地的图片 img = misc.imread(os.path.expanduser(image_path), mode='RGB') images = image_array_align_data(img, image_path, pnet, rnet, onet) #判断如果如图没有检测到人脸则直接返回 if len(images.shape) < 4: return json.dumps({'error': "not found face"}) feed_dict = {images_placeholder: images, phase_train_placeholder: False} emb_array = sess.run(embeddings, feed_dict=feed_dict) face_query = matrix_fun.matrix() #分别获取距离该图片中人脸最相近的人脸信息 # pic_min_scores 是数据库中人脸距离(facenet计算人脸相似度根据人脸距离进行的) # pic_min_names 是当时入库时保存的文件名 # pic_min_uid 是对应的用户id pic_min_scores, pic_min_names, pic_min_uid = face_query.get_socres(emb_array, ugroup) #如果提交的query没有group 则返回 if len(pic_min_scores) == 0: return json.dumps({'error': "not found user group"}) #设置返回结果 result = [] for i in range(0, len(pic_min_scores)): if pic_min_scores[i] 0: det = bounding_boxes[:, 0:4] det_arr = [] img_size = np.asarray(img.shape)[0:2] if nrof_faces > 1: if detect_multiple_faces: for i in range(nrof_faces): det_arr.append(np.squeeze(det[i])) else: bounding_box_size = (det[:, 2] - det[:, 0]) * (det[:, 3] - det[:, 1]) img_center = img_size / 2 offsets = np.vstack( [(det[:, 0] + det[:, 2]) / 2 - img_center[1], (det[:, 1] + det[:, 3]) / 2 - img_center[0]]) offset_dist_squared = np.sum(np.power(offsets, 2.0), 0) index = np.argmax( bounding_box_size - offset_dist_squared * 2.0) # some extra weight on the centering det_arr.append(det[index, :]) else: det_arr.append(np.squeeze(det)) images = np.zeros((len(det_arr), image_size, image_size, 3)) for i, det in enumerate(det_arr): det = np.squeeze(det) bb = np.zeros(4, dtype=np.int32) bb[0] = np.maximum(det[0] - margin / 2, 0) bb[1] = np.maximum(det[1] - margin / 2, 0) bb[2] = np.minimum(det[2] + margin / 2, img_size[1]) bb[3] = np.minimum(det[3] + margin / 2, img_size[0]) cropped = img[bb[1]:bb[3], bb[0]:bb[2], :] # 进行图片缩放 cv2.resize(img,(w,h)) scaled = misc.imresize(cropped, (image_size, image_size), interp='bilinear') nrof_successfully_aligned += 1 # 保存检测的头像 filename_base = './pic_tmp' filename = os.path.basename(image_path) filename_name, file_extension = os.path.splitext(filename) #多个人脸时,在picname后加_0 _1 _2 依次累加。 output_filename_n = "{}/{}_{}{}".format(filename_base, filename_name, i, file_extension) misc.imsave(output_filename_n, scaled) scaled = src.facenet.prewhiten(scaled) scaled = src.facenet.crop(scaled, False, 160) scaled = src.facenet.flip(scaled, False) images[i] = scaled if nrof_faces > 0: return images else: # 如果没有检测到人脸 直接返回一个1*3的0矩阵 多少维度都行 只要能和是不是一个图片辨别出来就行 return np.zeros((1, 3)) # 备用 通过urllib的方式从远程地址获取一个图片到本地 # 利用该方法可以提交一个图片的url地址,则也是先保存到本地再进行后续处理 def get_url_imgae(picurl): response = urllib.urlopen(picurl) pic = response.read() pic_name = "./pic_tmp/" + os.path.basename(picurl) with open(pic_name, 'wb') as f: f.write(pic) return pic_name @auth.get_password def get_password(username): if username == 'face': return 'face' return None @auth.error_handler def unauthorized(): return make_response(jsonify({'error': 'Unauthorized access'}), 401) @app.errorhandler(400) def not_found(error): return make_response(jsonify({'error': 'Invalid data!'}), 400) if __name__ == '__main__': app.run(host='0.0.0.0', port=8088) ``` - 处理文件夹下的人脸图片 ``` # -*- coding:utf-8 -*- import os import json import tensorflow as tf import src.facenet import src.align.detect_face import numpy as np from scipy import misc import face_mysql class face_reconition: def __init__(self): pass def prewhiten(self, x): mean = np.mean(x) std = np.std(x) std_adj = np.maximum(std, 1.0 / np.sqrt(x.size)) y = np.multiply(np.subtract(x, mean), 1 / std_adj) return y # 根据路径获取该文件夹中所有的图片 def get_image_paths(self, inpath): paths = [] for file in os.listdir(inpath): if os.path.isfile(os.path.join(inpath, file)): if file.lower().endswith(('.png', '.jpg', '.jpeg')) is False: continue paths.append(os.path.join(inpath, file)) return (paths) # 将一个文件夹下的所有图片转化为json 方法二 只能是传入文件夹 并存入数据库 def images_to_vectors(self, inpath, outjson_path, modelpath): results = dict() with tf.Graph().as_default(): with tf.Session() as sess: src.facenet.load_model(modelpath) # Get input and output tensors images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") image_paths = self.get_image_paths(inpath) for image_path in image_paths: # 获取图片中的人脸数 img = misc.imread(os.path.expanduser(image_path), mode='RGB') images = self.image_array_align_data(img,image_path) #判断是否检测出人脸 检测不出 就跳出此循环 if images.shape[0] == 1 : continue feed_dict = {images_placeholder: images, phase_train_placeholder: False} emb_array = sess.run(embeddings, feed_dict=feed_dict) filename_base, file_extension = os.path.splitext(image_path) for j in range(0, len(emb_array)): results[filename_base + "_" + str(j)] = emb_array[j].tolist() face_mysql_instant = face_mysql.face_mysql() face_mysql_instant.insert_facejson(filename_base + "_" + str(j), ",".join(str(li) for li in emb_array[j].tolist())) # All done, save for later! json.dump(results, open(outjson_path, "w")) # 返回图像中所有人脸的向量 def image_array_align_data(self, image_arr,image_path, image_size=160, margin=32, gpu_memory_fraction=1.0, detect_multiple_faces=True): minsize = 20 # minimum size of face threshold = [0.6, 0.7, 0.7] # three steps's threshold factor = 0.709 # scale factor print('Creating networks and loading parameters') with tf.Graph().as_default(): gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_fraction) sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False)) with sess.as_default(): pnet, rnet, onet = src.align.detect_face.create_mtcnn(sess, None) img = image_arr bounding_boxes, _ = src.align.detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor) nrof_faces = bounding_boxes.shape[0] nrof_successfully_aligned = 0 if nrof_faces > 0: det = bounding_boxes[:, 0:4] det_arr = [] img_size = np.asarray(img.shape)[0:2] if nrof_faces > 1: if detect_multiple_faces: for i in range(nrof_faces): det_arr.append(np.squeeze(det[i])) else: bounding_box_size = (det[:, 2] - det[:, 0]) * (det[:, 3] - det[:, 1]) img_center = img_size / 2 offsets = np.vstack( [(det[:, 0] + det[:, 2]) / 2 - img_center[1], (det[:, 1] + det[:, 3]) / 2 - img_center[0]]) offset_dist_squared = np.sum(np.power(offsets, 2.0), 0) index = np.argmax( bounding_box_size - offset_dist_squared * 2.0) # some extra weight on the centering det_arr.append(det[index, :]) else: det_arr.append(np.squeeze(det)) images = np.zeros((nrof_faces, image_size, image_size, 3)) for i, det in enumerate(det_arr): det = np.squeeze(det) bb = np.zeros(4, dtype=np.int32) bb[0] = np.maximum(det[0] - margin / 2, 0) bb[1] = np.maximum(det[1] - margin / 2, 0) bb[2] = np.minimum(det[2] + margin / 2, img_size[1]) bb[3] = np.minimum(det[3] + margin / 2, img_size[0]) cropped = img[bb[1]:bb[3], bb[0]:bb[2], :] # 进行图片缩放 cv2.resize(img,(w,h)) scaled = misc.imresize(cropped, (image_size, image_size), interp='bilinear') nrof_successfully_aligned += 1 # print(scaled) # scaled=self.prewhiten(scaled) # 保存检测的头像 filename_base = './img/' filename = os.path.basename(image_path) filename_name, file_extension = os.path.splitext(filename) output_filename_n = "{}/{}_{}{}".format(filename_base, filename_name, i, file_extension) misc.imsave(output_filename_n, scaled) scaled = src.facenet.prewhiten(scaled) scaled = src.facenet.crop(scaled, False, 160) scaled = src.facenet.flip(scaled, False) images[i] = scaled if nrof_faces > 0: return images else: #如果没有检测到人脸 直接返回一个1*3的0矩阵 多少维度都行 只要能和是不是一个图片辨别出来就行 return np.zeros((1,3)) if __name__ == "__main__": face_reconition = face_reconition() images_path = './img/img' #模型地址 modelpath = '/export/zang/facenet/models/facenet/20170512-110547' out_path = './img/pic.json' face_reconition.images_to_vectors(images_path, out_path, modelpath) ``` - 高德API代码 ``` #!/usr/bin/env python # coding: utf-8 # In[232]: # 准备工作 import requests,json import pandas as pd from PIL import Image from io import BytesIO zhou_key = "a24e04cfaf285a2af77f76b527b2128b" # 到高德api注册账号申请web服务API类型key # In[176]: # 准备起始点和终点 # 数据准备: origin = "山东省聊城市东昌府区盛世柳园D区" destination = "山东省聊城市东昌府区北顺小学" # In[177]: # 函数 def geocode(key,address,city=None,batch="false",output="JSON",callback=None)->str: """高德API地理编码获取""" url = "https://restapi.amap.com/v3/geocode/geo?parameters" params_geocode = { "key":key, "address":address, "city":city, "batch":batch, "output":output, "callback":callback } response = requests.get(url=url_geocode,params=params_geocode) results = response.json()['geocodes'][0]['location'] # 列表提取 return results # In[178]: help(geocode) # In[179]: results_起始点 = geocode(zhou_key,origin) results_起始点 # In[180]: results_终点 = geocode(zhou_key,destination) results_终点 # In[181]: # 逆地理密码的应用 # 1.逆地理编码可以将经纬度转换为详细结构化的地址,且返回附近周边的POI、AOI信息。 # 2.url:https://restapi.amap.com/v3/geocode/regeo?parameters (官网有提供) # 3.requests.get() # 4.参数: # 4.1必选参数:key、location(经纬度坐标) # 4.2可选参数: # poitype(返回附近POI类型,需要extensions参数为all时才生效,参数仅支持传入POI TYPECODE,可以传入多个POI TYPECODE,相互之间用“|”分隔。该参数在 batch 取值为true时不生效。获取 POI TYPECODE 可以参考POI分类码表 # radius(搜索半径,取值范围在0~3000,默认是1000。单位:米,缺省值:1000) # extensions(默认取值是 base,也就是返回基本地址信息;值为 all 时会返回基本地址信息、附近 POI 内容、道路信息以及道路交叉口信息。) # batch(参数设置为 true 时进行批量查询操作,最多支持 20 个经纬度点进行批量地址查询操作。设置为 false 时进行单点查询,此时即使传入多个经纬度也只返回第一个经纬度的地址解析查询结果。) # roadlevel(道路等级。当roadlevel=0时,显示所有道路,当roadlevel=1时,过滤非主干道路,仅输出主干道路数据。需要 extensions 参数为 all 时才生效) # output # callback # homeorcorp(供三个可选参数:0:不对召回的排序策略进行干扰。1:综合大数据分析将居家相关的 POI 内容优先返回,即优化返回结果中 pois 字段的poi顺序。2:综合大数据分析将公司相关的 POI 内容优先返回,即优化返回结果中 pois 字段的poi顺序。需要 extensions 参数为 all 时才生效) # 5.具体应用场景:提供给用户搜索当前所在地周边的生活基础设施,了解当前所在地的繁荣度。 # In[182]: # 数据准备 address_1 = "山东省聊城市聊城大学" city_1 = "山东" # 每次获取地理编码,只需要在此处填写目标地址和目标地址所在城市(省份) # In[183]: # 逆地理密码的获取 """获取逆地理编码函数""" """location为目标地址的坐标""" def Inverse_geocoding(key,location,poitype=None,radius=1000,extensions='all',batch='false',output='JSON',callback=None,roadlevel=1,homeorcorp=0): url = "https://restapi.amap.com/v3/geocode/regeo?parameters" params = { "key":key, "location":location, "poitype":poitype, "radius":radius, "extensions":extensions, "batch":batch, "output":output, "callback":callback, "roadlevel":roadlevel, "homeorcorp":homeorcorp } response = requests.get(url=url,params=params) results = pd.json_normalize(response.json()['regeocode']['pois']) return results # 返回值 # In[184]: location_聊城大学 = geocode(zhou_key,address_1,city_1) # In[185]: Inverse_geocoding(zhou_key,location_聊城大学) # In[186]: # 路径规划 准备 # 2.URL # 2.1步行url:https://restapi.amap.com/v3/direction/walking?parameters # 2.2公交:https://restapi.amap.com/v3/direction/transit/integrated?parameters # 2.3驾车:https://restapi.amap.com/v3/direction/driving?parameters # 3 具体应用场景:帮助用户规划通勤方案。 # In[187]: # 数据准备(出发地、目的地) origin_聊城大学 = geocode(zhou_key,address_1,city_1) destination_北顺小学_1 = "山东省聊城市东昌府区北顺小学" destination_北顺小学 = geocode(zhou_key,destination_北顺小学_1,city_1) # In[188]: """获取步行路径函数""" """origin为起始地的坐标,destination为目的地的坐标""" def walking(key,origin,destination,output='JSON',callback=None): url = "https://restapi.amap.com/v3/direction/walking?parameters" params = { "key":key, "origin":origin, "destination":destination, "output":output, "callback":callback } response = requests.get(url=url,params=params) result = pd.json_normalize(response.json()['route']['paths'][0]['steps']) return result # In[189]: walking(zhou_key,origin_聊城大学,destination_北顺小学) # In[190]: # 公交路径 参数: 必选参数:key、origin(出发地坐标)、destination(目的地坐标)、city(出发地城市)、cityd(目的地城市) # In[191]: """获取公交路径的函数""" """origin为起始地的坐标,destination为目的地的坐标,city为出发地城市,cityd为目的地城市""" def bus(key,origin,destination,city,cityd,extensions='base',strategy=3,nightflag=0,output='JSON',callback=None): url = "https://restapi.amap.com/v3/direction/transit/integrated?parameters" params = { "key":key, "origin":origin, "destination":destination, "city":city, "cityd":cityd, "extensions":extensions, "strategy":strategy, "nightflag":nightflag, "output":output, "callback":callback } response = requests.get(url,params=params) results = response.json() return results # In[192]: bus(zhou_key,origin_聊城大学,destination_北顺小学,'山东','山东') # In[193]: # 步行前往车站路径 pd.json_normalize(bus(zhou_key,origin_聊城大学,destination_北顺小学,'山东','山东')['route']['transits'][0]['segments'][0]['walking']['steps']) # In[194]: pd.json_normalize(bus(zhou_key,origin_聊城大学,destination_北顺小学,'山东','山东')['route']['transits'][0]['segments'][0]['bus']['buslines'][0]) # In[195]: pd.json_normalize(bus(zhou_key,origin_聊城大学,destination_北顺小学,'山东','山东')['route']['transits'][0]['segments'][0]['bus']['buslines'][0]['via_stops']) # In[196]: # 驾车路径查询 """获取驾车路径函数""" """origin为起始地的坐标,destination为目的地的坐标""" """province为车牌省份汉字缩写,number为车牌处省份外的字母与数字""" def driving(key,origin,destination,province,number,cartype=0,strategy=10,originid=None,destinationid=None,origintype=None,destinationtype=None,waypoints=None,avoidpolygons=None,avoidroad=None,ferry=0,roadaggregation='false',nosteps=0,output='JSON',callback=None,extensions='base'): # 自定义函数名称为driving,括号内为参数。 url = "https://restapi.amap.com/v3/direction/driving?parameters" params = { "key":key, "origin":origin, "destination":destination, "originid":originid, "destinationid":destinationid, "origintype":origintype, "destinationtype":destinationtype, "strategy":strategy, "waypoints":waypoints, "avoidpolygons":avoidpolygons, "province":province, "number":number, "cartype":cartype, "ferry":ferry, "roadaggregation":roadaggregation, "nosteps":nosteps, "output":output, "callback":callback, "extensions":extensions } response = requests.get(url,params=params) # 使用normalize函数制作成表格,并提取处我们想要的信息,方便阅读。 results = pd.json_normalize(response.json()['route']['paths'][0]['steps']) return results # In[197]: driving_origin = origin_聊城大学 driving_destination = destination_北顺小学 driving_province = "鲁" driving_number = "577EH" # In[198]: driving(zhou_key,driving_origin,driving_destination,driving_province,driving_number) # In[199]: # 行政区域查询 # 1.行政区域查询是一类简单的HTTP接口,根据用户输入的搜索条件可以帮助用户快速的查找特定的行政区域信。 # 2.(url:https://restapi.amap.com/v3/config/district?parameters) # 3.参数: # 3.1必选参数:key # 具体应用场景:帮助用户查询行政区域 # In[200]: """查询行政区域函数""" """keywords为省市名称""" def administration(key,keywords,subdistrict=1,page=1,offset=20,extensions="base",output='JSON',callback=None): url = "https://restapi.amap.com/v3/config/district?parameters" params = { "key":key, "keywords":keywords, "subdistrict":subdistrict, "page":page, "offset":offset, "extensions":extensions, "output":output, "callback":callback } response = requests.get(url,params=params) results = pd.json_normalize(response.json()['districts'][0]['districts']) return results # In[201]: administration_keywords = "山东" # In[202]: administration(zhou_key,administration_keywords) # In[203]: # 搜索POI # 关键字搜索 # 具体应用场景:用户可以通过指定区域和指定关键字,搜索到相关的地点的基本信息(图片、位置等) # In[204]: """关键字搜索函数""" """keywords为搜索内容的关键字,city为搜索内容所在城市""" def text(key,keywords,city,types=None,citylimit="true",extensions="all",children=0,offset=20,page=1,output='JSON',callback=None): url = "https://restapi.amap.com/v3/place/text?parameters" params = { "key":key, "keywords":keywords, "types":types, "city":city, "citylimit":citylimit, "extensions":extensions, "children":children, "offset":offset, "page":page, "output":output, "callback":callback } response = requests.get(url,params=params) result = response.json() return result # In[205]: text_keywords = "旅游景区" text_city = "山东" # In[206]: text(zhou_key,text_keywords,text_city) # In[207]: # 周边搜索 # 具体应用场景:用户可以通过关键字和指定中心地点,展开搜索四周的相关内容 # In[208]: """周边搜索函数""" """location为中心点坐标,keywords为搜索内容关键字""" def around(key,location,keywords,city=None,radius=3000,sortrule="distance",offset=20,page=1,extensions="base",output='JSON',callback=None): url = "https://restapi.amap.com/v3/place/around?parameters" params = { "key":key, "location":location, "keywords":keywords, "city":city, "radius":radius, "sortrule":sortrule, "offset":offset, "page":page, "extensions":extensions, "output":output, "callback":callback } response = requests.get(url,params=params) result = response.json() #result = pd.json_normalize(response.json()['pois'][0]['type']) return result # In[209]: around_location = origin_聊城大学 around_keywords = "美食" # In[210]: around(zhou_key,around_location,around_keywords) # In[211]: # ID查询 # 具体应用场景:用户通过兴趣点的唯一标识ID查询到此地点的基本信息(照片、地址等) # In[212]: """ID查询函数""" """id为兴趣点的唯一标识ID""" def id_search(key,id,output='JSON',callback=None): url = "https://restapi.amap.com/v3/place/detail?parameters " params = { "key":key, "id":id, "output":output, "callback":callback } response = requests.get(url,params=params) result = response.json() return result # In[213]: id_search(zhou_key,'B00140AKR1') # In[214]: # IP定位 # 具体应用场景:通过IP搜索到此IP的相关信息 # In[215]: """IP定位函数""" def ip_locating(key,ip,output='JSON'): url = "https://restapi.amap.com/v3/ip?parameters" params = { "key":key, "ip":ip, "output":output } response = requests.get(url,params=params) result = response.json() return result # In[216]: ip_locating(zhou_key,"61.242.54.73") # In[217]: # 静态地图 # 具体应用场景:为用户返回指定地点的地图,地图中包括周边路况、基础设施。 # In[218]: """获取静态地图函数""" """location为中心点坐标,zoom为地图缩放级别:[1,17]""" def staticmap(key,location,zoom,size="600*300",scale=2,markers=None,labels=None,paths=None,traffic=1): #zoom=None,size=400*400,scale=2,markers=None,labels=None,paths=None,traffic=1 url = "https://restapi.amap.com/v3/staticmap?parameters" params = { "key":key, "location":location, "zoom":zoom, "size":size, "scale":scale, "markers":markers, "labels":labels, "paths":paths, "traffic":traffic } r = requests.get(url,params=params) result = r.content from PIL import Image from io import BytesIO i = Image.open(BytesIO(r.content)) results = i return results # In[219]: staticmap_location = origin_聊城大学 # In[220]: staticmap(zhou_key,staticmap_location,17) # In[221]: # 坐标转换 # In[222]: """坐标转换函数""" """location为所需转换的地址的坐标""" def coordinate_convert(key,locations,coordsys="autonavi",output='JSON'): url = "https://restapi.amap.com/v3/assistant/coordinate/convert?parameters" params = { "key":key, "locations":locations, "coordsys":coordsys, "output":output } response = requests.get(url,params=params) result = response.json() return result # In[223]: coordinate_convert(zhou_key,origin_聊城大学) # In[224]: # 天气查询 # 具体应用场景:为用户返回指定地点的当前天气状况或预测天气状况。 # In[225]: """查询天气函数""" """city为所需查询的城市的城市编码""" def weather(key,city,extensions="base",output='JSON'): url = "https://restapi.amap.com/v3/weather/weatherInfo?parameters" params = { "key":key, "city":city, "extensions":extensions, "output":output } response = requests.get(url,params=params) result = pd.json_normalize(response.json()['lives']) return result # In[226]: weather(zhou_key,"371502") # In[227]: # 输入提示 # 具体应用场景:为用户搜索与关键词相关的地点。 # In[228]: """获取输入提示函数""" """keywords为搜索关键字,city为所需查询的城市的城市编码""" def inputtips(key,keywords,city,type=None,location=None,citylimit="true",datatype="all",output='JSON',callback=None): url = "https://restapi.amap.com/v3/assistant/inputtips?parameters" params = { "key":key, "keywords":keywords, "city":city, "type":type, "location":location, "citylimit":citylimit, "datatype":datatype, "output":output, "callback":callback } response = requests.get(url,params=params) result = pd.json_normalize(response.json()['tips']) return result # In[229]: inputtips(zhou_key,"汽修店","371502") # In[ ]: # In[ ]: ``` # API使用比较分析 - Azure 成本分析 ![成本](https://images.gitee.com/uploads/images/2021/0124/113510_9f7545f6_5329181.jpeg "azure.jpg") ![11](https://images.gitee.com/uploads/images/2021/0124/113715_8a959ab2_5329181.jpeg "azure11.jpg") Azure 计费 API 允许你以编程方式查看和管理计费详细信息。 下面列出的操作组不支持所有计费帐户。 表中指定了支持的计费帐户。 [计费账户与范围](https://docs.microsoft.com/zh-cn/azure/cost-management-billing/manage/view-all-accounts) | 范围 | 定义 | |------|------------------------------------------------------| | 计费账户 | 表示客户接受使用 Azure 的协议。 它包含一个或多个订阅 | | 订阅 | 表示 Azure 资源的分组。 发票在此范围生成。 其他计费信息(如付款方式和使用地址)与此范围相关联。 | - FACE++ 创建一个人脸的集合 FaceSet,用于存储人脸标识 face_token。一个 FaceSet 能够存储10000个 face_token。试用API Key可以创建1000个FaceSet,正式API Key可以创建10000个FaceSet。 - 智能百度云 ![百度云](https://images.gitee.com/uploads/images/2021/0124/114624_8c6f5b8c_5329181.jpeg "智能百度云.jpg") - 调用计费实例 - 如果您需要50个QPS,除免费赠送的10QPS外(需要企业认证),您还需购买40个QPS。则计费方式为:300*10+250*30=10500 元/月 - 如果您需要购买1个月+5天的1个QPS,可以按照包月+按天的搭配模式购买,即:300*1+30*5=450 元 # 人工智能概率性 - 确保为真人:通过离在线双重活体检测,确保操作者为真人,可有效抵御彩打照片、视频、3D建模等攻击。用户无需提交任何资料,或去网点柜台办理业务,高效方便 - 确保为本人:基于「真人」的基础,将真人人脸图片与公民身份信息库的人脸小图对比,确保操作者身份的真实性。避免身份证或人脸图像伪造等欺诈风险,权威可靠。 # 学习实践心得总结及感谢 学习心得:通过API人工智能这门课的学习,我了解到了许多有关API的知识,即API就是操作系统留给应用程序的一个调用接口,应用程序通过调用操作系统的 API 而使操作系统去执行应用程序的命令。非常高效便捷,节省了开发者的时间和精力,也更加体会到前后端分工合作的重要性。通过api这个课程的学习,拓宽了我的思维,使我以更加创新的方式思考和解决问题。 感谢Azure平台、高德开放平台,face++平台,百度云开放平台,是他们的支持让我对API有了更深刻的理解,在人脸识别API的学习中,我们共尝试了三个平台。每一个平台都会给出其API文档供我们了解其功能及调用方法。但它们都是大同小异的。以Azure为例,文档里包括了:功能概述、Http Method、Request URL、Request parameters、Request headers、Request body以及Response。整个文档及代码都是围绕着Request展开。接下来我们只需要按照把我们获取的(或自定义的)终结点、密钥,人脸相片URL等数据按照示例代码填入对应位置就基本搞定了。在Request parameters中,我们还可以进一步按需选用API文档里面提供的功能。 # 有效外链 - 交互原型 [体验链接](https://modao.cc/app/487dff36d88e01f31562f20e7b0fc9f628d07072?simulator_type=device&sticky) - 20*20投影片ppt视频解说 [视频解说](https://b23.tv/qccIq7) - Azure 平台 - [Azure 人脸识别文档](https://docs.microsoft.com/zh-cn/rest/api/cognitiveservices/face/facelist/create) - [成本管理与计费](https://docs.microsoft.com/zh-cn/azure/cost-management-billing/) - 百度ai 开放平台 [百度人脸识别](https://ai.baidu.com/ai-doc/FACE/Bk37c1kb7) - face++ [face++ 人脸识别](https://ai.baidu.com/ai-doc/FACE/Bk37c1kb7) - 其它 - [智能分析动态人脸识别系统技术需求书](https://www.docin.com/p-2148133661.html) - [Windows10 系统不兼容问题](https://www.cnblogs.com/lza945/p/13287158.html) - [下载各种模块超时问题](https://blog.csdn.net/weixin_41665637/article/details/105028725) - [jupyter notebook 下载模块问题](https://blog.csdn.net/qxqxqzzz/article/details/93791546) - [flask 的应用问题](https://blog.csdn.net/bbwangj/article/details/105497578) - [GitHub参考链接](https://github.com/JDAI-CV/FaceX-Zoo) - [MySQL配置环境变量](https://blog.csdn.net/weixin_49879718/article/details/107883543?utm_source=app&app_version=4.5.0)