221 lines
7.5 KiB
Python
221 lines
7.5 KiB
Python
import cv2
|
||
import numpy as np
|
||
import onnxruntime as ort
|
||
|
||
|
||
class QualityOfClarity:
|
||
def __init__(self, low_thresh=0.10, high_thresh=0.20):
|
||
self.low_thresh = low_thresh
|
||
self.high_thresh = high_thresh
|
||
|
||
def reblur(self, data, width, height):
|
||
data = np.array(data, dtype=np.float32).reshape((height, width))
|
||
|
||
# 创建一维核
|
||
kernel = np.ones((9,), np.float32) / 9.0
|
||
|
||
# 垂直方向模糊处理
|
||
BVer = cv2.filter2D(data, -1, kernel.reshape(-1, 1), borderType=cv2.BORDER_REPLICATE)
|
||
|
||
# 水平方向模糊处理
|
||
BHor = cv2.filter2D(data, -1, kernel.reshape(1, -1), borderType=cv2.BORDER_REPLICATE)
|
||
|
||
s_FVer, s_FHor, s_Vver, s_VHor = 0.0, 0.0, 0.0, 0.0
|
||
|
||
# 计算垂直方向的差分
|
||
D_Fver = np.abs(data[1:, :] - data[:-1, :])
|
||
D_BVer = np.abs(BVer[1:, :] - BVer[:-1, :])
|
||
|
||
# 计算垂直方向的累积
|
||
s_FVer = np.sum(D_Fver)
|
||
s_Vver = np.sum(np.maximum(0.0, D_Fver - D_BVer))
|
||
|
||
# 计算水平方向的差分
|
||
D_FHor = np.abs(data[:, 1:] - data[:, :-1])
|
||
D_BHor = np.abs(BHor[:, 1:] - BHor[:, :-1])
|
||
|
||
# 计算水平方向的累积
|
||
s_FHor = np.sum(D_FHor)
|
||
s_VHor = np.sum(np.maximum(0.0, D_FHor - D_BHor))
|
||
|
||
|
||
b_FVer = (s_FVer - s_Vver) / s_FVer
|
||
b_FHor = (s_FHor - s_VHor) / s_FHor
|
||
blur_val = max(b_FVer, b_FHor)
|
||
|
||
return blur_val
|
||
|
||
def grid_max_reblur(self, img, rows, cols):
|
||
height, width = img.shape
|
||
row_height = height // rows
|
||
col_width = width // cols
|
||
blur_val = float('-inf')
|
||
|
||
for y in range(rows):
|
||
for x in range(cols):
|
||
grid = img[y * row_height: (y + 1) * row_height, x * col_width: (x + 1) * col_width]
|
||
this_grad_blur_val = self.reblur(grid, col_width, row_height)
|
||
if this_grad_blur_val > blur_val:
|
||
blur_val = this_grad_blur_val
|
||
|
||
return max(blur_val, 0.0)
|
||
|
||
def clarity_estimate(self, image):
|
||
# x, y, w, h = rect
|
||
# if w < 9 or h < 9:
|
||
# return 0.0
|
||
|
||
src_data = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||
# src_data = gray_data[y:y+h, x:x+w]
|
||
blur_val = self.grid_max_reblur(src_data, 2, 2)
|
||
clarity = 1.0 - blur_val
|
||
|
||
T1, T2 = 0.0, 1.0
|
||
if clarity <= T1:
|
||
clarity = 0.0
|
||
elif clarity >= T2:
|
||
clarity = 1.0
|
||
else:
|
||
clarity = (clarity - T1) / (T2 - T1)
|
||
|
||
return clarity
|
||
|
||
def check(self, image):
|
||
clarity = self.clarity_estimate(image)
|
||
if clarity < self.low_thresh:
|
||
level = "LOW"
|
||
elif self.low_thresh <= clarity < self.high_thresh:
|
||
level = "MEDIUM"
|
||
else:
|
||
level = "HIGH"
|
||
return level != 'LOW'
|
||
# return {'level': level, "score": clarity}
|
||
|
||
|
||
class QualityChecker: # check resolution and clarity of image
|
||
def __init__(self, v0=70.0, v1=100.0, v2=210.0, v3=230.0, hw = (112,112)):
|
||
self.bright_thresh0 = v0
|
||
self.bright_thresh1 = v1
|
||
self.bright_thresh2 = v2
|
||
self.bright_thresh3 = v3
|
||
self.middle_thresh = (self.bright_thresh1 + self.bright_thresh2) / 2
|
||
self.rolu_thrds = hw # (h,w)
|
||
|
||
def get_bright_score(self, bright):
|
||
bright_score = 1.0 / (abs(bright - self.middle_thresh) + 1)
|
||
return bright_score
|
||
|
||
def grid_max_bright(self, img, rows, cols):
|
||
row_height = img.shape[0] // rows
|
||
col_width = img.shape[1] // cols
|
||
|
||
# 使用列表生成式获取所有网格的平均亮度
|
||
grid_means = [
|
||
np.mean(img[y * row_height:(y + 1) * row_height, x * col_width:(x + 1) * col_width])
|
||
for y in range(rows)
|
||
for x in range(cols)
|
||
]
|
||
|
||
# 获取最大亮度值
|
||
bright_val = max(grid_means)
|
||
return max(bright_val, 0)
|
||
|
||
def check_bright(self, face_image):
|
||
gray = cv2.cvtColor(face_image, cv2.COLOR_BGR2GRAY) if len(face_image.shape) == 3 else face_image
|
||
bright_value = self.grid_max_bright(gray, 3, 3)
|
||
|
||
if bright_value < self.bright_thresh0 or bright_value > self.bright_thresh3:
|
||
level = "LOW"
|
||
elif (self.bright_thresh0 <= bright_value < self.bright_thresh1) or (self.bright_thresh2 < bright_value <= self.bright_thresh3):
|
||
level = "MEDIUM"
|
||
else:
|
||
level = "HIGH"
|
||
|
||
return level == "HIGH"
|
||
|
||
def check_resolution(self, face_image):
|
||
H, W = face_image.shape[:2]
|
||
if H < self.rolu_thrds[0] or W < self.rolu_thrds[1]:
|
||
return False
|
||
return True
|
||
|
||
|
||
class QualityOfPose:
|
||
def __init__(self, pad=0.3, yaw_thrd=30, pitch_thrd=25, var_onnx_path = './checkpoints/fsanet-var.onnx', conv_onnx_path='./checkpoints/fsanet-conv.onnx') -> None:
|
||
self.pad = pad
|
||
self.input_width = 64
|
||
self.input_height = 64
|
||
self.yaw_thrd = abs(yaw_thrd)
|
||
self.pitch_thrd = abs(pitch_thrd)
|
||
self.var_fsanet = ort.InferenceSession(var_onnx_path)
|
||
self.conv_fsanet = ort.InferenceSession(conv_onnx_path)
|
||
|
||
self.var_input_names = [input_.name for input_ in self.var_fsanet.get_inputs()]
|
||
self.var_output_names = [output.name for output in self.var_fsanet.get_outputs()]
|
||
|
||
self.conv_input_names = [input_.name for input_ in self.conv_fsanet.get_inputs()]
|
||
self.conv_output_names = [output.name for output in self.conv_fsanet.get_outputs()]
|
||
|
||
def transform(self, mat):
|
||
h, w = mat.shape[:2]
|
||
nh = int(h + self.pad * h)
|
||
nw = int(w + self.pad * w)
|
||
nx1 = max(0, (nw - w) // 2)
|
||
ny1 = max(0, (nh - h) // 2)
|
||
|
||
# Create a padded canvas and copy the image into the center
|
||
canvas = np.zeros((nh, nw, 3), dtype=np.uint8)
|
||
canvas[ny1:ny1 + h, nx1:nx1 + w] = mat
|
||
|
||
# Resize the image to the input dimensions
|
||
canvas = cv2.resize(canvas, (self.input_width, self.input_height))
|
||
|
||
# Normalize the image in-place
|
||
canvas = canvas.astype(np.float32)
|
||
mean = 127.5
|
||
scale = 1.0 / 127.5
|
||
canvas = (canvas - mean) * scale
|
||
|
||
# Convert to CHW format
|
||
canvas = np.transpose(canvas, (2, 0, 1))
|
||
|
||
# Create a tensor
|
||
input_tensor = np.expand_dims(canvas, axis=0).astype(np.float32)
|
||
return input_tensor
|
||
|
||
def detect_angle(self, img):
|
||
input_tensor = self.transform(img)
|
||
|
||
var_output = self.var_fsanet.run(
|
||
self.var_output_names, {self.var_input_names[0]: input_tensor}
|
||
)[0]
|
||
conv_output = self.conv_fsanet.run(
|
||
self.conv_output_names, {self.conv_input_names[0]: input_tensor}
|
||
)[0]
|
||
yaw, pitch, roll = np.mean(np.vstack((var_output,conv_output)), axis=0)
|
||
|
||
return yaw, pitch, roll
|
||
|
||
def check(self, image):
|
||
yaw, pitch, roll = self.detect_angle(image)
|
||
|
||
if abs(yaw) <= self.yaw_thrd and abs(pitch) <= self.pitch_thrd:
|
||
return "frontFace"
|
||
elif yaw < -1.0 * self.yaw_thrd:
|
||
return "rightFace"
|
||
elif yaw > self.yaw_thrd:
|
||
return "leftFace"
|
||
elif pitch > self.pitch_thrd:
|
||
return "upFace"
|
||
elif pitch < -1.0 * self.pitch_thrd:
|
||
return "downFace"
|
||
else:
|
||
return "implementError"
|
||
|
||
|
||
if __name__ == "__main__":
|
||
qp = QualityOfPose()
|
||
img = cv2.imread("/home/bns/liteAitoolkit/Demos_onnx/examples/det_oeyecmouth.jpg")
|
||
angles = qp.check(img)
|
||
print(f"ONNXRuntime Version yaw: {angles[0]} pitch: {angles[1]} roll: {angles[2]}")
|
||
pass |