Python项目实战OpenCV计算机视觉在Web端的部署(二)
本节中将使用 Python Web 框架创建并部署一个完整的 Web 人脸检测应用程序,此程序不仅可以处理本地图片(利用 request.files["image"]),同时也可以用于处理来自网络中的图片(利用 request.args.get("url"))。
1.1 解析请求并构建响应
在此实战中,我们将看到如何使用 OpenCV 和 Flask 创建一个 Web 人脸检测 API,我们将项目命名为 face_detection,项目目录结构如下所示:face_detection |——server | face_detection.py | face_processing.py client request_test.py request_and_draw_rectangle.py test_example.png
其中 face_detection.py 脚本负责解析请求并构建对客户端的响应:# face_detection.py # 导入所需包 from flask import Flask, request, jsonify import urllib.request from face_processing import FaceProcessing app = Flask(__name__) fc = FaceProcessing() @app.errorhandler(400) def bad_request(e): # 返回代码错误 return jsonify({"status": "Not ok", "message": "This server could not understand your request"}), 400 @app.errorhandler(404) def not_found(e): # 返回代码错误 return jsonify({"status": "Not found", "message": "Route not found"}), 404 @app.errorhandler(500) def internal_error(e): # 返回代码错误 return jsonify({"status": "Internal Error", "message": "Internal error occurred in server"}), 500 @app.route("/detect", methods=["GET", "POST", "PUT"]) def detect_human_faces(): if request.method == "GET": if request.args.get("url"): with urllib.request.urlopen(request.args.get("url")) as url: return jsonify({"status": "Ok", "result": fc.face_detection(url.read())}), 200 else: return jsonify({"status": "Bad request", "message": "Parameter url is not present"}), 400 elif request.method == "POST": if request.files.get("image"): return jsonify({"status": "Ok", "result": fc.face_detection(request.files["image"].read())}), 200 else: return jsonify({"status": "Bad request", "message": "Parameter image is not present"}), 400 else: return jsonify({"status": "Failure", "message": "PUT method not supported for API"}), 405 if __name__ == "__main__": app.run(host="0.0.0.0")
如上所示,使用 jsonify() 函数来创建给定参数的 JSON 表示,以返回 application/json MIME 类型。 JSON 是信息交换的事实标准,此项目将返回 JSON 响应,在项目的最后我们将了解如何对其进行修改以返回图像,此 Web 人脸检测 API 支持 GET 和 POST 请求;此外,在 face_detection 脚本中,我们还通过使用 errorhandler() 装饰函数来注册错误处理程序,用来响应出错时向客户端返回设置的错误代码。
人脸检测程序与负责响应的程序进行了分离,人脸检测程序在 face_processing.py 脚本中执行,其中编写了 FaceProcessing() 类:# face_processing.py import cv2 import numpy as np import os class FaceProcessing(object): def __init__(self): self.file = os.path.join(os.path.join(os.path.dirname(__file__), "data"), "haarcascade_frontalface_alt.xml") self.face_cascade = cv2.CascadeClassifier(self.file) def face_detection(self, image): # 将图像转换为 OpenCV 格式 image_array = np.asarray(bytearray(image), dtype=np.uint8) img_opencv = cv2.imdecode(image_array, -1) output = [] # 检测人脸并构建返回值 gray = cv2.cvtColor(img_opencv, cv2.COLOR_BGR2GRAY) faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(25, 25)) for face in faces: # 返回检测框坐标 x, y, w, h = face.tolist() face = {"box": [x, y, x + w, y + h]} output.append(face) print(face) # 返回结果 return output
face_detection() 方法使用 OpenCV 的 detectMultiScale() 函数执行人脸检测,获得每个检测到的人脸的坐标 (x, y, w, h),并通过合适的格式对检测结果进行编码来构建返回检测框:face = {"box": [x, y, x + w, y + h]}
最后,我们将编码完成的人脸检测框添加到 output 数组中,将所有检测到的人脸检测框都添加到 output 数组后,将其返回:output.append(face)1.2 构建请求进行测试
为了使用 Web 人脸检测 API,我们可以从浏览器执行 GET 请求;同时,此 API 还支持 POST 请求。接下来,我们构建测试脚本测试此 API ,此脚本可以执行 GET 和 POST 请求,以了解如何与人脸 API 进行交互,更具体的讲,测试脚本将对人脸 API 发送多个请求,以获得不同的响应,并查看错误处理的工作原理。
首先使用不正确的 URL 执行 GET 请求:# request_test.py import requests FACE_DETECTION_REST_API_URL = "http://localhost:5000/detect" FACE_DETECTION_REST_API_URL_WRONG = "http://localhost:5000/process" IMAGE_PATH = "test_example.png" URL_IMAGE = "https://imgs.mmkk.me/wmnv/img/20190625073459-5d11cea35c407.png" # 提交 GET 请求 r = requests.get(FACE_DETECTION_REST_API_URL_WRONG) # 查看响应 print("status code: {}".format(r.status_code)) print("headers: {}".format(r.headers)) print("content: {}".format(r.json()))
打印响应信息,可以看到:status code: 404 headers: {"Content-Type": "application/json", "Content-Length": "51", "Server": "Werkzeug/1.0.1 Python/3.7.7", "Date": "Sat, 02 Oct 2021 01:45:19 GMT"} content: {"message": "Route not found", "status": "Not found"}
状态码 404 表示客户端可以与服务器通信,但服务器找不到请求的内容。这是因为请求的 URL (http://localhost:5000/process) 不正确。
执行的第二个请求是正确的 GET 请求:# 提交 GET 请求 payload = {"url": URL_IMAGE} r = requests.get(FACE_DETECTION_REST_API_URL, params=payload) # 查看响应 print("status code: {}".format(r.status_code)) print("headers: {}".format(r.headers)) print("content: {}".format(r.json()))
打印响应信息,可以看到:status code: 200 headers: {"Content-Type": "application/json", "Content-Length": "52", "Server": "Werkzeug/1.0.1 Python/3.7.7", "Date": "Sat, 02 Oct 2021 01:54:31 GMT"} content: {"result": [{"box": [233, 77, 356, 252]}], "status": "Ok"}
状态码 200 表示请求已成功执行,还可以看到已检测到与人脸相对应的检测框坐标。
接下来执行缺少有效负载的 GET 请求:# 提交 GET 请求 r = requests.get(FACE_DETECTION_REST_API_URL) # 查看响应 print("status code: {}".format(r.status_code)) print("headers: {}".format(r.headers)) print("content: {}".format(r.json()))
打印响应信息,可以看到:status code: 400 headers: {"Content-Type": "application/json", "Content-Length": "66", "Server": "Werkzeug/1.0.1 Python/3.7.7", "Date": "Sat, 02 Oct 2021 01:58:00 GMT"} content: {"message": "Parameter url is not present", "status": "Bad request"}
状态代码 400 表示错误请求,这是由于其缺少 url 参数。
接下来执行的第四个请求是具有正确负载的 POST 请求:# 加载图像并构建有效负载 image = open(IMAGE_PATH, "rb").read() payload = {"image": image} # 提交 POST 请求 r = requests.post(FACE_DETECTION_REST_API_URL, files=payload) # 查看响应 print("status code: {}".format(r.status_code)) print("headers: {}".format(r.headers)) print("content: {}".format(r.json()))
打印响应信息,可以看到:status code: 200 headers: {"Content-Type": "application/json", "Content-Length": "52", "Server": "Werkzeug/1.0.1 Python/3.7.7", "Date": "Sat, 02 Oct 2021 02:03:26 GMT"} content: {"result": [{"box": [193, 92, 355, 292]}], "status": "Ok"}
最后我们构造 PUT 请求:# 提交 PUT 请求 r = requests.put(FACE_DETECTION_REST_API_URL, files=payload) # 查看响应 print("status code: {}".format(r.status_code)) print("headers: {}".format(r.headers)) print("content: {}".format(r.json()))
打印响应信息,可以看到:status code: 405 headers: {"Content-Type": "application/json", "Content-Length": "66", "Server": "Werkzeug/1.0.1 Python/3.7.7", "Date": "Sat, 02 Oct 2021 02:05:54 GMT"} content: {"message": "PUT method not supported for API", "status": "Failure"}
这是由于我们的 API 不支持 PUT 方法,仅支持 GET 和 POST 方法,因此返回状态码 405。2. 根据获得的响应信息在客户端绘制检测框
当请求成功执行时,将检测到的人脸作为 JSON 数据返回,接下来我们将编写程序了解如何解析响应并绘制检测到的人脸:# request_and_draw_rectangle.py import cv2 import numpy as np import requests from matplotlib import pyplot as plt def show_img_with_matplotlib(color_img, title, pos): img_RGB = color_img[:, :, ::-1] ax = plt.subplot(1, 1, pos) plt.imshow(img_RGB) plt.title(title, fontsize=10) plt.axis("off") FACE_DETECTION_REST_API_URL = "http://localhost:5000/detect" IMAGE_PATH = "test_example.png" # 加载图像构造有效负载 image = open(IMAGE_PATH, "rb").read() payload = {"image": image} r = requests.post(FACE_DETECTION_REST_API_URL, files=payload) # 打印响应信息 print("status code: {}".format(r.status_code)) print("headers: {}".format(r.headers)) print("content: {}".format(r.json())) # 解析响应信息 json_data = r.json() result = json_data["result"] image_array = np.asarray(bytearray(image), dtype=np.uint8) img_opencv = cv2.imdecode(image_array, -1) # 绘制检测框 for face in result: left, top, right, bottom = face["box"] cv2.rectangle(img_opencv, (left, top), (right, bottom), (0, 255, 255), 2) cv2.circle(img_opencv, (left, top), 5, (0, 0, 255), -1) cv2.circle(img_opencv, (right, bottom), 5, (255, 0, 0), -1) # 可视化 fig = plt.figure(figsize=(8, 6)) plt.suptitle("Using face API", fontsize=14, fontweight="bold") show_img_with_matplotlib(img_opencv, "face detection", 1) plt.show()
在上示代码中,首先加载图像并构建有效负载,然后,执行 POST 请求,从响应中获取 JSON 数据并进行解析:# 解析响应信息 json_data = r.json() result = json_data["result"]
接下来,就可以利用返回的信息绘制检测到的人脸:# 绘制检测框 for face in result: left, top, right, bottom = face["box"] cv2.rectangle(img_opencv, (left, top), (right, bottom), (0, 255, 255), 2) cv2.circle(img_opencv, (left, top), 5, (0, 0, 255), -1) cv2.circle(img_opencv, (right, bottom), 5, (255, 0, 0), -1)
对于每个检测到的人脸,绘制矩形检测框以及左上角和右下角的点:
3. 在服务器端绘制检测框并返回
我们也可以直接在服务器端在图像中绘制检测框,然后将结果图像返回(相关讲解可以在《OpenCV计算机视觉项目在Web端的部署》中查看),我们需要做的仅仅是修改 face_detection.py,这就是代码分离的优势之一:# 这里仅修改 GET 请求,对于 POST 的修改也是类似的,可以自行探索 @app.route("/detect", methods=["GET", "POST", "PUT"]) def detect_human_faces(): if request.method == "GET": if request.args.get("url"): with urllib.request.urlopen(request.args.get("url")) as url: image = url.read() result = fc.face_detection(image) image_array = np.asarray(bytearray(image), dtype=np.uint8) img_opencv = cv2.imdecode(image_array, -1) for face in result: left, top, right, bottom = face["box"] cv2.rectangle(img_opencv, (left, top), (right, bottom), (0, 255, 255), 2) cv2.circle(img_opencv, (left, top), 5, (0, 0, 255), -1) cv2.circle(img_opencv, (right, bottom), 5, (255, 0, 0), -1) retval, buffer = cv2.imencode(".jpg", img_opencv) response = make_response(buffer.tobytes()) response.headers["Content-Type"] = "image" return response else: return jsonify({"status": "Bad request", "message": "Parameter url is not present"}), 400 elif request.method == "POST": if request.files.get("image"): return jsonify({"status": "Ok", "result": fc.face_detection(request.files["image"].read())}), 200 else: return jsonify({"status": "Bad request", "message": "Parameter image is not present"}), 400 else: return jsonify({"status": "Failure", "message": "PUT method not supported for API"}), 405
修改之后,我们就可以通过 GET 请求来查看程序效果:http://10.140.12.255:5000/detect?url=https://imgs.mmkk.me/wmnv/img/20190625073459-5d11cea35c407.png
小结
在本文中,我们使用 Python Web 框架创建并部署了一个完整的 Web 人脸检测应用程序,同时在项目中我们处理了来自浏览器的不同请求方式(例如 GET 和 POST 等),并通过实战使用 OpenCV 和 Flask 创建 Web 人脸检测 API,同时我们还使用了两种不同类型的响应结果提供不同的请求结果。
作者:盼小辉
原文链接:https://blog.csdn.net/LOVEmy134611/article/details/123203311
游客数大降!泰国大象失业了泰国东北部素林府班达格朗村被称为大象村,是泰国大象旅游产业的中心。然而新冠疫情下,泰国旅游业复苏缓慢,养象人和他们的大象都失业在家,生存成了问题。今年23岁的班达格朗村村民西里蓬通
性能至上的一加AcePro,浓浓的性价比味道自从一加开始继承了OPPO的Ace系列后,相继推出两款主打性能的一加Ace以及一加Ace竞速版,本以为Ace系列产品就此打住。没想到,这一次全方位升级表现更强的一加AcePro来了
夏天,烧烤摊必点的5道烧烤,学会后在家就能做,花钱少吃得好你喜欢夏天吗?当你夜晚看到路边烧烤摊生意火爆的时候,这就意味着真正的夏天到来了!除了烧烤,夏季里还有我最爱吃的小龙虾。如果你不愿意出门,那我今天就和你分享在家如何做烧烤,每种风味都
饭店的醋溜白菜为啥好吃,教你正确做法,色香味俱全,比吃肉过瘾饭店的醋溜白菜为啥好吃,教你正确做法,色香味俱全,比吃肉过瘾。百菜不如白菜,白菜是一种营养极其丰富的大众化蔬菜,它含有丰富的维生素膳食纤维和抗氧化物质,能促进肠道蠕动,帮助消化。白
它是补钙高手,钙是牛奶4倍,钾是香蕉10倍,营养高味道好大家好,这里是华家美食记!人上了年纪之后,身体的钙质就开始加速流失,补钙除了吃了吃钙片喝牛奶以外,还有非常多的天然食物可以帮到我们,今天华姐给大家介绍一种叶子,它是天然的补钙高手,
北京欢乐谷国潮街头艺术节来了!景区内中秋元素亮了北京日报客户端记者潘福达程功9月10日下午,北京欢乐谷宣布2022国潮街头艺术节启幕,作为2022华侨城文化旅游节的系列活动,本届主题节庆以中秋佳节为起点,活动周期长达28天,持续
黑马突围,为什么是安徽和陕西?每经记者淡忠奎每经编辑刘艳美图片来源摄图网501153221进入2022年,中国新能源汽车产业一路高歌猛进。根据中汽协公布的最新数据,18月,国内新能源汽车产销分别为397万辆和3
大虾别再煮着吃了这样做真简单,口感弹牙味道鲜,中秋家宴少不了大虾别再煮着吃了,这样做真简单,口感弹牙味道鲜,中秋家宴少不了秋后的这个季节,是海鲜上市的季节,各种海鲜数不胜数,例如大虾,螃蟹,皮皮虾,鲅鱼等等。秋后吃海鲜也成了很多人大饱口福的
无糖月饼,能否放开吃?中秋佳节到了,万家团圆少不了月饼。近年来,无糖月饼成为了最新网红,它自称没有糖,不会升高血糖,是老人血糖偏高以及糖尿病友人(以下简称糖友)的福音,并以健康养生自居。随之而来的是,很
中秋小长假民俗文化旅游潮起来来源ICPhoto2022年9月11日报道,2022中秋小长假,本地游近郊游唱主角,民俗文化旅游潮起来。2022年9月11日报道,2022中秋小长假,本地游近郊游唱主角,民俗文化旅
浙江嘉兴秀水泱泱圆梦之洲,绽放江南文化魅力夏季傍晚,漫步长虹公园,登长虹桥远眺,放松身心,享受当下。长虹桥,位于嘉兴市秀洲区,是京杭大运河上罕见的巨型三孔实腹石拱大桥,也是秀洲乃至嘉兴唯一进入联合国教科文组织世界遗产名录的