1.demo_skeleton.py
FONTFACE = cv2.FONT_HERSHEY_DUPLEX
# FONTSCALE = 0.75
FONTSCALE = 2
FONTCOLOR = (255, 255, 255) # BGR, white
THICKNESS = 1
# LINETYPE = 1
LINETYPE = 2
(1)这一部分是用来对标签颜色大小线的粗细进行的设置。修改试一下。
原图像
修改后
(2)从main函数开始看
1)首先main函数先args = parse_args()解析命令行参数,通过调用这个函数,你可以获取到用户在命令行中传递给程序的参数值。
假设命令行输入
python demo/demo_skeleton.py demo/ntu_sample.avi demo/demo.mp4
参数包括输入视频,输出视频。其他参数就会选择默认的选项,例如
parser.add_argument(
'--config',
default='configs/posec3d/slowonly_r50_ntu120_xsub/joint.py',
help='skeleton action recognition config file path')
parser.add_argument(
'--checkpoint',
default='https://download.openmmlab.com/mmaction/pyskl/ckpt/posec3d/slowonly_r50_ntu120_xsub/joint.pth',
help='skeleton action recognition checkpoint file/url')
parser.add_argument(
'--det-config',
default='demo/faster_rcnn_r50_fpn_1x_coco-person.py',
help='human detection config file path (from mmdet)')
parser.add_argument(
'--det-checkpoint',
default=('https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco-person/'
'faster_rcnn_r50_fpn_1x_coco-person_20201216_175929-d022e227.pth'),
help='human detection checkpoint file/url')
parser.add_argument(
'--pose-config',
default='demo/hrnet_w32_coco_256x192.py',
help='human pose estimation config file path (from mmpose)')
parser.add_argument(
'--pose-checkpoint',
default='https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth',
help='human pose estimation checkpoint file/url')
parser.add_argument(
'--det-score-thr',
type=float,
default=0.9,
help='the threshold of human detection score')
parser.add_argument(
'--label-map',
default='tools/data/label_map/nturgbd_120.txt',
help='label map file')
parser.add_argument(
'--device', type=str, default='cuda:0', help='CPU/CUDA device option')
parser.add_argument(
'--short-side',
type=int,
default=480,
help='specify the short-side length of the image')
这里面default都是默认情况下的选择。命令行没有输入这些,那麽就会按照默认的进行执行。
2)第二行代码就是对输入的视频进行的处理
frame_paths, original_frames = frame_extraction(args.video,
args.short_side)
这里调用了一个函数frame_extraction帧提取参数有两个分别是命令行中输入的视频,以及默认的图像的大小设置。可以试一下将大小修改后的视频情况。默认是480帧
parser.add_argument(
'--short-side',
type=int,
default=480,
help='specify the short-side length of the image')
我们设置成260帧看一下效果
原始图像
改变后的图像
可以看到提取帧变少,视频变得模糊,但是为什么左上角的字也变大了呢。可以看一下你这个函数的代码。
target_dir = osp.join('./tmp', osp.basename(osp.splitext(video_path)[0]))
os.makedirs(target_dir, exist_ok=True)
这段代码第一行会将视频文件名与./tmp结合在一起形成./tmp/video_path_name
第二行是创建这个目录./tmp/video_path_name,如果存在不会报错,如果不存在则会报错。
但是目录里面没有形成文件,把exist_ok参数设置为False试一下。它不仅没有报错而且也没有在tmp中生成帧。
他生成了然后用完了之后又自动将这个文件给删掉了。可以看到这个功能是在./tmp/video_path_name放各个帧的图片。
frame_tmpl = osp.join(target_dir, 'img_{:06d}.jpg')
这行代码定义了一个字符串模板,用于后续创建保存帧的文件名。模板中的{:06d}
表示一个六位的整数,例如000001
、000002
等。所以,对于每一个提取的帧,都会生成一个如img_000001.jpg
、img_000002.jpg
等的文件名。
vid = cv2.VideoCapture(video_path)
这行代码使用OpenCV库中的VideoCapture
函数打开一个视频文件,并返回一个视频对象。通过这个视频对象,我们可以逐帧读取视频,或者获取视频的一些基本信息,如帧率、分辨率等。
frames = []
frame_paths = []
这两行代码初始化两个空列表,frames
用于存储提取的帧,而frame_paths
用于存储这些帧的文件路径。
frames = []
:定义一个空列表,用于存储提取的帧。
frame_paths = []
:定义一个空列表,用于存储这些帧的文件路径。
这两行代码是提取视频帧前的准备工作,为后续的循环读取视频帧和保存帧做准备。
flag, frame = vid.read()
这行代码从视频中读取一帧。如果读取成功,flag
为True
,否则为False
。读取到的帧数据会存储在frame
变量中。
这里的vid.read()
函数会返回两个值:
flag
:一个布尔值,表示是否成功读取了一帧。如果成功读取,则为True
,否则为False
。frame
:读取到的帧数据,是一个NumPy数组。
通过这行代码,我们可以逐帧读取视频,并对每一帧进行处理或保存。
while flag:
if new_h is None:
h, w, _ = frame.shape
new_w, new_h = mmcv.rescale_size((w, h), (short_side, np.Inf))
这段代码的目的是调整视频帧的大小,以适应指定的短边尺寸。
new_h, new_w = None, None
:初始化new_h
和new_w
为None
。这两个变量将用于存储调整大小后的帧的宽度和高度。while flag:
:这是一个循环,会一直执行直到flag
变为False
。在上面的代码中,flag
和frame
是通过vid.read()
函数得到的,其中flag
是一个布尔值,表示是否成功读取了一帧。if new_h is None:
:检查new_h
是否为None
。如果是,说明还没有对帧进行过尺寸调整。h, w, _ = frame.shape
:使用NumPy的shape属性获取当前帧的高度、宽度和通道数。这里只关心高度和宽度,所以用下划线_
忽略通道数。new_w, new_h = mmcv.rescale_size((w, h), (short_side, np.Inf))
:使用mmcv.rescale_size
函数重新调整帧的大小。这个函数接受原始的宽度和高度作为第一个参数,以及新的短边尺寸作为第二个参数。这里将长边设置为无穷大(由np.Inf
表示),以确保只对短边进行缩放。
这段代码的目的是确保提取的帧的短边尺寸与指定的短边尺寸相匹配,这在某些应用中可能是必要的,例如在视频处理或机器视觉任务中,可能需要对视频帧进行统一的尺寸处理。
frame = mmcv.imresize(frame, (new_w, new_h))
frames.append(frame)
frame_path = frame_tmpl.format(cnt + 1)
frame_paths.append(frame_path)
cv2.imwrite(frame_path, frame)
cnt += 1
flag, frame = vid.read()
这段代码是在处理视频帧,具体来说,它执行以下操作:
frame = mmcv.imresize(frame, (new_w, new_h))
:使用mmcv.imresize
函数调整帧的大小。这里,帧的宽度和高度被设置为new_w
和new_h
,这是通过前面的代码计算得到的。frames.append(frame)
:将调整大小后的帧添加到frames
列表中。frame_path = frame_tmpl.format(cnt + 1)
:使用之前定义的模板frame_tmpl
生成保存帧的文件名。这里使用cnt + 1
作为文件名的占位符,其中cnt
是一个计数器,用于跟踪已经处理的帧数。frame_paths.append(frame_path)
:将生成的文件路径添加到frame_paths
列表中。cv2.imwrite(frame_path, frame)
:使用OpenCV的imwrite
函数将帧保存到指定的文件路径。cnt += 1
:增加计数器cnt
的值,以便下一次迭代时生成下一个文件名。flag, frame = vid.read()
:再次从视频中读取一帧。如果读取成功,则继续循环;否则,循环结束。
这段代码的主要目的是从视频中逐帧提取并保存调整大小后的帧。提取的帧被保存在指定的目录中,并按照指定的文件命名模板进行命名。
所以这可以解答一下前面的问题,short_side的作用到底是什么,它不是减少帧数,而是改变图像的短边的宽度,可以更改看一下它提取的帧数是否发生改变。
可以看到short_side在480的情况下帧数是72帧,我们改变一下短边的大小,变成240
可以看到更改后还是没有变化,依然是72帧,只不过短边变窄,那么为什么图像变的模糊了呢,我认为可能跟你输出的图像有关,输出的图像大小不变,而随着设定的短边变小,相应的就会放大为原来的尺寸,从而导致视频变得模糊。
3)跳回到main函数当中
num_frame = len(frame_paths)
h, w, _ = original_frames[0].shape
可以看到果然是把h,w设置成原始帧第一个帧的大小,而第一个帧并没有进行短边操作,所以变模糊的原因找到了,这里我们可以改成第二帧大小,那么就不会出现模糊的结果。结果却是没有变化依然模糊。
config = mmcv.Config.fromfile(args.config)
这行代码是在使用mmcv.Config
类从指定的配置文件(通常是一个JSON文件)中加载配置信息。这里,args.config
指定了配置文件的路径。
解释一下各个部分:
mmcv.Config
:mmcv
是一个用于计算机视觉任务的库,其中Config
类用于加载和解析配置文件。fromfile()
: 这是Config
类的一个方法,用于从指定的文件中加载配置信息。args.config
: 这是一个变量,通常是通过命令行参数或某种方式传递进来的配置文件路径。
通过调用fromfile()
方法,你可以将配置文件中的设置加载到一个Config
对象中,然后可以使用这个对象来访问或修改这些设置。这在深度学习、计算机视觉和其他机器学习任务中非常常见,因为这些任务通常需要大量的配置参数来调整模型和训练过程。