I have made a motion detection with cv2 which get video as input and as output it returns a csv file contain the time of the motions that happend during the video. the problem is, I have used datetime.now()
for the time that the motion happening but the speed of the video is much more faster. I don't have problem with the speed of the video, I don't know how to say the object moved at this time of the video.
It would be great if you could help me :)
here is the code:
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()
To calculate in video time
you have to know video FPS and curent frame number.
fps = float(self.stream.get(CAP_PROP_FPS))
Then try to calculate in video time
(in seconds) with last frame number :
videotime_s = last_frame_num/fps
Or change it to timedelta if you need
videotime_td = timedelta(seconds=videotime_s)
Now you have relative(to start) video time. If you need absolute time then you can remeber video start time and caluclate each event time
event_dt = videostartime_dt + videotime_td
This method works well for videos with constant framerate. If you have video with dynamic framerate it's more complicated and probably you have to analyze video format(for example h265) and use ffmpeg and more complicated things.