Annotating video frames with a label based on state - python

I have a bunch of videos and depthmaps showing human poses from the Microsoft Kinect.
I can get a skeleton of the human in the video but what I want to do is recognize a certain pose from this skeleton data.
To do that I need to annotate each frame in the videos with a 0 or 1, corresponding to "bad pose" and "good pose", i.e. the frame has a binary state variable.
I want to be able to playback the avi file in matlab and then press space to switch between these two states and simultaneously add the state variable to an array giving the state for each frame in the video.
Is there a tool in matlab that can do this? Otherwise matlab is not a restriction, python, C++ or any other language is fine.
I have been googling around, and most of the stuff I have found is to annotate individual frames with a polygon. I want to do this at maybe half the regular framerate of the video.
EDIT: I used the solution provided by miindlek and decided to share a few things if someone runs into this. I needed to see in the video what annotation I was assigning to each frame, so I made a small circle in the upper left corner of the video as I displayed it. Hopefully this will be useful for someone else later. I also capture the key pressed with waitKey and then do something based on the output. This allows for multiple keys to be pressed during the annotations.
import numpy as np
import cv2
import os
os.chdir('PathToVideo')
# Blue cicle means that the annotation haven't started
# Green circle is a good pose
# Red is a bad pose
# White circle means we are done, press d for that
# Instructions on how to use!
# Press space to swap between states, you have to press space when the person
# starts doing poses.
# Press d when the person finishes.
# press q to quit early, then the annotations are not saved, you should only
# use this if you made a mistake and need to start over.
cap = cv2.VideoCapture('Video.avi')
# You can INCREASE the value of speed to make the video SLOWER
speed = 33
# Start with the beginning state as 10 to indicate that the procedure has not started
current_state = 10
saveAnnotations = True
annotation_list = []
# We can check wether the video capture has been opened
cap.isOpened()
colCirc = (255,0,0)
# Iterate while the capture is open, i.e. while we still get new frames.
while(cap.isOpened()):
# Read one frame.
ret, frame = cap.read()
# Break the loop if we don't get a new frame.
if not ret:
break
# Add the colored circle on the image to know the state
cv2.circle(frame,(50,50), 50, colCirc, -1)
# Show one frame.
cv2.imshow('frame', frame)
# Wait for a keypress and act on it
k = cv2.waitKey(speed)
if k == ord(' '):
if current_state==0:
current_state = 1
colCirc = (0,0,255)
else:
current_state = 0
colCirc = (0,255,0)
if current_state == 10:
current_state = 0
colCirc = (0,255,0)
if k == ord('d'):
current_state = 11
colCirc = (255,255,255)
# Press q to quit
if k == ord('q'):
print "You quit! Restart the annotations by running this script again!"
saveAnnotations = False
break
annotation_list.append(current_state)
# Release the capture and close window
cap.release()
cv2.destroyAllWindows()
# Only save if you did not quit
if saveAnnotations:
f = open('poseAnnot.txt', 'w')
for item in annotation_list:
print>>f, item
f.close()

One way to solve your task is using the opencv library with python, as described in this tutorial.
import numpy as np
import cv2
cap = cv2.VideoCapture('video.avi')
current_state = False
annotation_list = []
while(True):
# Read one frame.
ret, frame = cap.read()
if not ret:
break
# Show one frame.
cv2.imshow('frame', frame)
# Check, if the space bar is pressed to switch the mode.
if cv2.waitKey(1) & 0xFF == ord(' '):
current_state = not current_state
annotation_list.append(current_state)
# Convert the list of boolean values to a list of int values.
annotation_list = map(int, annotation_list)
print annotation_list
cap.release()
cv2.destroyAllWindows()
The variable annotation_list contains all annotations for each frame. To switch between the two modes, you have to press the space bar.

Related

OpenCV Recorded webcam-video is faster than real life Python

I am reaching some problems recording my video from the webcam. Because I am doing an experiment and at the same time recording the video, it is very important that the real second is the same as the second recorded.
The code I am using is this one:
def record_video(self, path_video="test"):
vid_capture = cv2.VideoCapture(0)
#vid_capture.set(cv2.CAP_PROP_FPS, 20)
fps=vid_capture.get(cv2.CAP_PROP_FPS)
#vid_capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)
vid_cod = cv2.VideoWriter_fourcc(*'XVID')
output = cv2.VideoWriter("experiment_videos/" + path_video + ".avi", vid_cod, fps, (640,480))
x = threading.Thread(target=socket_trigger)
x.daemon = True
x.start()
print("Waiting")
while(start==0):
ret_cam, frame_cam = vid_capture.read()
while (True):
ret_cam, frame_cam = vid_capture.read()
output.write(frame_cam)
# Close and break the loop after pressing "x" key
if cv2.waitKey(1) & 0XFF == ord('x'):
break
if end== 1:
break
# close the already opened camera
vid_capture.release()
#cap.release()
# close the already opened file
output.release()
# close the window and de-allocate any associated memory usage
cv2.destroyAllWindows()
All code works, the flag variables that I receive work properly. The problem comes when, for instance, if I record a video of 5 mins (real time), the output can be 4:52,4:55 or even 5:00. It's just not exact.
I think it's because I write in a output file of 30fps (that's what vid_capture.get(cv2.CAP_PROP_FPS) returns) and my camera sometimes is recording in less frames(let's say 28,29).
I don't know what to do, I have tried setting fps of the cameras at 20 but it didn't work (#vid_capture.set(cv2.CAP_PROP_FPS, 20)).
Any ideas? For me is so critical matching times, and my only job is to record a webcam camera.
Thanks for all,
Jaime

Record two set of point location from mouse event from first frame of a video

I have a video of the cow farm. My objectives are -
(a) get the location of the corners of the cow pen (cowhouse)
(b) get the corners of the food container
Here is my approach I am thinking about-
(a) - capture the frame and freeze on the 1st frame
- user will manually put the mouse on the corners
- the x,y location will be saved in a list
- press "p" key to proceed to the next frame
(b) - freeze the frame on the second frame
- user will manually put the mouse on the corners
- the x,y location will be saved in another list
- press "c" key to proceed to next frames
I already have other codes to carry out other operations. I tried the following codes to get point from an image (not video). Now sure how to pause the video and use the existing frame as the input image
import cv2, numpy as np
ix,iy = -1,-1
# the list of locations
mouse = []
def get_location(event,x,y,flags,param):
global ix,iy
if event == cv2.EVENT_LBUTTONDBLCLK:
ix,iy = x,y
mouse.append([x,y])
# take image and name it
img = cv2.imread("colo.png",0)
cv2.namedWindow('image')
cv2.setMouseCallback('image',get_location)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(20) & 0xFF
if k == 27:
break
elif k == ord('a'):
print (ix,iy)
print (mouse)
cv2.destroyAllWindows()
The answers I am looking for are - (a) how to freeze the frame on a specific frame number and (b) cv2.setMouseCallback('image',get_location) is taking a string as the first argument, how to insert the frame as argument here?
a) use a variable to set the waitKey to 0. Only after a key press the next frame will be shown. Change the variable after "c" is pressed, so the video runs normally:
waitTime = 0
k = cv2.waitKey(waitTime)
if k == ord('c'):
waitTime = 20
b) the string argument is the name of the window where the callback is attached to. To 'insert the frame', just call imshow on the window. The code you have seems fine in that regard.

Keep the code running while a video is displayed

So I am trying to code up something that keeps a video running until a condition is met and some processes are done and new video is loaded immediately after these processes. These processes should continue without closing the current video and should only close the current video when the new video is loaded and ready for vizualization.
This is best formulated by an example as given below:
import numpy as np
import os
import pygame
import cv2
import time
def play_video(vid_loc):
pygame.init()
infos = pygame.display.Info()
screen_size = (infos.current_w, infos.current_h)
cap = cv2.VideoCapture(vid_loc)
frame_counter =0
while(True):
ret, frame = cap.read()
frame_counter += 1
if frame_counter == cap.get(cv2.CAP_PROP_FRAME_COUNT):
frame_counter = 0
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
frame= cv2.resize(frame,screen_size)
cv2.namedWindow('image', flags=cv2.WINDOW_GUI_NORMAL)
cv2.setWindowProperty("image", cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
cv2.imshow('image',frame)
if cv2.waitKey(1000) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
vid_loc = ["home/odd.ogv", "home/even.ogv"]
while True:
n = random.randint(1, 100)
if n%2 == 0:
play_video(vid_loc[1])
else:
play_video(vid_loc[0])
time.sleep(10)
So this code generates a random number and checks if it is a even number or not. If even it runs a different video and if odd another video. My expectation with this code was to keep the random number being generated every
10 second and keep the video running while the "while loop" runs again , generates another random number and checks if it is even or not without closing the video. If the number is odd , another video is run immediately after current video is closed. However this code would just keep the video running in loop as intended but does not generate another random number.
It basically gets stuck at cv2.imshow until "q" key is pressed and only then the "while loop" runs again.

OpenCV frame count wrong for interlaced videos, workaround?

Working with the code sample from How does QueryFrame work? I noticed that the program used a lot of time to exit if it ran to the end of the video. I wanted to exit quickly on the last frame, and I verified that it's a lot quicker if I don't try to play past the end of the video, but there are some details that don't make sense to me. Here's my code:
import cv2
# create a window
winname = "myWindow"
win = cv2.namedWindow(winname, cv2.CV_WINDOW_AUTOSIZE)
# load video file
invideo = cv2.VideoCapture("video.mts")
frames = invideo.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT)
print "frame count:", frames
# interval between frame in ms.
fps = invideo.get(cv2.cv.CV_CAP_PROP_FPS)
interval = int(1000.0 / fps)
# play video
while invideo.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) < frames:
print "Showing frame number:", invideo.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
(ret, im) = invideo.read()
if not ret:
break
cv2.imshow(winname, im)
if cv2.waitKey(interval) == 27: # ASCII 27 is the ESC key
break
del invideo
cv2.destroyWindow(winname)
The only thing is that the frame count returned is 744, while the last played frame number is 371 (counting from 0, so that's 372 frames). I assume this is because the video is interlaced, and I guess I need to account for that and divide interval by 2 and frames by 2. But the question is, how do I figure out that I need to do this? There doesn't seem to be a property to check this:
http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get

Save Video as Frames OpenCV{PY}

I would like to create a program which saves .jpg images taken from the webcam(frames).
What my program do for now is, opening a webcam, taking one and only one frame, and then everything stops.
What i would like to have is more than one frame
My error-code is this one:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
count = 0
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imwrite("frame%d.jpg" % ret, frame) # save frame as JPEG file
count +=1
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(10):
break
Actually it sounds like you are always saving your image with the same name
because you are concatenating ret instead of count in the imwrite method
try this :
name = "frame%d.jpg"%count
cv2.imwrite(name, frame) # save frame as JPEG file
use this -
count = 0
cv2.imwrite("frame%d.jpg" % count, frame)
count = count+1
When no key is pressed and the time delay expires, cv2.waitKey returns -1. You can check it in the doc.
Basically, all you have to do is changing slightly the end of your program:
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(10) != -1:
break
Though this is late I have to say that prtkp's answer is what you needed... the , ret value you use to enumerate your images is wrong. Ret is only a boolean... so while it detects the image it its placing a one there for the name of the image...
I just used this... with a c=0 on the header
cv2.imwrite("img/frame %d.jpg" % c,img)
c=c+1

Categories

Resources