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
都是移动支付,银联推出的云闪付,为什么不敌微信支付宝?作为当前深入大家生活中的移动支付,手机打开轻轻一扫完成支付,方便快捷的支付手段,已经成为了一种习惯。而作为当前的两大移动支付主流方式,微信和支付宝两者之间的竞争也是没少被提及。正如
爬虫闲谈数据处理个人公众号yk坤帝获取更多学习资料之前我们讨论了一下请求和响应,接下来几天我们都会讨论对数据的处理。接触了爬虫这个领域,大家肯定都听过正则表达式的鼎鼎大名,不过今天我们暂时不谈正则
芯片是大国的象征人民日报评我国芯片发展芯片的重要性有目共睹了。没有了他,就连华为这样的巨头都寸步难行中兴跪地求饶中小企业寒蝉鸣泣消费者满脸愁容电子消费类全部涨价国家的工业系统差点崩溃。有了他,才能
苹果发布折叠屏手机?网友制作新机概念图,有安卓那味了近几年,三星和华为等手机大厂都推出了折叠屏手机,但是却唯独没有苹果的身影。所以,当下有不少网友也在呼吁苹果推出折叠屏手机。近日,有人制作了iPhoneFlip概念图,同时还在图中标
小米自研超级拟人技术,雷军喊出了180000米粉的名字IT之家8月14日消息在小米手机十周年之际,小米将3。7亿元返还给小米手机1首批用户,每人赠送1999元无门槛红包。据小米公司公众号消息,雷军还为初代小米手机用户录了一段话,而实际
5000元预算只能买来网游本?大人,时代变了网上流传着一句话叫五千预算进某吧,加钱加到一万八。通常我们在买大件产品之前,都会听信很多朋友的意见,导致最后没拿住自己的主意,不仅钱包被掏空,还买来一个性能过剩的产品。其实要避免这
全球电视市场增速放缓,OLED和MiniLED却会迎来逆势增长自新冠疫情爆发以来,宅经济带动了电视市场连续四个季度的高速增长。但如今,宅经济的影响逐渐减弱,电视市场的需求也逐渐减少。据数据机构统计,今年上半年,全球电视市场出货数量规模为1。0
HIFI初烧实惠套装Hifi包括1。音源。一般cd盘和无损歌曲例如ape,flac格式即可满足。2。线材。尽量买短的,用料好的。注意阻抗75欧。3。转盘。包含cd转盘和数字转盘。一般来说同价位cd音质
真无线蓝牙耳机探底,百元带显示屏!体验aigoT23随着蓝牙优势凸显,以及手机厂商取消3。5mm耳机孔的设计,身边越来越多的人戴上了蓝牙耳机。只是市场上的无线耳机品类繁多,看得人眼花缭乱,中高端产品数百上千元,入门几十上百元,而且这
郡旗智能指纹锁Q1,您的贴心卫士随着人工智能技术的快速发展和人们对门锁需求的日趋改变,智能门锁在国内有了相对较高的普及率,伴随着消费经济的逐步增长,越来越多的消费者追求智能门锁的智能化设计。作为智能门锁高端品牌,
千元党手机真香警告!荣耀Play5TPro超清影像大内存还有快充在大众的固有印象中,千元档手机因为受成本限制,配置和品质都略显短板,在用户眼中略显局促。但其实随着如今手机市场的细分,不乏一些出实力色的千元国产手机蓬勃涌现。就比如这款荣耀Play