https://gitee.com/seuvcl/CVPR2020-OOH
极简
注意事项:
- 把basicmodel_neutral_lbs_10_207_0_v1.1.0.pkl下下来改名SMPL_NEUTRAL.pkl后放进data。不能直接用smplx的,里面数据结构不太兼容
- 目前代码只支持输入图片的文件夹,急着用所以就视频单独截帧了。注意类似Ubuntu的处理方法,帧命名补0,不然后面生成的结果顺序就乱了
- 截帧后的自建图片文件夹要在yaml里修改
data_folder
- 有时图像中人形难以辨认会导致后续矩阵计算中出现奇异矩阵不可逆,所以我把
utils\imutils.py
的estimate_translation_np
函数里加了个伪逆,不是最佳处理办法,暂时凑活用了
import sys
def estimate_translation_np(S, joints_2d, joints_conf, focal_length=5000, cx=128., cy=128.):num_joints = S.shape[0]... # square matrixA = np.dot(Q.T, Q)b = np.dot(Q.T, c)# 检查矩阵 A 是否是奇异的if np.linalg.cond(A) < 1/sys.float_info.epsilon:# 如果不是奇异的,使用正常的求解方法trans = np.linalg.solve(A, b)else:# 如果是奇异的,使用伪逆pinv = np.linalg.pinv(A)trans = np.dot(pinv, b)return trans
记录一下截帧代码
cap = cv2.VideoCapture(video_path)
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frame_id = 1
gap = 4
save_path = f"demo_{datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}"
os.makedirs(save_path,exist_ok=True)
while True:start_time = time.time()ret, frame = cap.read()if frame_id % gap != 0:frame_id += 1continueif not ret:breakelapsed_time = time.time() - start_timelogger.info('Frame {}/{} ({:.2f} ms)'.format(frame_id, frame_count, elapsed_time * 1000), )frame_id += 1id_save_path = f"{save_path}/{frame_id:05d}.png"cv2.imwrite(id_save_path, frame)
cap.release()
以及生成效果视频的代码
def create_video(image_folder, video_name, fps):images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]images.sort() # 确保图像是按顺序排列的# 读取第一张图像来确定视频的分辨率frame = cv2.imread(os.path.join(image_folder, images[0]))height, width, layers = frame.shapevideo = cv2.VideoWriter(video_name, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height))for image in images:video.write(cv2.imread(os.path.join(image_folder, image)))cv2.destroyAllWindows()video.release()path = "output/demo/01.02-15h40m11s/images" # 请替换为您的根目录路径
temp_folder = f"temp_images_{datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}" # 以防后续帧数太多,所以整个临时文件夹用于存储拼接后的图像
os.makedirs(temp_folder, exist_ok=True)
num=len(os.listdir(path))//6
for i in range(num):img_path = f"{path}/{i:05d}_img.jpg"mask_path = f"{path}/{i:05d}_mask.jpg"render_path = f"{path}/{i:05d}_render.jpg"heat_path = f"{path}/{i:05d}_heatmap.jpg"img = cv2.imread(img_path)mask = cv2.imread(mask_path)render = cv2.imread(render_path)heat = cv2.imread(heat_path)combined_image_1 = np.hstack((img, heat))combined_image_2 = np.hstack((mask, render))combined_image = np.vstack((combined_image_1, combined_image_2))# 保存拼接后的图像cv2.imwrite(f"{temp_folder}/{i:05d}.jpg", combined_image)# 创建视频
create_video(temp_folder, f"output_video_{datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}.mp4", 10) # 10 FPS
存在问题
生成的四类图像都没有回到原图的分辨率导致很模糊,pad的黑边也没有去,之后看看优化一下?
具体算法原理之后再说,大体上是基于分割剪影和预设UV图得到的蒙皮,关节点应该只是辅助
所以分割效果差的帧,生成的蒙皮也会很神秘
- 两只手臂都在胸前的话无论做什么动作,在mask中都是看不出来的
(虽说这个mask是有几层通道的,也就是说其实有类似sam会有区分前景后景的吧)
,所以这种错就很明显 - mask不成人样的就没有生成蒙皮
- 快动作手臂残影可以预测到它的位置还不错
(包括有些只有人头像的帧也能脑补出来个蹲坐的蒙皮还挺逗的)
,但是有些时候手臂的抬起高度很明显却对不准,很怪