思考了好几天,今天准备写一下关于图片和视频关联处理的工具,首先定义MyFile类,它代表了文件拥有的一般属性和方法,代码如下:
import os
import shutil
import datetime
class MyFile():
def __init__(self,path,name,create_time):
self.file_path=path
self.file_name=name
self.create_time=create_time
def judge_name(self,newname):
if newname=='':
return self.file_name
if len(newname.split('.'))==1:
s=self.file_name.split('.')[-1]
return newname+'.'+s
return newname
def rename(self,newname):
oldfullname=os.path.join(self.file_path,self.file_name)
self.file_name=self.judge_name(newname)
file_fullname=os.path.join(self.file_path,self.file_name)
os.rename(oldfullname,file_fullname)
def get_fullname(self):
return os.path.join(self.file_path,self.file_name)
def get_name(self):
return self.file_name
def get_path(self):
return self.file_path
def get_createTime(self):
return self.create_time
def copyto(self,dist_path,newname=''):
newname=self.judge_name(newname)
shutil.copyfile(os.path.join(self.file_path,self.file_name),os.path.join(dist_path,newname))
return MyFile(dist_path,newname,self.create_time)
def moveto(self,dist_path,newname=''):
newname=self.judge_name(newname)
shutil.move(os.path.join(self.file_path,self.file_name),os.path.join(dist_path,newname))
self.file_path=dist_path
self.file_name=newname
def delete(self):
os.remove(self.get_fullname())
self.file_path = ''
self.file_name = ''
self.create_time = ''
def get_date(self):
# 返回该文件创建时间的周计数和周内秒计数(以2020年元旦的0点为起点)
time_ref=datetime.datetime.strptime('20200101_000000','%Y%m%d_%H%M%S')
time_file = datetime.datetime.strptime(self.create_time, '%Y%m%d_%H%M%S')
week_count=int((time_file-time_ref).total_seconds()/604800)
week_second_count=int((time_file-time_ref).total_seconds()%604800)
return week_count,week_second_count
其次是Picture类和Video类,这两个类继承自文件类,并拥有各自特色的属性和方法,如下所示:
Video类:
from myfile import MyFile
import cv2
class Video(MyFile):
def __init__(self,path,name,create_time):
super().__init__(path,name,create_time)
def get_video_prop(self,prop):
cap=cv2.VideoCapture(self.get_fullname())
p=cap.get(prop)
cap.release()
return p
def get_frames(self):
return int(self.get_video_prop(cv2.CAP_PROP_FRAME_COUNT))
def get_FPS(self):
return int(self.get_video_prop(cv2.CAP_PROP_FPS))
def get_time_span(self):
return self.get_frames()/self.get_FPS()
def copyto(self,dist_path,newname=''):
file=super().copyto(dist_path,newname)
return Video(file.get_path(),file.get_name(),file.get_createTime())
Picture类:
from myfile import MyFile
class Picture(MyFile):
def __init__(self,path,name,create_time,video=None,frame=-1):
super().__init__(path,name,create_time)
self.bind_video(video,frame)
def bind_video(self,video,frame):
self.parent_video=video
self.frame=frame
def copyto(self,dist_path,newname=''):
file=super().copyto(dist_path,newname)
return Picture(file.get_path(),file.get_name(),file.get_createTime(),video=self.parent_video,frame=self.frame)
def get_parent_video(self):
return self.parent_video
def get_frame(self):
return self.frame
这几个基础类定义好之后就可以使用它们了,本文假设图片是从视频中截图的某帧数据,现在要求把图片和所属视频进行关联,定义PVTopo类如下:
from video import Video
from picture import Picture
import os
class PVTopo():
def __init__(self,pic_path_list,video_path_list,pic_style,v_style):
self.pic_path_list=pic_path_list
self.video_path_list=video_path_list
self.pv_list=[]
self.nomatch_list=[]
self.pic_style=pic_style
self.v_style=v_style
def pic_video(self,pic,v):
pic_time_w,pic_time_s=pic.get_date()
v_start_time_w,v_start_time_s=v.get_date()
v_time_span=v.get_time_span()
tt=(pic_time_w-v_start_time_w)*604800+(pic_time_s-v_start_time_s)
if tt>0 and tt
pic.bind_video(v,tt)
return True
return False
def get_pic(self,pic_handel,video_handle,):
for i in range(len(self.pic_path_list)):
pic_list=[Picture(self.pic_path_list[i],p,pic_handel(p)) for p in os.listdir(self.pic_path_list[i]) if p.split('.')[-1].upper()==self.pic_style.upper()]
video_list=[Video(self.video_path_list[i],v,video_handle(v)) for v in os.listdir(self.video_path_list[i]) if v.split('.')[-1].upper()==self.v_style.upper()]
for pic in pic_list:
for v in video_list:
if self.pic_video(pic,v):
self.pv_list.append(pic)
break
if not pic.get_parent_video():
self.nomatch_list.append(pic)
return self.pv_list,self.nomatch_list
由于图片的创建时间可能是一各种形式出现的,因此为了保证PVTopo类的适用范围更广,采用python的lambda表达式对创建时间进行处理,这里假定图片和视频的创建时间都是其名称的第二、三部分,因此可以使用同一个lambda表达式。现在定义orPVTopo类(继承自PVTopo类)如下:
Picture类po import PVTopo
class orPVTopo(PVTopo):
def __init__(self,pic_path_list,video_path_list):
super().__init__(pic_path_list,video_path_list,pic_style='JPG',v_style='mp4')
def get_time(self,pic):
nosense,date,time,*_=pic.split('_')
return date+'_'+time
def get_pic(self):
handle=lambda x:self.get_time(x)
return super().get_pic(handle,handle)
接下来在orPVTopo所属文件中进行测试这个类,先创建一些视频和图片:
测试代码如下:
if __name__=='__main__':
pic_path_list=[r'C:\Users\43880\Desktop\result\pic']
video_path_list=[r'C:\Users\43880\Desktop\result']
tp=orPVTopo(pic_path_list,video_path_list)
pic_list,nomatch_list=tp.get_pic()
print('匹配结果如下:')
for pic in pic_list:
print(pic.get_fullname())
print(pic.get_parent_video().get_fullname())
print('-----------------')
print('未匹配上的图片个数有{}个'.format(len(nomatch_list)))
print('下面移动其中一个图片关联的视频,并打印与其同属一个视频的另一张图片所关联的视频名称是否变化')
pic_list[0].get_parent_video().moveto(r'C:\Users\43880\Desktop\result\pic\test','123')
print(pic_list[1].get_parent_video().get_fullname())
本段代码将匹配成功的图片和视频进行配对输出,并输出未匹配上的图片列表中图片的个数,
由于测试图片中微信图片_20200102_121213_.jpg和微信图片_20200102_121214_.jpg都属于视频ch1_20200102_121212_.mp4,所以通过其中一个图片对象将该视频对象移动到另一个目录,查看另一个图片对象所关联的视频对象是否也变化了,结果如下:
匹配结果如下:
C:\Users\43880\Desktop\result\pic\微信图片_20200102_121213_.jpg
C:\Users\43880\Desktop\result\ch1_20200102_121212_.mp4
-----------------
C:\Users\43880\Desktop\result\pic\微信图片_20200102_121214_.jpg
C:\Users\43880\Desktop\result\ch1_20200102_121212_.mp4
-----------------
C:\Users\43880\Desktop\result\pic\微信图片_20200102_131213_.jpg
C:\Users\43880\Desktop\result\ch1_20200102_131212_.mp4
-----------------
C:\Users\43880\Desktop\result\pic\微信图片_20200102_141213_.jpg
C:\Users\43880\Desktop\result\ch1_20200102_141212_ .mp4
-----------------
C:\Users\43880\Desktop\result\pic\微信图片_20200102_151213_.jpg
C:\Users\43880\Desktop\result\ch1_20200102_151212_.mp4
-----------------
未匹配上的图片个数有1个
下面移动其中一个图片关联的视频,并打印与其同属一个视频的另一张图片所关联的视频名称是否变化
C:\Users\43880\Desktop\result\pic\test\123.mp4
可见,多个图片关联同一视频,若其中一个图片对该视频进行了处理,会同步更新到其它图片。