OpenCV-Python實戰(21)——OpenCV人臉檢測專案在Web端的部署
- 0. 前言
- 1. OpenCV 人臉檢測專案在 Web 端的部署
- 1.1 決議請求并構建回應
- 1.2 構建請求進行測驗
- 2. 根據獲得的回應資訊在客戶端繪制檢測框
- 3. 在服務器端繪制檢測框并回傳
- 小結
- 系列鏈接
0. 前言
將 OpenCV 計算機視覺專案部署在 Web 端一個有趣的話題,部署在 Web 端的優勢之一是不需要安裝任何應用,只需要訪問地址就可以訪問應用,在本文中,我們使用 Python Web 框架創建并部署一個完整的 Web 人臉檢測應用程式,在專案中我們將學習到如何處理來自瀏覽器的不同請求方式(例如 GET 和 POST 等),以及如何實戰使用 OpenCV 和 Flask 創建 Web 人臉檢測 API,
1. 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,同時我們還使用了兩種不同型別的回應結果提供不同的請求結果,
系列鏈接
OpenCV-Python實戰(1)——OpenCV簡介與影像處理基礎
OpenCV-Python實戰(2)——影像與視頻檔案的處理
OpenCV-Python實戰(3)——OpenCV中繪制圖形與文本
OpenCV-Python實戰(4)——OpenCV常見影像處理技術
OpenCV-Python實戰(5)——OpenCV影像運算
OpenCV-Python實戰(6)——OpenCV中的色彩空間和色彩映射
OpenCV-Python實戰(7)——直方圖詳解
OpenCV-Python實戰(8)——直方圖均衡化
OpenCV-Python實戰(9)——OpenCV用于影像分割的閾值技術
OpenCV-Python實戰(10)——OpenCV輪廓檢測
OpenCV-Python實戰(11)——OpenCV輪廓檢測相關應用
OpenCV-Python實戰(12)——一文詳解AR增強現實
OpenCV-Python實戰(13)——OpenCV與機器學習的碰撞
OpenCV-Python實戰(14)——人臉檢測詳解
OpenCV-Python實戰(15)——面部特征點檢測詳解
OpenCV-Python實戰(16)——人臉追蹤詳解
OpenCV-Python實戰(17)——人臉識別詳解
OpenCV-Python實戰(18)——深度學習簡介與入門示例
OpenCV-Python實戰(19)——OpenCV與深度學習的碰撞
OpenCV-Python實戰(20)——OpenCV計算機視覺專案在Web端的部署
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/435448.html
標籤:AI
上一篇:安裝PyTorch后jupyter notebook中仍出現“No module named torch“
下一篇:Java環境JDK安裝
