from __future__ import absolute_import from __future__ import print_function from __future__ import division import os import os.path as osp from collections import OrderedDict import cv2 import numpy as np from skimage.filters import gaussian def get_transform(center, scale, res, rot=0): """Generate transformation matrix.""" # res: (height, width), (rows, cols) crop_aspect_ratio = res[0] / float(res[1]) h = 200 * scale w = h / crop_aspect_ratio t = np.zeros((3, 3)) t[0, 0] = float(res[1]) / w t[1, 1] = float(res[0]) / h t[0, 2] = res[1] * (-float(center[0]) / w + .5) t[1, 2] = res[0] * (-float(center[1]) / h + .5) t[2, 2] = 1 if not rot == 0: rot = -rot # To match direction of rotation from cropping rot_mat = np.zeros((3, 3)) rot_rad = rot * np.pi / 180 sn, cs = np.sin(rot_rad), np.cos(rot_rad) rot_mat[0, :2] = [cs, -sn] rot_mat[1, :2] = [sn, cs] rot_mat[2, 2] = 1 # Need to rotate around center t_mat = np.eye(3) t_mat[0, 2] = -res[1] / 2 t_mat[1, 2] = -res[0] / 2 t_inv = t_mat.copy() t_inv[:2, 2] *= -1 t = np.dot(t_inv, np.dot(rot_mat, np.dot(t_mat, t))) return t def transform(pt, center, scale, res, invert=0, rot=0): """Transform pixel location to different reference.""" t = get_transform(center, scale, res, rot=rot) if invert: t = np.linalg.inv(t) new_pt = np.array([pt[0] - 1, pt[1] - 1, 1.]).T new_pt = np.dot(t, new_pt) return np.array([round(new_pt[0]), round(new_pt[1])], dtype=int) + 1 def crop(img, center, scale, res): """ Crop image according to the supplied bounding box. res: [rows, cols] """ # Upper left point ul = np.array(transform([1, 1], center, scale, res, invert=1)) - 1 # Bottom right point br = np.array(transform([res[1] + 1, res[0] + 1], center, scale, res, invert=1)) - 1 new_shape = [br[1] - ul[1], br[0] - ul[0]] if len(img.shape) > 2: new_shape += [img.shape[2]] new_img = np.zeros(new_shape, dtype=np.float32) # Range to fill new array new_x = max(0, -ul[0]), min(br[0], len(img[0])) - ul[0] new_y = max(0, -ul[1]), min(br[1], len(img)) - ul[1] # Range to sample from original image old_x = max(0, ul[0]), min(len(img[0]), br[0]) old_y = max(0, ul[1]), min(len(img), br[1]) try: new_img[new_y[0]:new_y[1], new_x[0]:new_x[1]] = img[old_y[0]:old_y[1], old_x[0]:old_x[1]] except Exception as e: print(e) new_img = cv2.resize(new_img, (res[1], res[0])) # (cols, rows) return new_img, ul, br def process_image(orig_img_rgb, center, scale, crop_height=256, crop_width=192, blur=False, do_crop=True): """ Read image, do preprocessing and possibly crop it according to the bounding box. If there are bounding box annotations, use them to crop the image. If no bounding box is specified but openpose detections are available, use them to get the bounding box. """ if blur: # Blur image to avoid aliasing artifacts downsampling_factor = ((scale * 200 * 1.0) / crop_height) downsampling_factor = downsampling_factor / 2.0 if downsampling_factor > 1.1: orig_img_rgb = gaussian(orig_img_rgb, sigma=(downsampling_factor-1)/2, channel_axis=2, preserve_range=True) IMG_NORM_MEAN = [0.485, 0.456, 0.406] IMG_NORM_STD = [0.229, 0.224, 0.225] if do_crop: img, ul, br = crop(orig_img_rgb, center, scale, (crop_height, crop_width)) else: img = orig_img_rgb.copy() crop_img = img.copy() img = img / 255. mean = np.array(IMG_NORM_MEAN, dtype=np.float32) std = np.array(IMG_NORM_STD, dtype=np.float32) norm_img = (img - mean) / std norm_img = np.transpose(norm_img, (2, 0, 1)) return norm_img, crop_img