|
|
|
|
|
|
|
|
|
|
|
|
|
import collections |
|
import numpy as np |
|
import cv2 as cv |
|
import sys |
|
|
|
class Compose: |
|
def __init__(self, transforms=[]): |
|
self.transforms = transforms |
|
|
|
def __call__(self, img): |
|
for t in self.transforms: |
|
img = t(img) |
|
if img is None: |
|
break |
|
return img |
|
|
|
class Resize: |
|
def __init__(self, size, interpolation=cv.INTER_LINEAR): |
|
self.size = size |
|
self.interpolation = interpolation |
|
|
|
def __call__(self, img): |
|
return cv.resize(img, self.size) |
|
|
|
class CenterCrop: |
|
def __init__(self, size): |
|
self.size = size |
|
|
|
def __call__(self, img): |
|
h, w, _ = img.shape |
|
ws = int(w / 2 - self.size[0] / 2) |
|
hs = int(h / 2 - self.size[1] / 2) |
|
return img[hs:hs+self.size[1], ws:ws+self.size[0], :] |
|
|
|
class Normalize: |
|
def __init__(self, mean=None, std=None): |
|
self.mean = mean |
|
self.std = std |
|
|
|
def __call__(self, img): |
|
img = img.astype("float32") |
|
if self.mean is not None: |
|
img[:, :, 0] = img[:, :, 0] - self.mean[0] |
|
img[:, :, 1] = img[:, :, 1] - self.mean[1] |
|
img[:, :, 2] = img[:, :, 2] - self.mean[2] |
|
if self.std is not None: |
|
img[:, :, 0] = img[:, :, 0] / self.std[0] |
|
img[:, :, 1] = img[:, :, 1] / self.std[1] |
|
img[:, :, 2] = img[:, :, 2] / self.std[2] |
|
return img |
|
|
|
class ColorConvert: |
|
def __init__(self, ctype): |
|
self.ctype = ctype |
|
|
|
def __call__(self, img): |
|
return cv.cvtColor(img, self.ctype) |
|
|
|
class HandAlign: |
|
def __init__(self, model): |
|
self.model = model |
|
sys.path.append('../../models/palm_detection_mediapipe') |
|
from mp_palmdet import MPPalmDet |
|
self.palm_detector = MPPalmDet(modelPath='../../models/palm_detection_mediapipe/palm_detection_mediapipe_2023feb.onnx', nmsThreshold=0.3, scoreThreshold=0.9) |
|
|
|
def __call__(self, img): |
|
return self.mp_handpose_align(img) |
|
|
|
def mp_handpose_align(self, img): |
|
palms = self.palm_detector.infer(img) |
|
if len(palms) == 0: |
|
return None |
|
palm = palms[0] |
|
palm_bbox = palm[0:4].reshape(2, 2) |
|
palm_landmarks = palm[4:18].reshape(7, 2) |
|
p1 = palm_landmarks[0] |
|
p2 = palm_landmarks[2] |
|
radians = np.pi / 2 - np.arctan2(-(p2[1] - p1[1]), p2[0] - p1[0]) |
|
radians = radians - 2 * np.pi * np.floor((radians + np.pi) / (2 * np.pi)) |
|
angle = np.rad2deg(radians) |
|
|
|
center_palm_bbox = np.sum(palm_bbox, axis=0) / 2 |
|
|
|
rotation_matrix = cv.getRotationMatrix2D(center_palm_bbox, angle, 1.0) |
|
|
|
rotated_image = cv.warpAffine(img, rotation_matrix, (img.shape[1], img.shape[0])) |
|
|
|
homogeneous_coord = np.c_[palm_landmarks, np.ones(palm_landmarks.shape[0])] |
|
rotated_palm_landmarks = np.array([ |
|
np.dot(homogeneous_coord, rotation_matrix[0]), |
|
np.dot(homogeneous_coord, rotation_matrix[1])]) |
|
|
|
rotated_palm_bbox = np.array([ |
|
np.amin(rotated_palm_landmarks, axis=1), |
|
np.amax(rotated_palm_landmarks, axis=1)]) |
|
|
|
|
|
wh_rotated_palm_bbox = rotated_palm_bbox[1] - rotated_palm_bbox[0] |
|
shift_vector = [0, -0.1] * wh_rotated_palm_bbox |
|
rotated_palm_bbox = rotated_palm_bbox + shift_vector |
|
|
|
center_rotated_plam_bbox = np.sum(rotated_palm_bbox, axis=0) / 2 |
|
wh_rotated_palm_bbox = rotated_palm_bbox[1] - rotated_palm_bbox[0] |
|
new_half_size = np.amax(wh_rotated_palm_bbox) / 2 |
|
rotated_palm_bbox = np.array([ |
|
center_rotated_plam_bbox - new_half_size, |
|
center_rotated_plam_bbox + new_half_size]) |
|
|
|
|
|
center_rotated_plam_bbox = np.sum(rotated_palm_bbox, axis=0) / 2 |
|
wh_rotated_palm_bbox = rotated_palm_bbox[1] - rotated_palm_bbox[0] |
|
new_half_size = wh_rotated_palm_bbox * 1.5 |
|
rotated_palm_bbox = np.array([ |
|
center_rotated_plam_bbox - new_half_size, |
|
center_rotated_plam_bbox + new_half_size]) |
|
|
|
|
|
[[x1, y1], [x2, y2]] = rotated_palm_bbox.astype(np.int32) |
|
diff = np.maximum([-x1, -y1, x2 - rotated_image.shape[1], y2 - rotated_image.shape[0]], 0) |
|
[x1, y1, x2, y2] = [x1, y1, x2, y2] + diff |
|
crop = rotated_image[y1:y2, x1:x2, :] |
|
crop = cv.copyMakeBorder(crop, diff[1], diff[3], diff[0], diff[2], cv.BORDER_CONSTANT, value=(0, 0, 0)) |
|
return crop |
|
|