mirror of
https://github.com/Yuukiy/JavSP.git
synced 2026-10-28 21:52:43 +08:00
旋转图片检测到人脸后计算旋转前的图片的人脸中心点
This commit is contained in:
+51
-22
@@ -1,12 +1,13 @@
|
||||
"""使用Open CV识别图像"""
|
||||
import os
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import sys
|
||||
import math
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
from core.datatype import mei_path
|
||||
|
||||
face_cascade = cv2.CascadeClassifier(mei_path('data/haarcascade_frontalface_default.xml'))
|
||||
face_cascade = cv.CascadeClassifier(mei_path('data/haarcascade_frontalface_default.xml'))
|
||||
|
||||
|
||||
# https://github.com/PyImageSearch/imutils/blob/master/imutils/convenience.py#L41
|
||||
@@ -17,7 +18,7 @@ def rotate_bound(image, angle):
|
||||
|
||||
# grab the rotation matrix (applying the negative of the angle to rotate clockwise),
|
||||
# then grab the sine and cosine (i.e., the rotation components of the matrix)
|
||||
M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
|
||||
M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
|
||||
cosine = abs(M[0, 0])
|
||||
sine = abs(M[0, 1])
|
||||
|
||||
@@ -30,7 +31,7 @@ def rotate_bound(image, angle):
|
||||
M[1, 2] += (nH / 2) - cY
|
||||
|
||||
# perform the actual rotation and return the image
|
||||
return cv2.warpAffine(image, M, (nW, nH))
|
||||
return cv.warpAffine(image, M, (nW, nH))
|
||||
|
||||
|
||||
def isValidArea(area):
|
||||
@@ -43,40 +44,68 @@ def isValidArea(area):
|
||||
return False
|
||||
|
||||
|
||||
def calc_origin_area(img, area, rotate, ori_size):
|
||||
"""计算图片中指定区域的中心点在旋转前的位置"""
|
||||
# 计算area的中心点以图片中心点为坐标原点的新坐标
|
||||
(h, w) = img.shape[:2]
|
||||
Ox, Oy = (h//2, w//2)
|
||||
new_x = area[0] + area[2]//2 - Ox
|
||||
new_y = area[1] + area[3]//2 - Oy
|
||||
# 计算area的中心点做反向旋转后的坐标
|
||||
anti_rotate = math.radians(-rotate)
|
||||
anti_x = new_x * math.cos(anti_rotate) - new_y * math.sin(anti_rotate)
|
||||
anti_y = new_x * math.sin(anti_rotate) + new_y * math.cos(anti_rotate)
|
||||
# 计算area的中心点在原图坐标系中的坐标
|
||||
(ori_h, ori_w) = ori_size
|
||||
origin_x = int(ori_w // 2 + anti_x)
|
||||
origin_y = int(ori_h // 2 + anti_y)
|
||||
return (origin_x, origin_y)
|
||||
|
||||
|
||||
def detect_faces(img_path, debug=False):
|
||||
img = cv2.imread(img_path)
|
||||
faces = []
|
||||
"""检测图片中的人脸并返回第一个有效的人脸区域"""
|
||||
img = cv.imread(img_path)
|
||||
# OpenCV的检测效果似乎受图像角度影响很大,因此要尝试旋转图片
|
||||
rotate_angles = (0, 10, -10, 20, -20, 30, -30, 40, -40, 50, -50, 60, -60)
|
||||
for angle in rotate_angles:
|
||||
rotated = rotate_bound(img, angle)
|
||||
grey = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
|
||||
grey = cv.cvtColor(rotated, cv.COLOR_BGR2GRAY)
|
||||
faces = face_cascade.detectMultiScale(grey, 1.1, 4)
|
||||
for area in faces:
|
||||
if isValidArea(area) and (not debug):
|
||||
return area
|
||||
ori_pos = calc_origin_area(rotated, area, angle, img.shape[:2])
|
||||
return ori_pos
|
||||
# 有效区域用绿框标记,无效区域用红框标记
|
||||
color = (0, 255, 0) if isValidArea(area) else (0, 0, 255)
|
||||
(x, y, w, h) = area
|
||||
cv2.rectangle(rotated, (x, y), (x+w, y+h), color, 2)
|
||||
cv.rectangle(rotated, (x, y), (x+w, y+h), color, 2)
|
||||
recog_info = f'({x},{y}), {w}x{h}'
|
||||
(h2, w2) = rotated.shape[:2]
|
||||
pos = (min(w2-170, x), max(y-10, 12)) # 避免信息显示到绘图区外
|
||||
cv2.putText(rotated, recog_info, pos, cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)
|
||||
cv.putText(rotated, recog_info, pos, cv.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)
|
||||
if debug:
|
||||
win_name = "Actress detection"
|
||||
cv2.imshow(win_name, rotated)
|
||||
cv2.setWindowTitle(win_name, win_name + f" with ratotion {angle} degrees")
|
||||
cv2.waitKey(0)
|
||||
return faces
|
||||
cv.imshow(win_name, rotated)
|
||||
cv.setWindowTitle(win_name, win_name + f" with ratotion {angle} degrees")
|
||||
cv.waitKey(0)
|
||||
|
||||
|
||||
def crop_by_face(img_path, debug=False):
|
||||
"""根据指定的人脸区域裁剪图片"""
|
||||
face_center = detect_faces(img_path)
|
||||
if debug:
|
||||
if not os.path.exists('debug'):
|
||||
os.mkdir('debug')
|
||||
img = cv.imread(img_path)
|
||||
cv.circle(img, face_center, 100, (0,255,0), 1)
|
||||
filepath, ext = os.path.splitext(img_path)
|
||||
output = 'debug/' + filepath + '_opencv' + ext
|
||||
cv.imwrite(output, img)
|
||||
return face_center
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
# construct the argument parse and parse the arguments
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("-i", "--image", required=True,
|
||||
help="path to the image file")
|
||||
args = vars(ap.parse_args(['-i', 'YPPx.jpg']))
|
||||
|
||||
detect_faces(args['image'], True)
|
||||
if len(sys.argv) < 2:
|
||||
sys.argv.append('siro-4701.jpg')
|
||||
for img_path in sys.argv[1:]:
|
||||
crop_by_face(img_path, True)
|
||||
|
||||
Reference in New Issue
Block a user