前言
我们要实现一个人脸识别的功能,人脸识别的都是调用本地的图片,所以我们搭建一个接口服务来提供图片的上传。
接口
一般接口
接口使用FastAPI框架
https://fastapi.tiangolo.com/zh/#_4
注意
该框架需要Python 3.6 及更高版本
环境变量中添加
KEY | VALUE |
---|---|
Path | D:ToolsPython310D:ToolsPython310Scripts |
另外要注意
系统变量
的优先级要比用户变量
的优先级高,如果配置后还是2.x版本,就要看看是否系统变量中也配置了。 配置完成后要重启开发工具,不用重启电脑。
安装
代码语言:javascript复制pipenv install fastapi
pipenv install uvicorn[standard]
创建一个 main.py
文件并写入以下内容:
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
通过以下命令运行服务器:
代码语言:javascript复制pipenv run uvicorn main:app --reload
使用浏览器访问
http://127.0.0.1:8000/items/5?q=somequery
这样我们的接口服务就搭建好了。
对接的接口文档地址
http://127.0.0.1:8000/docs
静态文件
代码语言:javascript复制from fastapi.staticfiles import StaticFiles
app.mount("/web", StaticFiles(directory="web"), name="web")
所有以/web/
开头的请求都会访问到web目录中。
文件上传
一般文件上传
要用 File,需要先安装这个库
代码语言:javascript复制pipenv install python-multipart
代码
代码语言:javascript复制# -*- coding:utf-8 -*-
import uuid
import uvicorn
import os
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.get("/")
def read_root():
return {"code": 0, "msg": "请求成功"}
# file 参数类型是字节 bytes
@app.post("/upfile/")
async def upfile(file: bytes = File(...)):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def uploadfile(image: UploadFile = File(...)):
try:
if not os.path.exists("images"):
os.makedirs("images")
except Exception as e:
print(e)
suffix_arr = image.filename.split(".")
suffix = suffix_arr[len(suffix_arr) - 1]
file_name = os.getcwd() "/images/" str(uuid.uuid1()) "." suffix
with open(file_name, "wb ") as f:
f.write(image.file.read())
f.close()
return {"filename": file_name}
if __name__ == "__main__":
uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True, debug=True)
Base64图片上传
代码语言:javascript复制import base64
from fastapi import Body
@app.post("/base64file")
async def uploadfile(image=Body(None), suffix=Body(None)):
imgdata = base64.b64decode(image)
file_name = os.getcwd() "/images/" str(uuid.uuid1()) "." suffix
file = open(file_name, 'wb')
file.write(imgdata)
file.close()
return {"code": 0, "obj": file_name}
人像识别
face_recognition
https://github.com/ageitgey/face_recognition
安装
代码语言:javascript复制pipenv install cmake
pipenv install dlib
pipenv install face_recognition
使用
代码语言:javascript复制import face_recognition
image = face_recognition.load_image_file("your_file.jpg")
face_locations = face_recognition.face_locations(image)
deepface
https://github.com/serengil/deepface
安装
代码语言:javascript复制pipenv install deepface
使用
代码语言:javascript复制from deepface import DeepFace
result = DeepFace.verify(img1_path = "img1.jpg", img2_path = "img2.jpg")
print(result)
注意
这个库主要用于对比人脸相似度,人脸的特征等功能。
接口对接人脸识别
代码语言:javascript复制# -*- coding:utf-8 -*-
import uuid
import uvicorn
import os
from fastapi import FastAPI, File, UploadFile
from starlette.responses import RedirectResponse
import face_recognition
app = FastAPI()
@app.get("/")
def root():
response = RedirectResponse(url="/docs")
return response
@app.post("/uploadfile/")
async def uploadfile(image: UploadFile = File(...)):
try:
if not os.path.exists("images"):
os.makedirs("images")
except Exception as e:
print(e)
suffix_arr = image.filename.split(".")
suffix = suffix_arr[len(suffix_arr) - 1]
file_name = os.getcwd() "/images/" str(uuid.uuid1()) "." suffix
with open(file_name, "wb ") as f:
f.write(image.file.read())
f.close()
image = face_recognition.load_image_file(file_name)
face_locations = face_recognition.face_locations(image)
if len(face_locations) > 0:
return {"code": 0, "obj": face_locations}
else:
return {"code": 1, "obj": face_locations}
if __name__ == "__main__":
uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True, debug=True)
WEB获取摄像头做识别
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div class="imgouter">
<div class="left_div"><video id="v"></video></div>
<canvas id="canvas" style="display:none;"></canvas>
<img id="photo" alt="photo" class="right_div">
</div>
<div class="msg"></div>
</body>
<style>
body {
margin: 0;
padding: 0;
}
.imgouter {
display: flex;
height: 90vh;
width: 100vw;
}
.left_div,
.right_div {
width: 0;
flex: 1;
}
#v {
width: 100%;
height: 100%;
object-fit: fill;
}
.msg {
display: flex;
align-items: center;
justify-content: center;
height: 10vh;
font-size: 30px;
}
</style>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function upload_img (imgstr) {
let arr = imgstr.split(";base64,");
let suffix = arr[0].split("/")[1];
let base64str = arr[1];
let para = {
image: base64str,
suffix: suffix
};
axios
.post('/base64file', para)
.then(function (response) {
let data = response.data;
if (data.code === 0) {
document.querySelector(".msg").innerHTML = "发现人像:" data.obj.length;
} else {
document.querySelector(".msg").innerHTML = "未发现人像";
}
})
.catch(function (error) {
console.log(error);
});
}
!(function () {
// 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先,如果有getUserMedia的话,就获得它
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
// 否则,为老的navigator.getUserMedia方法包裹一个Promise
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
}
}
const constraints = {
video: true,
audio: false
};
let videoPlaying = false;
let v = document.getElementById('v');
let promise = navigator.mediaDevices.getUserMedia(constraints);
promise.then(stream => {
// 旧的浏览器可能没有srcObject
if ("srcObject" in v) {
v.srcObject = stream;
} else {
// 防止在新的浏览器里使用它,应为它已经不再支持了
v.src = window.URL.createObjectURL(stream);
}
v.onloadedmetadata = function (e) {
v.play();
videoPlaying = true;
take_pic();
setInterval(() => {
take_pic();
}, 3000);
};
}).catch(err => {
console.error(err.name ": " err.message);
});
function take_pic () {
if (videoPlaying) {
let canvas = document.getElementById('canvas');
canvas.width = v.videoWidth;
canvas.height = v.videoHeight;
canvas.getContext('2d').drawImage(v, 0, 0);
let data = canvas.toDataURL("image/jpeg", 0.8);
//console.info(data);
upload_img(data);
document.getElementById('photo').setAttribute('src', data);
}
}
})();
</script>
</html>
web端只能传base64,后端也要处理base64
代码语言:javascript复制import base64
import uuid
import os
from fastapi import Body
@app.post("/base64file")
async def uploadfile(image=Body(None), suffix=Body(None)):
imgdata = base64.b64decode(image)
file_name = os.getcwd() "/images/" str(uuid.uuid1()) "." suffix
file = open(file_name, 'wb')
file.write(imgdata)
file.close()
try:
image = face_recognition.load_image_file(file_name)
face_locations = face_recognition.face_locations(image)
if os.path.exists(file_name):
os.remove(file_name)
if len(face_locations) > 0:
return {"code": 0, "obj": face_locations}
else:
return {"code": 1, "obj": face_locations}
except Exception as e:
return {"code": 1, "obj": [], "msg": str(e)}