How to get previous frame of a video in opencv python - python

I want to detect obstacles from a video based on their increasing size.To do that first I applied SIFT on gray image to get feature points of current frame. Next to compare the feature points of current frame with the previous frame I want to apply Brute-Force algorithm. For that I want to get feature points in previous frame. How can I access previous frame in opencv python ? and how to avoid accessing previous frame when the current frame is the first frame of the video?
below is the code written in python to get feature points of current frame.
import cv2
import numpy as np
cap = cv2.VideoCapture('video3.mov')
while(cap.isOpened()):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#detect key feature points
sift = cv2.xfeatures2d.SIFT_create()
kp, des = sift.detectAndCompute(gray, None)
#draw key points detected
img=cv2.drawKeypoints(gray,kp,gray,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("grayframe",img)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

You could also get/set the zero-based frame index (CAP_PROP_POS_FRAMES), which might be useful if you wanted flexibility to step back through more than one frame, compare to a specific frame, etc. Note though that this would reset the position for the next read(), so if you really only ever want the previous frame, storing it in a variable per the other answers is probably better.
next_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)
current_frame = next_frame - 1
previous_frame = current_frame - 1
if previous_frame >= 0:
cap.set(cv2.CAP_PROP_POS_FRAMES, previous_frame)
ret, frame = cap.read()

There is no specific function in OpenCV to access the previous frame. Your problem can be solved by calling cap.read() once before entering the while loop. Use a variable prev_frame to store the previous frame just before reading the new frame. Finally, as a good practice, you should verify that the frame was properly read, before doing computations on it. Your code could look something like:
import cv2
import numpy as np
cap = cv2.VideoCapture('video3.mov')
ret, frame = cap.read()
while(cap.isOpened()):
prev_frame=frame[:]
ret, frame = cap.read()
if ret:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#detect key feature points
sift = cv2.xfeatures2d.SIFT_create()
kp, des = sift.detectAndCompute(gray, None)
#some magic with prev_frame
#draw key points detected
img=cv2.drawKeypoints(gray,kp,gray, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("grayframe",img)
else:
print('Could not read frame')
if cv2.waitKey(100) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Simply save the current frame to be the previous frame in the next iteration. Use a list, if you need more than 1.
import cv2
import numpy as np
cap = cv2.VideoCapture('video3.mov')
previousFrame=None
while(cap.isOpened()):
ret, frame = cap.read()
if previousFrame is not None:
#use previous frame here
pass
#save current frame
previousFrame=frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#detect key feature points
sift = cv2.xfeatures2d.SIFT_create()
kp, des = sift.detectAndCompute(gray, None)
#draw key points detected
img=cv2.drawKeypoints(gray,kp,gray,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("grayframe",img)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Related

Compare the X last frames of a live feed/ webcam and highlight their difference

As part of a project, I am trying to create a script that will
detect motion using a camera, and when doing so,
capture some frames of the feed for further analysis.
(But without delaying the actual feed!) Until now I am able to detect movement but without much say to the settings, so I am looking for a better solution.
What I cannot find a way to do is:
Hold on a frame while the feed plays.
What could help me a lot move forward:
a way to store X previous frames. (It will be empty for the first X frames, and afterwards it will be replaced with the a frame rolling frame set.)
or
a way to store a frame X seconds before the current. (It will be empty for the first X seconds, and afterwards it will be replaced with the new frame.)
What I have until now
import cv2, time, pandas # importing OpenCV, time and Pandas library
import threading
from datetime import datetime # importing datetime class from datetime library
My try to capture a previous frame, but it delays the feed:
def CheckFrame():
threading.Timer(100.0 , CheckFrame).start()
check, frame2 = video.read() # second image
return frame2
video = cv2.VideoCapture(0) # Capturing video
#check if connection with camera is successfully
if video.isOpened():
ret, frame = video.read() #capture a frame from live video
#check whether frame is successfully captured
if ret:
# continue to display window until 'q'/Esc is pressed Check end of code
while(True):
check, frame = video.read() #capture a frame from live video
# frame Converting color image to gray_scale image
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# frame Converting gray scale image to GaussianBlur so that change can be find easily
gray = cv2.GaussianBlur(gray, (21, 21), 10)
frame2 = CheckFrame()
# frame2 Converting color image to gray_scale image
gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# frame2 Converting gray scale image to GaussianBlur so that change can be find easily
gray2 = cv2.GaussianBlur(gray2, (21, 21), 10)
# Difference between rame2f and current frame
diff_frame = cv2.absdiff(gray2, gray)
# If change in between static background and current frame is greater than 30 it will show white color(255)
thresh_frame = cv2.threshold(diff_frame, 2, 255, cv2.THRESH_BINARY)[1]
thresh_frame = cv2.dilate(thresh_frame, None, iterations = 1)
# Finding contour of moving object
cnts,_ = cv2.findContours(thresh_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in cnts:
if cv2.contourArea(contour) < 1000:
continue
(x, y, w, h) = cv2.boundingRect(contour)
# making green rectangle around the moving object
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
cv2.imshow("Color Frame", frame) # Displaying color frame with contour of motion of object
#cv2.imshow("Gray Frame", gray) # Displaying image in gray_scale
cv2.imshow("Threshold Frame", thresh_frame) # Displaying the black and white image in which if intensity difference greater than 30 it will appear white
cv2.imshow("Difference Frame", diff_frame) # Displaying the difference in currentframe to the staticframe(very first_frame)
if cv2.waitKey(1) & 0xFF == 27: #press 'Esc' to break out of the loop
#if cv2.waitKey(1) & 0xFF == ord('q'): #press 'q' to break out of the loop
break
#print error if frame capturing was unsuccessful
else:
print("Error : Failed to capture frame")
video.release()
# Destroying all the windows
cv2.destroyAllWindows()
# print error if the connection with camera is unsuccessful
else:
print("Cannot open camera")

Controlling Contrast and Brightness of Video Stream in OpenCV and Python

I’m using OpenCV3 and Python 3.7 to capture a live video stream from my webcam and I want to control the brightness and contrast. I cannot control the camera settings using OpenCV's cap.set(cv2.CAP_PROP_BRIGHTNESS, float) and cap.set(cv2.CAP_PROP_BRIGHTNESS, int) commands so I want to apply the contrast and brightness after each frame is read. The Numpy array of each captured image is (480, 640, 3). The following code properly displays the video stream without any attempt to change the brightness or contrast.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
I get a washed-out video stream when I use Numpy’s clip() method to control the contrast and brightness, even when I set contrast = 1.0 (no change to contrast) and brightness = 0 (no change to brightness). Here is my attempt to control contrast and brightness.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
contrast = 1.0
brightness = 0
frame = np.clip(contrast * frame + brightness, 0, 255)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
How can I control the contrast and brightness of a video stream using OpenCV?
I found the solution using the numpy.clip() method and #fmw42 provided a solution using the cv2.normalize() method. I like the cv2.normalize() solution slightly better because it normalizes the pixel values to 0-255 rather than clip them at 0 or 255. Both solutions are provided here.
The cv2.normalize() solution:
Brightness - shift the alpha and beta values the same amount. Alpha
can be negative and beta can be higher than 255. (If alpha >= 255,
then the picture is white and if beta <= 0, then the picure is black.
Contrast - Widen or shorten the gap between alpha and beta.
Here is the code:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
cv2.normalize(frame, frame, 0, 255, cv2.NORM_MINMAX)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
The numpy.clip() solution:
This helped me solve the problem: How to fast change image brightness with python + OpenCV?. I need to:
Convert Red-Green Blue (RGB) to Hue-Saturation-Value (HSV) first
(“Value” is the same as “Brightness”)
“Slice” the Numpy array to the Value portion of the Numpy array and adjust brightness and contrast on that slice
Convert back from HSV to RGB.
Here is the working solution. Vary the contrast and brightness values. numpy.clip() ensures that all the pixel values remain between 0 and 255 in each on the channels (R, G, and B).
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
contrast = 1.25
brightness = 50
frame[:,:,2] = np.clip(contrast * frame[:,:,2] + brightness, 0, 255)
frame = cv2.cvtColor(frame, cv2.COLOR_HSV2BGR)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
import cv2 as cv
cap = cv.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# normalize the frame
frame = cv.normalize(
frame, None, alpha=0, beta=255, norm_type=cv.NORM_MINMAX, dtype=cv.CV_8UC1
)
# Display the resulting frame
cv.imshow("frame", frame)
# press q to quit
if cv.waitKey(1) & 0xFF == ord("q"):
break

Get a frame from a live video stream

What would you have to do to get a single frame from a live webcam feed and update it repeatedly to a output file? I have seen this done before so i know it is possible. I want to use something like Python if possible but any help is welcome. Maybe this is possible using OpenCV?
This should meet your requirements of "Saving each frame from the video feed "
import numpy as np
import cv2
import random
cap = cv2.VideoCapture(0)
i=0
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
i+=1
cv2.imwrite('database/{index}.png'.format(index=i),frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
In Code . database is the directory where every frame will be saved through index(i) iteration.
OpenCV should be able to do this pretty easily:
import numpy as np
import cv2
cap = cv2.VideoCapture(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)
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
Source: http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_gui/py_video_display/py_video_display.html

get frame from video with CV_CAP_PROP_POS_FRAMES in opencv python

I am trying to detect a (photography) flash in a video using OpenCV.
I detected the frame in which the flash occurs (average brightness above a threshold) and now I'd like to get the frame number.
I tried using CV_CAP_PROP_POS_FRAMES from the OpenCV docs without any success.
import numpy as np
import cv2
cap = cv2.VideoCapture('file.MOV')
while(cap.isOpened()):
ret, frame = cap.read()
BW = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
average = np.average(v) #computes the average brightness
if average > 200: #flash is detected
cv2.imshow('frame',BW)
frameid = cap.get(CV_CAP_PROP_POS_FRAMES) # <--- this line does not work
print(frameid)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Any tips ?
You can either:
Use cap.get(cv2.CAP_PROP_POS_FRAMES) (see here, also), or
increment a variable at each iteration: its current value is the current frame number
From opencv-doc:
When querying a property that is not supported by the backend used by the VideoCapture class, value 0 is returned
Probably it is not supported. In that case you have to count the frame number yourself.

openCV VideoCapture is several frames behind

I am making a program that uses a webcam to track objects in real time. The resulting display is always a few frames behind. For an example, when I move the camera to point at a new spot, it still shows the first position for a few frames.
Here is my program, it should find the circles in the frame and return an image with them circled:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles() # parameters removed
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
#draw circle
cv2.circle() # parameters removed
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0XFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
As you can see it takes some time to process each frame. I expected the it to be choppy, but the result shows images from several seconds ago.

Categories

Resources