2021-04-14 15:22:51 +08:00
|
|
|
'''
|
|
|
|
@ Date: 2020-11-28 17:23:04
|
|
|
|
@ Author: Qing Shuai
|
|
|
|
@ LastEditors: Qing Shuai
|
2023-06-19 17:23:44 +08:00
|
|
|
@ LastEditTime: 2022-10-27 15:13:56
|
2022-08-21 16:04:51 +08:00
|
|
|
@ FilePath: /EasyMocapPublic/easymocap/mytools/vis_base.py
|
2021-04-14 15:22:51 +08:00
|
|
|
'''
|
|
|
|
import cv2
|
|
|
|
import numpy as np
|
|
|
|
import json
|
|
|
|
|
2023-06-19 17:23:44 +08:00
|
|
|
def generate_colorbar(N = 20, cmap = 'jet', rand=True,
|
|
|
|
ret_float=False, ret_array=False, ret_rgb=False):
|
2021-04-14 15:22:51 +08:00
|
|
|
bar = ((np.arange(N)/(N-1))*255).astype(np.uint8).reshape(-1, 1)
|
|
|
|
colorbar = cv2.applyColorMap(bar, cv2.COLORMAP_JET).squeeze()
|
|
|
|
if False:
|
|
|
|
colorbar = np.clip(colorbar + 64, 0, 255)
|
2022-08-21 16:04:51 +08:00
|
|
|
if rand:
|
|
|
|
import random
|
|
|
|
random.seed(666)
|
|
|
|
index = [i for i in range(N)]
|
|
|
|
random.shuffle(index)
|
|
|
|
rgb = colorbar[index, :]
|
|
|
|
else:
|
|
|
|
rgb = colorbar
|
2023-06-19 17:23:44 +08:00
|
|
|
if ret_rgb:
|
|
|
|
rgb = rgb[:, ::-1]
|
|
|
|
if ret_float:
|
|
|
|
rgb = rgb/255.
|
|
|
|
if not ret_array:
|
|
|
|
rgb = rgb.tolist()
|
2021-04-14 15:22:51 +08:00
|
|
|
return rgb
|
|
|
|
|
2022-08-21 16:04:51 +08:00
|
|
|
# colors_bar_rgb = generate_colorbar(cmap='hsv')
|
|
|
|
colors_bar_rgb = [
|
|
|
|
(94, 124, 226), # 青色
|
|
|
|
(255, 200, 87), # yellow
|
|
|
|
(74, 189, 172), # green
|
|
|
|
(8, 76, 97), # blue
|
|
|
|
(219, 58, 52), # red
|
|
|
|
(77, 40, 49), # brown
|
|
|
|
]
|
2021-04-14 15:22:51 +08:00
|
|
|
|
|
|
|
colors_table = {
|
|
|
|
'b': [0.65098039, 0.74117647, 0.85882353],
|
|
|
|
'_pink': [.9, .7, .7],
|
|
|
|
'_mint': [ 166/255., 229/255., 204/255.],
|
|
|
|
'_mint2': [ 202/255., 229/255., 223/255.],
|
|
|
|
'_green': [ 153/255., 216/255., 201/255.],
|
|
|
|
'_green2': [ 171/255., 221/255., 164/255.],
|
|
|
|
'r': [ 251/255., 128/255., 114/255.],
|
|
|
|
'_orange': [ 253/255., 174/255., 97/255.],
|
|
|
|
'y': [ 250/255., 230/255., 154/255.],
|
|
|
|
'g':[0,255/255,0],
|
|
|
|
'k':[0,0,0],
|
2022-08-21 16:04:51 +08:00
|
|
|
'_r':[255/255,0,0],
|
|
|
|
'_g':[0,255/255,0],
|
|
|
|
'_b':[0,0,255/255],
|
|
|
|
'_k':[0,0,0],
|
2021-04-14 15:22:51 +08:00
|
|
|
'_y':[255/255,255/255,0],
|
|
|
|
'purple':[128/255,0,128/255],
|
|
|
|
'smap_b':[51/255,153/255,255/255],
|
|
|
|
'smap_r':[255/255,51/255,153/255],
|
2022-08-21 16:04:51 +08:00
|
|
|
'person': [255/255,255/255,255/255],
|
|
|
|
'handl': [255/255,51/255,153/255],
|
|
|
|
'handr': [51/255,255/255,153/255],
|
2021-04-14 15:22:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
def get_rgb(index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
if index == -1:
|
|
|
|
return (255, 255, 255)
|
|
|
|
if index < -1:
|
|
|
|
return (0, 0, 0)
|
2022-08-21 16:04:51 +08:00
|
|
|
# elif index == 0:
|
|
|
|
# return (245, 150, 150)
|
|
|
|
col = list(colors_bar_rgb[index%len(colors_bar_rgb)])[::-1]
|
2023-06-19 17:23:44 +08:00
|
|
|
elif isinstance(index, str):
|
2021-04-14 15:22:51 +08:00
|
|
|
col = colors_table.get(index, (1, 0, 0))
|
|
|
|
col = tuple([int(c*255) for c in col[::-1]])
|
2023-06-19 17:23:44 +08:00
|
|
|
else:
|
|
|
|
raise TypeError('index should be int or str')
|
2021-04-14 15:22:51 +08:00
|
|
|
return col
|
|
|
|
|
2021-06-04 17:12:30 +08:00
|
|
|
def get_rgb_01(index):
|
|
|
|
col = get_rgb(index)
|
|
|
|
return [i*1./255 for i in col[:3]]
|
|
|
|
|
|
|
|
def plot_point(img, x, y, r, col, pid=-1, font_scale=-1, circle_type=-1):
|
|
|
|
cv2.circle(img, (int(x+0.5), int(y+0.5)), r, col, circle_type)
|
|
|
|
if font_scale == -1:
|
|
|
|
font_scale = img.shape[0]/4000
|
2021-04-14 15:22:51 +08:00
|
|
|
if pid != -1:
|
2021-06-04 17:12:30 +08:00
|
|
|
cv2.putText(img, '{}'.format(pid), (int(x+0.5), int(y+0.5)), cv2.FONT_HERSHEY_SIMPLEX, font_scale, col, 1)
|
2021-04-14 15:22:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
def plot_line(img, pt1, pt2, lw, col):
|
|
|
|
cv2.line(img, (int(pt1[0]+0.5), int(pt1[1]+0.5)), (int(pt2[0]+0.5), int(pt2[1]+0.5)),
|
|
|
|
col, lw)
|
|
|
|
|
2021-06-04 17:12:30 +08:00
|
|
|
def plot_cross(img, x, y, col, width=-1, lw=-1):
|
|
|
|
if lw == -1:
|
2021-08-28 20:50:20 +08:00
|
|
|
lw = max(1, int(round(img.shape[0]/1000)))
|
2021-06-04 17:12:30 +08:00
|
|
|
width = lw * 5
|
2021-04-14 15:22:51 +08:00
|
|
|
cv2.line(img, (int(x-width), int(y)), (int(x+width), int(y)), col, lw)
|
|
|
|
cv2.line(img, (int(x), int(y-width)), (int(x), int(y+width)), col, lw)
|
|
|
|
|
2022-08-21 16:04:51 +08:00
|
|
|
def plot_bbox(img, bbox, pid, scale=1, vis_id=True):
|
2021-04-14 15:22:51 +08:00
|
|
|
# 画bbox: (l, t, r, b)
|
2022-08-21 16:04:51 +08:00
|
|
|
x1, y1, x2, y2, c = bbox
|
|
|
|
if c < 0.01:return img
|
|
|
|
x1 = int(round(x1*scale))
|
|
|
|
x2 = int(round(x2*scale))
|
|
|
|
y1 = int(round(y1*scale))
|
|
|
|
y2 = int(round(y2*scale))
|
2021-04-14 15:22:51 +08:00
|
|
|
color = get_rgb(pid)
|
|
|
|
lw = max(img.shape[0]//300, 2)
|
|
|
|
cv2.rectangle(img, (x1, y1), (x2, y2), color, lw)
|
|
|
|
if vis_id:
|
2021-06-04 17:12:30 +08:00
|
|
|
font_scale = img.shape[0]/1000
|
|
|
|
cv2.putText(img, '{}'.format(pid), (x1, y1+int(25*font_scale)), cv2.FONT_HERSHEY_SIMPLEX, font_scale, color, 2)
|
2021-04-14 15:22:51 +08:00
|
|
|
|
2022-08-21 16:04:51 +08:00
|
|
|
def plot_keypoints(img, points, pid, config, vis_conf=False, use_limb_color=True, lw=2, fliplr=False):
|
|
|
|
lw = max(lw, 2)
|
|
|
|
H, W = img.shape[:2]
|
2021-04-14 15:22:51 +08:00
|
|
|
for ii, (i, j) in enumerate(config['kintree']):
|
|
|
|
if i >= len(points) or j >= len(points):
|
|
|
|
continue
|
2022-08-21 16:04:51 +08:00
|
|
|
if (i >25 or j > 25) and config['nJoints'] != 42:
|
|
|
|
_lw = max(int(lw/4), 1)
|
|
|
|
else:
|
|
|
|
_lw = lw
|
2021-04-14 15:22:51 +08:00
|
|
|
pt1, pt2 = points[i], points[j]
|
2022-08-21 16:04:51 +08:00
|
|
|
if fliplr:
|
|
|
|
pt1 = (W-pt1[0], pt1[1])
|
|
|
|
pt2 = (W-pt2[0], pt2[1])
|
2021-04-14 15:22:51 +08:00
|
|
|
if use_limb_color:
|
|
|
|
col = get_rgb(config['colors'][ii])
|
|
|
|
else:
|
|
|
|
col = get_rgb(pid)
|
|
|
|
if pt1[-1] > 0.01 and pt2[-1] > 0.01:
|
|
|
|
image = cv2.line(
|
|
|
|
img, (int(pt1[0]+0.5), int(pt1[1]+0.5)), (int(pt2[0]+0.5), int(pt2[1]+0.5)),
|
2022-08-21 16:04:51 +08:00
|
|
|
col, _lw)
|
|
|
|
for i in range(min(len(points), config['nJoints'])):
|
|
|
|
x, y = points[i][0], points[i][1]
|
|
|
|
if fliplr:
|
|
|
|
x = W - x
|
|
|
|
c = points[i][-1]
|
|
|
|
if c > 0.01:
|
|
|
|
text_size = img.shape[0]/1000
|
|
|
|
col = get_rgb(pid)
|
|
|
|
radius = int(lw/1.5)
|
|
|
|
if i > 25 and config['nJoints'] != 42:
|
|
|
|
radius = max(int(radius/4), 1)
|
|
|
|
cv2.circle(img, (int(x+0.5), int(y+0.5)), radius, col, -1)
|
|
|
|
if vis_conf:
|
|
|
|
cv2.putText(img, '{:.1f}'.format(c), (int(x), int(y)),
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, text_size, col, 2)
|
|
|
|
|
2023-06-19 17:23:44 +08:00
|
|
|
def plot_keypoints_auto(img, points, pid, vis_conf=False, use_limb_color=True, scale=1, lw=-1, config_name=None, lw_factor=1):
|
2022-08-21 16:04:51 +08:00
|
|
|
from ..dataset.config import CONFIG
|
2023-06-19 17:23:44 +08:00
|
|
|
if config_name is None:
|
|
|
|
config_name = {25: 'body25', 15: 'body15', 21: 'hand', 42:'handlr', 17: 'coco', 1:'points', 67:'bodyhand', 137: 'total', 79:'up',
|
|
|
|
19:'ochuman'}[len(points)]
|
2022-08-21 16:04:51 +08:00
|
|
|
config = CONFIG[config_name]
|
|
|
|
if lw == -1:
|
|
|
|
lw = img.shape[0]//200
|
|
|
|
if config_name == 'hand':
|
2023-06-19 17:23:44 +08:00
|
|
|
lw = img.shape[0]//100
|
2022-08-21 16:04:51 +08:00
|
|
|
lw = max(lw, 1)
|
|
|
|
for ii, (i, j) in enumerate(config['kintree']):
|
|
|
|
if i >= len(points) or j >= len(points):
|
|
|
|
continue
|
|
|
|
if i >= 25 and config_name in ['bodyhand', 'total']:
|
|
|
|
lw = max(img.shape[0]//400, 1)
|
|
|
|
pt1, pt2 = points[i], points[j]
|
|
|
|
if use_limb_color:
|
|
|
|
col = get_rgb(config['colors'][ii])
|
|
|
|
else:
|
|
|
|
col = get_rgb(pid)
|
2023-06-19 17:23:44 +08:00
|
|
|
if pt1[0] < -10000 or pt1[1] < -10000 or pt1[0] > 10000 or pt1[1] > 10000:
|
2022-08-21 16:04:51 +08:00
|
|
|
continue
|
2023-06-19 17:23:44 +08:00
|
|
|
if pt2[0] < -10000 or pt2[1] < -10000 or pt2[0] > 10000 or pt2[1] > 10000:
|
2022-08-21 16:04:51 +08:00
|
|
|
continue
|
|
|
|
if pt1[-1] > 0.01 and pt2[-1] > 0.01:
|
|
|
|
image = cv2.line(
|
|
|
|
img, (int(pt1[0]*scale+0.5), int(pt1[1]*scale+0.5)), (int(pt2[0]*scale+0.5), int(pt2[1]*scale+0.5)),
|
2021-04-14 15:22:51 +08:00
|
|
|
col, lw)
|
2022-08-21 16:04:51 +08:00
|
|
|
lw = img.shape[0]//200
|
|
|
|
if config_name == 'hand':
|
|
|
|
lw = img.shape[0]//500
|
|
|
|
lw = max(lw, 1)
|
2021-04-14 15:22:51 +08:00
|
|
|
for i in range(len(points)):
|
2022-08-21 16:04:51 +08:00
|
|
|
x, y = points[i][0]*scale, points[i][1]*scale
|
|
|
|
if x < 0 or y < 0 or x >10000 or y >10000:
|
|
|
|
continue
|
|
|
|
if i >= 25 and config_name in ['bodyhand', 'total']:
|
|
|
|
lw = max(img.shape[0]//400, 1)
|
2021-04-14 15:22:51 +08:00
|
|
|
c = points[i][-1]
|
|
|
|
if c > 0.01:
|
|
|
|
col = get_rgb(pid)
|
2022-08-21 16:04:51 +08:00
|
|
|
if len(points) == 1:
|
2023-06-19 17:23:44 +08:00
|
|
|
_lw = max(0, int(lw * lw_factor))
|
|
|
|
cv2.circle(img, (int(x+0.5), int(y+0.5)), _lw*2, col, lw*2)
|
|
|
|
plot_cross(img, int(x+0.5), int(y+0.5), width=_lw, col=col, lw=lw*2)
|
2022-08-21 16:04:51 +08:00
|
|
|
else:
|
|
|
|
cv2.circle(img, (int(x+0.5), int(y+0.5)), lw*2, col, -1)
|
2021-04-14 15:22:51 +08:00
|
|
|
if vis_conf:
|
2023-06-19 17:23:44 +08:00
|
|
|
cv2.putText(img, '{:.1f}'.format(c), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, col, 2)
|
2021-04-14 15:22:51 +08:00
|
|
|
|
2022-08-21 16:04:51 +08:00
|
|
|
def plot_keypoints_total(img, annots, scale, pid_offset=0):
|
|
|
|
_lw = img.shape[0] // 150
|
|
|
|
for annot in annots:
|
|
|
|
pid = annot['personID'] + pid_offset
|
|
|
|
for key in ['keypoints', 'handl2d', 'handr2d']:
|
|
|
|
if key not in annot.keys():continue
|
|
|
|
if key in ['handl2d', 'handr2d', 'face2d']:
|
|
|
|
lw = _lw // 2
|
|
|
|
else:
|
|
|
|
lw = _lw
|
|
|
|
lw = max(lw, 1)
|
|
|
|
plot_keypoints_auto(img, annot[key], pid, vis_conf=False, use_limb_color=False, scale=scale, lw=lw)
|
|
|
|
if 'bbox' not in annot.keys() or (annot['bbox'][0] < 0 or annot['bbox'][0] >10000):
|
|
|
|
continue
|
|
|
|
plot_bbox(img, annot['bbox'], pid, scale=scale, vis_id=True)
|
|
|
|
return img
|
|
|
|
|
|
|
|
def plot_points2d(img, points2d, lines, lw=-1, col=(0, 255, 0), putText=True, style='+'):
|
2021-04-14 15:22:51 +08:00
|
|
|
# 将2d点画上去
|
2021-06-04 17:12:30 +08:00
|
|
|
if points2d.shape[1] == 2:
|
|
|
|
points2d = np.hstack([points2d, np.ones((points2d.shape[0], 1))])
|
2022-08-21 16:04:51 +08:00
|
|
|
if lw == -1:
|
|
|
|
lw = img.shape[0]//200
|
2021-04-14 15:22:51 +08:00
|
|
|
for i, (x, y, v) in enumerate(points2d):
|
|
|
|
if v < 0.01:
|
|
|
|
continue
|
|
|
|
c = col
|
2022-08-21 16:04:51 +08:00
|
|
|
if '+' in style:
|
|
|
|
plot_cross(img, x, y, width=10, col=c, lw=lw*2)
|
|
|
|
if 'o' in style:
|
|
|
|
cv2.circle(img, (int(x), int(y)), 10, c, lw*2)
|
|
|
|
cv2.circle(img, (int(x), int(y)), lw, c, lw)
|
2021-04-14 15:22:51 +08:00
|
|
|
if putText:
|
2022-08-21 16:04:51 +08:00
|
|
|
c = col[::-1]
|
|
|
|
font_scale = img.shape[0]/1000
|
2021-06-04 17:12:30 +08:00
|
|
|
cv2.putText(img, '{}'.format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, font_scale, c, 2)
|
2021-04-14 15:22:51 +08:00
|
|
|
for i, j in lines:
|
|
|
|
if points2d[i][2] < 0.01 or points2d[j][2] < 0.01:
|
|
|
|
continue
|
2022-08-21 16:04:51 +08:00
|
|
|
plot_line(img, points2d[i], points2d[j], max(1, lw//2), col)
|
2021-04-14 15:22:51 +08:00
|
|
|
|
2021-06-04 17:12:30 +08:00
|
|
|
row_col_ = {
|
|
|
|
2: (2, 1),
|
|
|
|
7: (2, 4),
|
|
|
|
8: (2, 4),
|
|
|
|
9: (3, 3),
|
|
|
|
26: (4, 7)
|
|
|
|
}
|
2022-08-21 16:04:51 +08:00
|
|
|
|
|
|
|
row_col_square = {
|
|
|
|
2: (2, 1),
|
|
|
|
7: (3, 3),
|
|
|
|
8: (3, 3),
|
|
|
|
9: (3, 3),
|
|
|
|
26: (5, 5)
|
|
|
|
}
|
|
|
|
|
|
|
|
def get_row_col(l, square):
|
|
|
|
if square and l in row_col_square.keys():
|
|
|
|
return row_col_square[l]
|
2021-06-04 17:12:30 +08:00
|
|
|
if l in row_col_.keys():
|
|
|
|
return row_col_[l]
|
|
|
|
else:
|
2021-04-14 15:22:51 +08:00
|
|
|
from math import sqrt
|
2021-06-04 17:12:30 +08:00
|
|
|
row = int(sqrt(l) + 0.5)
|
|
|
|
col = int(l/ row + 0.5)
|
|
|
|
if row*col<l:
|
|
|
|
col = col + 1
|
2021-04-14 15:22:51 +08:00
|
|
|
if row > col:
|
|
|
|
row, col = col, row
|
2021-06-04 17:12:30 +08:00
|
|
|
return row, col
|
|
|
|
|
2022-08-21 16:04:51 +08:00
|
|
|
def merge(images, row=-1, col=-1, resize=False, ret_range=False, square=False, **kwargs):
|
2021-06-04 17:12:30 +08:00
|
|
|
if row == -1 and col == -1:
|
2022-08-21 16:04:51 +08:00
|
|
|
row, col = get_row_col(len(images), square)
|
2021-04-14 15:22:51 +08:00
|
|
|
height = images[0].shape[0]
|
|
|
|
width = images[0].shape[1]
|
2022-08-21 16:04:51 +08:00
|
|
|
# special case
|
|
|
|
if height > width:
|
|
|
|
if len(images) == 3:
|
|
|
|
row, col = 1, 3
|
|
|
|
if len(images[0].shape) > 2:
|
|
|
|
ret_img = np.zeros((height * row, width * col, images[0].shape[2]), dtype=np.uint8) + 255
|
|
|
|
else:
|
|
|
|
ret_img = np.zeros((height * row, width * col), dtype=np.uint8) + 255
|
2021-04-14 15:22:51 +08:00
|
|
|
ranges = []
|
|
|
|
for i in range(row):
|
|
|
|
for j in range(col):
|
|
|
|
if i*col + j >= len(images):
|
|
|
|
break
|
|
|
|
img = images[i * col + j]
|
|
|
|
# resize the image size
|
|
|
|
img = cv2.resize(img, (width, height))
|
|
|
|
ret_img[height * i: height * (i+1), width * j: width * (j+1)] = img
|
|
|
|
ranges.append((width*j, height*i, width*(j+1), height*(i+1)))
|
|
|
|
if resize:
|
2021-08-28 20:50:20 +08:00
|
|
|
min_height = 1000
|
2021-06-04 17:12:30 +08:00
|
|
|
if ret_img.shape[0] > min_height:
|
|
|
|
scale = min_height/ret_img.shape[0]
|
2021-04-14 15:22:51 +08:00
|
|
|
ret_img = cv2.resize(ret_img, None, fx=scale, fy=scale)
|
|
|
|
if ret_range:
|
|
|
|
return ret_img, ranges
|
|
|
|
return ret_img
|