如何在OpenCV中获取视频内运动事件的实际播放时间
运动检测程序的视频时间记录问题
我用OpenCV实现了一个运动检测程序,输入是视频,输出包含运动发生时间的CSV文件。现在的问题是,我用datetime.now()记录运动发生的时间,但视频播放速度比实际快,导致无法准确记录视频实际播放时间,求解决办法。
原代码
def press_it(): STime=0 FTime=0 moji = True first_frame = None status_list = [None,None] times = [] startTime=datetime.now() print(startTime) #Dataframe to store the time values during which object detection and movement appears | "C:/Users/mojta/Desktop/videos/pred.mp4" df = pd.DataFrame(columns=['Start','End','Duration']) cam = cv2.VideoCapture(file) frames = cam.get(cv2.CAP_PROP_FRAME_COUNT) fps = cam.get(cv2.CAP_PROP_FPS) seconds = round(frames / fps) length = int(cam.get(cv2.CAP_PROP_FRAME_COUNT)) print(length) y=int(values["-IN4-"]) x=int(values["-IN3-"]) h= int(values["-IN5-"]) w= int(values["-IN6-"]) #Iterate through frames and display the window while cam.isOpened(): check, frame = cam.read() length-=1 if moji==True: STime=datetime.now() moji=False frame = frame[y:y+h, x:x+w] #Status at beginning of the recording is zero as the object is not visisble status = 0 #Converting each frame into gray scale image gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #Convert grayscale image to GaussianBlur gray = cv2.GaussianBlur(gray, (21,21), 0) #This is used to store the first image/frame of the video if first_frame is None or length%500==0: first_frame = gray continue #Calculates the difference between the first frame and another frames delta_frame = cv2.absdiff(first_frame,gray) #Giving a threshold value, such that it will convert the difference value with less than 30 to black #If it is greater than 30, then it will convert those pixels to white _,thresh_delta = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY) thresh_delta = cv2.dilate(thresh_delta, None, iterations=3) #Defining the contour area i.e., borders cnts,_ = cv2.findContours(thresh_delta.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #Removes noises and shadows, i.e., it will keep only that part white, which has area greater than 10000 pixels Acuraccy = acuraccySlider for cont in cnts: if cv2.contourArea(cont) < Acuraccy: continue #Change in status when the object is being detected status = 1 #creates a rectangular box around the object in the frame (x1, y1, w1, h1) = cv2.boundingRect(cont) cv2.rectangle(frame, (x1,y1), (x1+w1,y1+h1), (0,0,255), 3) #List of status for every frame status_list.append(status) status_list = status_list[-2:] #Record datetime in a list when change occurs if status_list[-1]==1 and status_list[-2]==0: times.append(datetime.now()-startTime) if status_list[-1]==0 and status_list[-2]==1: times.append(datetime.now()-startTime) #Opening all types of frames/images cv2.imshow("Grey Scale",gray) cv2.imshow("Delta", delta_frame) cv2.imshow("Threshold", thresh_delta) cv2.imshow("Colored frame",frame) last_frame_num = cam.get(cv2.CAP_PROP_FRAME_COUNT) #Generate a new frame after every 1 millisecond key = cv2.waitKey(1) #If entered 'q' on keyboard, breaks out of loop, and window gets destroyed print(length) if key == ord('q') or length<=10: if status==1: times.append(datetime.now()-startTime) FTime=datetime.now() break #Store time values in a Dataframe DURATION=FTime-STime FINAL = DURATION/seconds for i in range(0,len(times),2): if len(times)%2==1 and i==len(times)-1: break df = df.append({'Start':times[i],'End':times[i+1],'Duration':(times[i+1]-times[i])}, ignore_index=True) #Write the dataframe to a CSV file df.to_csv("Times.csv") cam.release() #Closes all the windows cv2.destroyAllWindows() window.Close()
解决方法
核心问题是用系统时间记录会受播放速度影响,改用视频帧序号 + 帧率计算视频内的实际时间,完全不受播放快慢干扰。
具体修改:
- 初始化帧计数器:在打开视频后添加帧计数变量,获取视频FPS
- 计算当前视频时间:每读取一帧就更新计数器,用
帧计数器 / FPS得到当前视频的实际播放时间(单位:秒) - 替换时间记录逻辑:把所有
datetime.now()-startTime的地方换成计算出的视频时间
修改后的完整代码:
def press_it(): STime=0 FTime=0 moji = True first_frame = None status_list = [None,None] times = [] df = pd.DataFrame(columns=['Start','End','Duration']) cam = cv2.VideoCapture(file) frames = cam.get(cv2.CAP_PROP_FRAME_COUNT) fps = cam.get(cv2.CAP_PROP_FPS) seconds = round(frames / fps) length = int(cam.get(cv2.CAP_PROP_FRAME_COUNT)) print(length) y=int(values["-IN4-"]) x=int(values["-IN3-"]) h= int(values["-IN5-"]) w= int(values["-IN6-"]) # 新增帧计数器 frame_count = 0 #Iterate through frames and display the window while cam.isOpened(): check, frame = cam.read() if not check: break length-=1 frame_count += 1 # 计算当前视频的实际播放时间(秒) current_video_time = frame_count / fps if moji==True: STime=current_video_time moji=False frame = frame[y:y+h, x:x+w] status = 0 gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (21,21), 0) if first_frame is None or length%500==0: first_frame = gray continue delta_frame = cv2.absdiff(first_frame,gray) _,thresh_delta = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY) thresh_delta = cv2.dilate(thresh_delta, None, iterations=3) cnts,_ = cv2.findContours(thresh_delta.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) Acuraccy = acuraccySlider for cont in cnts: if cv2.contourArea(cont) < Acuraccy: continue status = 1 (x1, y1, w1, h1) = cv2.boundingRect(cont) cv2.rectangle(frame, (x1,y1), (x1+w1,y1+h1), (0,0,255), 3) status_list.append(status) status_list = status_list[-2:] # 替换时间记录逻辑 if status_list[-1]==1 and status_list[-2]==0: times.append(current_video_time) if status_list[-1]==0 and status_list[-2]==1: times.append(current_video_time) cv2.imshow("Grey Scale",gray) cv2.imshow("Delta", delta_frame) cv2.imshow("Threshold", thresh_delta) cv2.imshow("Colored frame",frame) key = cv2.waitKey(1) print(length) if key == ord('q') or length<=10: if status==1: times.append(current_video_time) FTime=current_video_time break # 更新时长计算逻辑 DURATION=FTime-STime for i in range(0,len(times),2): if len(times)%2==1 and i==len(times)-1: break df = df.append({'Start':times[i],'End':times[i+1],'Duration':(times[i+1]-times[i])}, ignore_index=True) df.to_csv("Times.csv") cam.release() cv2.destroyAllWindows() window.Close()
额外说明:
- 计算出的
current_video_time是视频内的实际播放时间,和系统播放速度无关,哪怕逐帧播放,记录的时间依然是视频本身的进度 - 如果需要更易读的时间格式,可以把秒数转成
datetime.timedelta类型,比如timedelta(seconds=current_video_time),CSV中的时间会显示为00:00:XX格式
内容的提问来源于stack exchange,提问作者MojtabaMAleki02
相关产品推荐
相关产品推荐

