Is it possible to read frames from a video in steps (eg I want to read every fifth frame of a video stream). Currently I'm doing this as a workaround but it's not very effecient.
bool bSuccess
int FramesSkipped = 5;
for (int a = 0; < FramesSkipped; a++)
bSuccess = cap.read(NextFrameBGR);
Any suggestions so I do not have to loop through the five frames to get the desired frame?
I'm afraid there's not much you can do and it's not just a shortcoming of OpenCV. You see, modern video codecs, are, generally, complex beasts. To get a higher compression rate the encoding of a frame is often dependent on previous and sometimes even successive frames.
So, most of the time you have to decode frames before the desired one even if you don't need them.
There are rather non-trivial tricks to specifically encode a video file, so that it would be cheap to get every Nth frame, but it's not feasible in general case.
That said, you can try the seeking functionality OpenCV provides (see OpenCV Seek Function/Rewind). It may (as well as may not) work faster depending on the circumstances. However, personally, I wouldn't bet on it.
I've had success in Python 3 using a simple counter and setting the capture to that counter's frame, as follows:
import cv2
cap = cv2.VideoCapture('XYZ.avi')
# For streams:
# cap = cv2.VideoCapture('rtsp://url.to.stream/media.amqp')
# Or e.g. most common ID for webcams:
# cap = cv2.VideoCapture(0)
count = 0
while cap.isOpened():
ret, frame = cap.read()
if ret:
cv2.imwrite('frame{:d}.jpg'.format(count), frame)
count += 30 # i.e. at 30 fps, this advances one second
cap.set(cv2.CAP_PROP_POS_FRAMES, count)
else:
cap.release()
break
I've tried to find a way to make this a little more pythonic using a with statement but I don't believe the CV2 library has been updated for it.
I got it to work in Python... See below for two sample use cases and some caveats.
# First, import some packages
import cv2
import math
import numpy as np
# Make sure that the print function works on Python 2 and 3
from future import print_function
# Capture every n seconds (here, n = 5)
#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success, image = vidcap.read()
#################### Setting up parameters ################
seconds = 5
fps = vidcap.get(cv2.CAP_PROP_FPS) # Gets the frames per second
multiplier = fps * seconds
#################### Initiate Process ################
while success:
frameId = int(round(vidcap.get(1))) #current frame number, rounded b/c sometimes you get frame intervals which aren't integers...this adds a little imprecision but is likely good enough
success, image = vidcap.read()
if frameId % multiplier == 0:
cv2.imwrite("FolderSeconds/frame%d.jpg" % frameId, image)
vidcap.release()
print("Complete")
# Alternatively, capture every n frames (here, n = 10)
#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success, image = vidcap.read()
#################### Setting up parameters ################
#OpenCV is notorious for not being able to good to
# predict how many frames are in a video. The point here is just to
# populate the "desired_frames" list for all the individual frames
# you'd like to capture.
fps = vidcap.get(cv2.CAP_PROP_FPS)
est_video_length_minutes = 3 # Round up if not sure.
est_tot_frames = est_video_length_minutes * 60 * fps # Sets an upper bound # of frames in video clip
n = 5 # Desired interval of frames to include
desired_frames = n * np.arange(est_tot_frames)
#################### Initiate Process ################
for i in desired_frames:
vidcap.set(1, i-1)
success, image = vidcap.read(1) # image is an array of array of [R,G,B] values
frameId = vidcap.get(1) # The 0th frame is often a throw-away
cv2.imwrite("FolderFrames/frame%d.jpg" % frameId, image)
vidcap.release()
print("Complete")
That's pretty much it.
Some unfortunate caveats... depending on your version of `opencv` (this is built for `opencv` V3), you may need to set the fps variable differently. See [here][1] for details. To find out your version, you can do the following:
major_ver, minor_ver, subminor_ver = cv2.__version__.split('.')
print(major_ver)
I encountered the same problem.
All i did was this:
import cv2
vs = cv2.VideoCapture("<path of your video>.mp4")
print("Showing frames...")
c=1
while True:
grabbed, frame = vs.read()
if c%5==0:
cv2.imshow('Frame',frame)
cv2.waitKey(1)
c+=1
vs.release()
You should use the grab function to move to next frame. And only use retrieve to decode the frame you need.
bool bSuccess
int FramesSkipped = 5;
for (int a = 0; < FramesSkipped; a++)
bSuccess = cap.grab();
bSuccess = cap.retrieve(NextFrameBGR);
Here is what I suggest:
CvCapture* capture = cvCaptureFromFile("input_video_path");
int loop = 0;
IplImage* frame = NULL;
Mat matframe;
char fname[20];
do {
frame = cvQueryFrame(capture);
matframe = cv::cvarrToMat(frame);
cvNamedWindow("video_frame", CV_WINDOW_AUTOSIZE);
cvShowImage("video_frame", frame);
sprintf(fname, "frame%d.jpg", loop);
cv::imwrite(fname, matframe);//save each frame locally
loop++;
cvWaitKey(100);
} while( frame != NULL );
Now that you have saved all the frames locally you can quickly read the nth frame that you want.
CATUION:A sample video of 12 secs I had was composed of >200 images. This will eat up lot of space.
A simple yet effective optimization will be to read the nth frame using the approach that you are using or the one suggested by #sergie. After this you can save the image with its index so that later query at same index will return the saved image rather than having to skip frames like you are. This way you will save the space that you would have wasted in saving frames that you wouldn't have queried and time taken to read & save those unwanted frames aswell.
When I had the same goal with OpenCV, I just tuned around the number of "keyframes" I wanted per second of video, regardless of the frame rate or total number of frames. So, this gets me the N-th key given my target KPS.
# python3.6 code using OpenCV 3.4.2
import cv2
KPS = 5 # Target Keyframes Per Second
VIDEO_PATH = "path/to/video/folder" # Change this
IMAGE_PATH = "path/to/image/folder" # ...and this
EXTENSION = ".png"
cap = cv2.VideoCapture(VIDEO_PATH)
# Set frames-per-second for capture
fps = round(cap.get(cv2.CAP_PROP_FPS))
hop = round(fps / KPS)
curr_frame = 0
while(True):
ret, frame = cap.read()
if not ret: break
if curr_frame % hop == 0:
print('Creating... {0}'.format(name,))
name = IMAGE_PATH + "_" + str(curr_frame) + EXTENSION
cv2.imwrite(name, frame)
curr_frame += 1
cap.release()
Note that I'm rolling through all the frames, but only writing the N-th frame using hop as N.
I use this repo!
Main idea is:
main.py
from camera import VideoCam
SKIPFRAME = 8
url = 0
v1 = VideoCam(url)
v1.check_camera(v1.cap)
ct = 0
while True:
ct += 1
try:
ret = v1.cap.grab()
if ct % SKIPFRAME == 0: # skip some frames
ret, frame = v1.get_frame()
if not ret:
v1.restart_capture(v1.cap)
v1.check_camera(v1.cap)
continue
# frame HERE
v1.show_frame(frame, 'frame')
except KeyboardInterrupt:
v1.close_cam()
exit(0)
camera.py
import cv2
import logging
class VideoCam():
def __init__(self, url=0):
self.url = url
self.cap = cv2.VideoCapture(self.url)
self.get_frame()
self.get_frame_read()
logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)
def check_camera(self, cap):
logging.info('Camera {} status: {}'.format(self.url, cap.isOpened()))
def show_frame(self, frame, name_fr='NAME'):
cv2.imshow(name_fr, frame)
# cv2.imshow(name_fr, cv2.resize(frame, (0, 0), fx=0.4, fy=0.4))
cv2.waitKey(1)
def get_frame(self):
return self.cap.retrieve()
def get_frame_read(self):
return self.cap.read()
def close_cam(self):
self.cap.release()
cv2.destroyAllWindows()
def restart_capture(self, cap):
cap.release()
self.cap = cv2.VideoCapture(self.url)
if anyone will need to capture every 5th frame and save it as jpg, based on Ishan Shah's code:
import cv2
vid = cv2.VideoCapture('C:/python_works/creatives_gardenscapes/0c52b83ed1dec617092aaf83278f12ad.mp4')
if not os.path.exists('images'):
os.makedirs('images')
index = 0
while(True):
ret, frame = vid.read()
if not ret:
break
name = 'C:/python_works/creatives_gardenscapes/frames/0c52b83ed1dec617092aaf83278f12ad' + str(index) + '.jpg'
if index%50==0:
cv2.imwrite(name, frame)
index += 1
code:
import cv2
vidcap = cv2.VideoCapture('bali.mp4')
success,image = vidcap.read()
fps = vidcap.get(cv2.CAP_PROP_FPS)
print('video fps :', fps)
length = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT))
print( 'total frames :', length )
count = 0
skip = 10
success = True
while success:
success,image = vidcap.read()
if count%skip==0:
print(count)
cv2.imwrite("frames/frame%d.jpg" % count, image) # save frame as JPEG file
if cv2.waitKey(10) == 27: # exit if Escape is hit
break
count += 1
output:
You can effectively "skip" a frame by reading it then discarding it. Granted, this does exactly not what you are asking, but might still suffice as a work-around. Obviously this has implications on performance but may be adequate for your purposes.
vs = cv2.videoCapture('/my/clip.mp4')
for i in (thing):
# Read a frame
_, frame = vs.read()
# Skip the frame you just read by reading another
_, frame = vs.read()
# Run a process on said frame
cv2.imshow("Window", frame)
vs.release()
This is what i did on skip frame
skip_frame = cap.get(cv2.CAP_PROP_POS_FRAMES) #get current frames
sk = skip_frame + 10 # How many frames you want to skip
cap.set(cv2.CAP_PROP_POS_FRAMES, sk) # set the Current frame to the sk
It is not possible to extract random frames as the encoding scheme is generally extremely complex. For example in MPEG-4, Only the information containing the difference between two frames is stored, Hence clearly the previous frames are required.
I've refactored #benJephunneh's answer to be more "Pythonic" and wrapped the code in an iterator.
def every_n_frames(path, n):
video = cv2.VideoCapture(path)
# start at frame 0
count = 0
while video.isOpened():
success, frame = video.read()
if not success:
break
try:
yield frame
except Exception as e:
video.release()
raise e
count += n # advance by n frames
video.set(cv2.CAP_PROP_POS_FRAMES, count)
video.release()
# Usage:
framerate = 30
for i, frame in enumerate(every_n_frames("XYZ.avi", framerate)):
cv2.imwrite("frame{:d}.jpg".format(i * framerate), frame)
Note: If you're using lower values of n (e.g. every 2, 3 frames), setting cv2.CAP_PROP_POS_FRAMES will be much slower than just reading every frame then discarding the ones you don't need.
Skipping frames in cv2 python
cap = cv2.VideoCapture(0)
x = 0
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray,(7, 7), 0)
(T, thresh) = cv2.threshold(blurred, 135, 255, cv2.THRESH_BINARY)
contours, hierarchy=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
for contour in contours:
area = cv2.contourArea(contour)
if(x != 0):
x -= 1
break
if(area >= 517000 and area <= 522000):
holdFrame = frame
results = yourAlgorithm(holdFrame) # Your Algorithm Here
x = 3
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.waitKey(0)
cv2.destroyAllWindows()
In the Code Above, I have done 3 things totally, that solved my problem
Capturing Frames and initializing the variable x = 0
Then if my required area of contour is detected I run my algorithm.
After running the algorithm I set my x = 3
Then next time my function goes to trigger my algorithm, it checks
if x != 0, while x = 3 so it breaks out of the loop twice while
decrementing the value of x by 1 each time. So, when the value of x
becomes 0, approximately 3,4 frames have been skipped.
Related
I have a python app with the Django framework. I display a video stream with detection using yolov5, sometimes the stream crashes and it's display this eroor
Assertion fctx->async_lock failed at libavcodec/pthread_frame.c:167
I think that it happens because of my detection() function .
the goal of the detection() function is to send to the client the percent of the detection any time that I have detect when my custom object appears in the video.
cap = cv2.VideoCapture("video.mp4")
def stream():
model.iou=0.5
while (cap.isOpened()):
ret, frame = cap.read()
if not ret:
print("Error: failed to capture image")
break
results = model(frame,augment=False)
for i in results.render():
data=im.fromarray(i)
data.save('demo.jpg')
annotator = Annotator(frame, line_width=2, pil=not ascii)
im0 = annotator.result()
image_bytes = cv2.imencode('.jpg', im0)[1].tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + image_bytes + b'\r\n')
cap.release()
cv2.destroyAllWindows()
def detection():
if(cap.isOpened()):
ret,frame = cap.read()
if not ret:
print("Erorr:faild to capture image")
data={"isRunning":False}
dataJson=json.dumps(data)
return dataJson
results = model(frame, augment=False)
pred = results.pandas().xyxy[0]
for index, row in pred.iterrows():
if float(row['confidence']) > 0.15:
detection=float(row['confidence'])
det = '%.2f' % detection
data={"det":det,"isRunning":cap.isOpened()}
dataJson=json.dumps(data)
return dataJson
data={"isRunning":cap.isOpened()}
dataJson=json.dumps(data)
return dataJson
data={"isRunning":False}
dataJson=json.dumps(data)
return dataJson
def video_feed(request):
return StreamingHttpResponse(stream(), content_type='multipart/x-mixed-replace; boundary=frame')
def detection_percentage(request):
return HttpResponse(detection())
I think that I need to read the frame from the video with another approach but I am not sure if that is actually the problem.
I'll be grateful for helping me facing with this problem.
Below code was taken from an existing post by Kieleth which I use as a subset of my larger codebase. I'm trying to leverage it to capture a list of frames taken once every thousand+ real time frames and later play in a time-lapse fashion. I've captured the frames but can't seem to view them when calling a simple function. I've seen in other posts that for loops are not recommended for this type of event but haven't figured out how to properly display. Any advise on this one would be appreciated?
from tkinter import ttk
import time
import cv2
from PIL import Image,ImageTk
#import threading
root = Tk()
def video_button1():# this flips between start and stop when video button pressed.
if root.video_btn1.cget('text') == "Stop Video":
root.video_btn1.configure(text = "Start Video")
root.cap.release()
elif root.video_btn1.cget('text') == "Start Video":
root.video_btn1.configure(text = "Stop Video")
root.cap = cv2.VideoCapture(0)
show_frame()
def show_frame():
# if video_btn1.cget('text') == "Stop Video":
global time_lapse_counter
ret, frame = root.cap.read()
if ret:
frame = cv2.flip(frame, 1) #flip image
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img) #converts img into tkinter readable format
root.video_label.imgtk = imgtk
if time_lapse_counter >= 20: # for Every 20 frames, capture one into time_lapse_list
time_lapse_list.append(imgtk)
time_lapse_counter = 0
root.video_label.configure(image=imgtk)
if len(time_lapse_list) == 5: # keep only 4 frames in the list *** debug purposes.
time_lapse_list.pop(0)
time_lapse_counter += 1
video_loop = root.after(40, show_frame)
else:
root.video_btn1.configure(text = "Start Video")
def time_lapse_play():
root.cap.release() #stop capturing video.
for image in time_lapse_list:
print (image, " ", len(time_lapse_list)," ",time_lapse_list) #
#*** I see the print of the pyimagexxx but nothing appears on the video***#
imgtk = image
root.video_label.imgtk = imgtk
root.video_label.configure(image=imgtk)
cv2.waitKey(500)
# video_loop = root.after(500, time_lapse_play)
def setup_widgets(): #simple label and 2 button widget setup
#Setup Top Right Window with pictures
f_width, f_height = 810, 475
root.rightframe= Frame(root, border=0, width=f_width, height = f_height)
root.rightframe.grid(row=0, column=0, padx=10, pady=0)
# Show video in Right Frame
root.cap = cv2.VideoCapture(0)
root.cap.set(cv2.CAP_PROP_FRAME_WIDTH, f_width)
root.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, f_height)
root.video_label = Label(root.rightframe)
root.video_label.grid(row=0, column = 0)
root.video_btn1 = Button(root.rightframe, fg='maroon', bg="yellow", text = "Stop Video", font=("Arial",10),height=0, width = 10, command=video_button1)
root.video_btn1.grid(row=0, column = 1)
root.video_btn2 = Button(root.rightframe, fg='maroon', bg="yellow", text="Time Lapse", font=("Arial",10),height=0, width = 10, command=time_lapse_play)
root.video_btn2.grid(row=1, column = 1)
# Main Code
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
screen_resolution = str(screen_width)+'x'+str(screen_height)
root.geometry(screen_resolution)
time_lapse_counter = 0
time_lapse_list=[]
setup_widgets()
show_frame()
root.mainloop()```
I've finally figure this one out. Seems that the for loop effectively doesn't work when using callback. I've modified the code to remove the for loop. I'm sure it could use some improvements but it works. I'm not sure how to reset the image count within the list as pop/append grows the list image number over time and I wonder about an overflow error. i.e after a few minutes, the list will contain [pyimage100 - pyimage200], after a few hours, [pyimage1000000 - pyimage1000100].
from tkinter import *
import cv2
from PIL import Image,ImageTk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg)
import matplotlib.pyplot as plt
root = Tk()
def video_button1():# this flips between start and stop when video button pressed.
if root.video_btn1.cget('text') == "Stop Video":
root.video_btn1.configure(text = "Start Video")
root.cap.release()
elif root.video_btn1.cget('text') == "Start Video":
root.video_btn1.configure(text = "Stop Video")
root.cap = cv2.VideoCapture(0)
root.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 400)
root.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 400)
show_frame()
def show_frame():
# if video_btn1.cget('text') == "Stop Video":
global time_lapse_counter
ret, frame = root.cap.read()
if ret:
frame = cv2.flip(frame, 1) #flip image
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img) #converts img into tkinter readable format
root.video_label.imgtk = imgtk
root.video_label.configure(image=imgtk)
if time_lapse_counter >= 20: # for Every 20 frames, capture one into time_lapse_list
time_lapse_list.append(imgtk)
time_lapse_counter = 0
if len(time_lapse_list) == 100: # keep 99 frames in the list
time_lapse_list.pop(0)
time_lapse_counter += 1
video_loop = root.after(40, show_frame)
else:
root.video_btn1.configure(text = "Start Video")
def time_lapse_play():
root.cap.release() #stop capturing video.
global frame_counter
if frame_counter <= len(time_lapse_list)-1:
imgtk = time_lapse_list[frame_counter] # get image from list
root.video_label.configure(image=imgtk) # update label with image from list
frame_counter += 1
video_loop = root.after(250, time_lapse_play) #wait 250ms until next frame
else:
frame_counter = 0 #reset frame_counter
def setup_widgets(): #simple label and 2 button widget setup
#Setup Top Right Window with pictures
f_width, f_height = 1200, 500
root.rightframe= Frame(root, border=0, width=f_width, height = f_height)
root.rightframe.grid(row=0, column=0, padx=10, pady=0)
# Show video in Right Frame
root.cap = cv2.VideoCapture(0)
root.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 400)
root.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 400)
root.video_label = Label(root.rightframe)
root.video_label.grid(row=0, column = 0)
root.video_btn1 = Button(root.rightframe, fg='maroon', bg="yellow", text =
"Stop Video", font=("Arial",10),height=0, width = 10, command=video_button1)
root.video_btn1.grid(row=0, column = 1)
root.video_btn2 = Button(root.rightframe, fg='maroon', bg="yellow", text="Time Lapse", font=("Arial",10),height=0, width = 10, command=time_lapse_play)
root.video_btn2.grid(row=1, column = 1)
fig = plt.figure(1)
canvas = FigureCanvasTkAgg(fig, root.rightframe)
canvas.get_tk_widget().place(x=700,y=0)
canvas.get_tk_widget().config(border=2, bg="yellow", width=400, height=400)
# Main Code
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
screen_resolution = str(screen_width)+'x'+str(screen_height)
root.geometry(screen_resolution)
time_lapse_counter = 0
frame_counter = 0
time_lapse_list=[]
setup_widgets()
show_frame()
root.mainloop()
`
First of all, I'm sorry I can not speak English well.
I ask for your understanding even if there are some awkward parts of my words.
I am a beginner to get into Opencv.
I want to translate a picture of a horizontal line into a picture of a circle.
I tried to recommend linearPolar, logPolar, and warpPolar in several articles, but I did not get the desired result.
Result Image:
Here is the image I want to put and the desired result.
Input Image:
Output Image:
What function should I use to get this result?
If you have any examples or explanations for reference, please let me know.
If you let me know just the keywords, I will search Google and this site hard.
Thank you for reading my question.
linearPolar or warpPolar are exactly what you are looking for
You just need to pass it the WARP_INVERSE_MAP flag to make it transform the direction you're looking for.
modified example from samples/cpp/polar_transforms.cpp
Would be something like this:
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
int main(int argc, const char** argv)
{
using namespace cv;
using namespace std;
int flags = INTER_LINEAR + WARP_FILL_OUTLIERS;
Mat src = imread(R"(C:\temp\IPpzR.png)");
Mat lin_polar_img;
rotate(src, lin_polar_img, cv::ROTATE_90_COUNTERCLOCKWISE);
imshow("Loaded",src);
Mat recovered_lin_polar_img;
Point2f center( (float)src.cols / 2, (float)src.rows / 2 );
double maxRadius = min(center.y, center.x);
cv::linearPolar(lin_polar_img, recovered_lin_polar_img, center, maxRadius, flags + WARP_INVERSE_MAP);
cv::imshow("Modified",recovered_lin_polar_img);
cv::waitKey();
return 0;
}
which gives the following result:
Peter's answer is great (+1).
I had a play with it and just wanted to post a Python version of his approach with some sliders:
#!/usr/bin/env python
import numpy as np
import cv2
# main window
WINDOW_NAME = "carToPol"
cv2.namedWindow(WINDOW_NAME)
# read input
src = cv2.imread("iPpzR.png")
# get dimenions and compute half (for center/radius)
dims = src.shape[:-1]
cols,rows = dims
half = cols // 2
def carToPol(src,center,maxRadius,interpolation,rotate90=True):
# rotate 90 degrees (cv2.warpAffine seems to mess up a column)
if(rotate90):
src = np.rot90(src)
# cartesian to polar (WARP_INVERSE_MAP)
return cv2.linearPolar(src,(centerX,centerY),maxRadius,interpolation + cv2.WARP_FILL_OUTLIERS + cv2.WARP_INVERSE_MAP)
# interpolation names: just for debugging
interpolations = ["NEAREST","LINEAR","CUBIC","AREA","LANCZOS4"]
# slider callbacks: just for debugging
def printCenterX(x):
print("center",x)
def printCenterY(x):
print("centerY",x)
def printMaxRadius(x):
print("maxRadius",x)
def printInterpolation(x):
global interpolations
print("interpolation",interpolations[x])
# create sliders
cv2.createTrackbar("centerX" ,WINDOW_NAME,half,cols,printCenterX)
cv2.createTrackbar("centerY" ,WINDOW_NAME,half,cols,printCenterY)
cv2.createTrackbar("maxRadius",WINDOW_NAME,half,cols * 4,printMaxRadius)
cv2.createTrackbar("interpolation",WINDOW_NAME,cv2.INTER_CUBIC,cv2.INTER_LANCZOS4,printInterpolation)
# continously process for quick feedback
while 1:
# exit on ESC key
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# read slider values
centerX = cv2.getTrackbarPos("centerX",WINDOW_NAME)
centerY = cv2.getTrackbarPos("centerY",WINDOW_NAME)
maxRadius = cv2.getTrackbarPos("maxRadius",WINDOW_NAME)
interpolation = cv2.getTrackbarPos("interpolation",WINDOW_NAME)
dst = carToPol(src,(centerX,centerY),maxRadius,interpolation,True)
# show result
cv2.imshow(WINDOW_NAME,dst)
# save image with 's' key
if k == ord('s'):
cv2.imwrite("output.png",dst)
# exit
cv2.destroyAllWindows()
I am an enthusiastic learner of opencv and write down a code for video streaming with opencv I want to learn the use of cv2.createTrackbar() to add some interactive functionality. Though, I tried this function but its not working for me :
For streaming and resizing the frame i use this code
import cv2
import sys
import scipy.misc
import scipy
cap = cv2.VideoCapture(sys.argv[1])
new_size = 0.7 # value range(0,1) can be used for resizing the frame size
while(1):
ret, frame = cap.read()
frame = scipy.misc.imresize(frame, new_size)
cv2.imshow("t",frame)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
Then i have transformed the above code like this to add the track bar functionality to resize the frame.
import cv2
import sys
import scipy.misc
import scipy
def nothing(x):
pass
cv2.createTrackbar('t','frame',0,1,nothing)
cap = cv2.VideoCapture(sys.argv[1])
while(1):
ret, frame = cap.read()
j = cv2.getTrackbarPos('t','frame')
frame = scipy.misc.imresize(frame, j)
cv2.imshow("t",frame)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
but this code is not working and ended up with this error given bellow:
me#ubuntu:~/Desktop/final_video_soft$ python GUI_STREAM.py p.3gp
Traceback (most recent call last):
File "GUI_STREAM.py", line 20, in <module>
frame = scipy.misc.imresize(frame, j)
File "/usr/lib/python2.7/dist-packages/scipy/misc/pilutil.py", line 365, in imresize
imnew = im.resize(size, resample=func[interp])
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 1305, in resize
im = self.im.resize(size, resample)
TypeError: must be 2-item sequence, not float
Your code will surely fail. There are too many issues indicating you haven't read the document. Even the 1st new_size one will fail for sure.
cap = cv2.VideoCapture(sys.argv[1]) this is wrong. Because it requires int instead of str. You have to do cap = cv2.VideoCapture(int(sys.argv[1]))
another obvious error is the conflicted window name you give in following code:
cv2.createTrackbar('t','frame',0,1,nothing)
cv2.imshow("t",frame)
imshow used a window name 't'. But the 't' is actually the trackbar name.
Moreover, if you have read the document you will know the createTrackbar will only accept int as val and count. Thus you either have j = 0 or j = 1 in your code. The value is initial value of the trackbar. Thus in your case it is always 0, which will raise an error in imshow.
The getTrackbarPos should be in event triggered callback not in the main loop. If you do it like you posted, it might still run, but it will not respond to every sliding-event. However, it does not cause visible trouble since the video capture loop is quite fast.
After fix all those errors, it will ends up like this:
scale = 700
max_scale = 1000
def modified():
scale = 500
_scale = float(scale)/max_scale
cv2.namedWindow('frame', cv2.WINDOW_AUTOSIZE)
cv2.createTrackbar('t','frame', scale, max_scale, nothing)
cap = cv2.VideoCapture(int(sys.argv[1]))
while(1):
ret, frame = cap.read()
if not ret:
break
scale = cv2.getTrackbarPos('t','frame')
if scale > 1:
_scale = float(scale)/max_scale
print "scale = ", _scale
frame = scipy.misc.imresize(frame, _scale)
cv2.imshow("frame",frame)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
Sorry, i am familiar with c++, here is the C++ code, hope it helps.
The code mentioned below adds a contrast adjustment to the live video stream from the camera using createTrackbar function
#include "opencv2\highgui.hpp"
#include "opencv2\core.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char **argv[])
{
string owin = "Live Feed Original";
string mwin = "Modified Live stream";
int trackval = 50;
Mat oframe;
Mat inframe;
VideoCapture video(0);
if (!video.isOpened())
{
cout << "The Camera cannot be accessed" << endl;
return -1;
}
namedWindow(owin);
moveWindow(owin, 0, 0);
namedWindow(mwin);
createTrackbar("Contrast", mwin, &trackval, 100);
while (1)
{
video >> inframe;
imshow(owin, inframe);
inframe.convertTo(oframe, -1, trackval / 50.0);
imshow(mwin, oframe);
if (waitKey(33) == 27)
break;
}
}
I want to count the vehicles from a video. After frame differencing I got a gray scale image or kind of binary image. I have defined a Region of Interest to work on a specific area of the frames, the values of the pixels of the vehicles passing through the Region of Interest are higher than 0 or even higher than 40 or 50 because they are white.
My idea is that when a certain number of pixels in a specific interval of time (say 1-2 seconds) are white then there must be a vehicle passing so I will increment the counter.
What I want is, to check whether there are still white pixels coming or not after a 1-2 seconds. If there are no white pixels coming it means that the vehicle has passed and the next vehicle is gonna come, in this way the counter must be incremented.
One method that came to my mind is to count the frames of the video and store it in a variable called No_of_frames. Then using that variable I think I can estimate the time passed. If the value of the variable No_of_frames is greater then lets say 20, it means that nearly 1 second has passed, if my videos frame rate is 25-30 fps.
I am using Qt Creator with windows 7 and OpenCV 2.3.1
My code is something like:
for(int i=0; i<matFrame.rows; i++)
{
for(int j=0;j<matFrame.cols;j++)
if (matFrame.at<uchar>(i,j)>100)//values of pixels greater than 100
//will be considered as white.
{
whitePixels++;
}
if ()// here I want to use time. The 'if' statement must be like:
//if (total_no._of_whitepixels>100 && no_white_pixel_came_after 2secs)
//which means that a vehicle has just passed so increment the counter.
{
counter++;
}
}
Any other idea for counting the vehicles, better than mine, will be most welcomed. Thanks in advance.
For background segmentation I am using the following algorithm but it is very slow, I don't know why. The whole code is as follows:
// opencv2/video/background_segm.hpp OPENCV header file must be included.
IplImage* tmp_frame = NULL;
CvCapture* cap = NULL;
bool update_bg_model = true;
Mat element = getStructuringElement( 0, Size( 2,2 ),Point() );
Mat eroded_frame;
Mat before_erode;
if( argc > 2 )
cap = cvCaptureFromCAM(0);
else
// cap = cvCreateFileCapture( "C:\\4.avi" );
cap = cvCreateFileCapture( "C:\\traffic2.mp4" );
if( !cap )
{
printf("can not open camera or video file\n");
return -1;
}
tmp_frame = cvQueryFrame(cap);
if(!tmp_frame)
{
printf("can not read data from the video source\n");
return -1;
}
cvNamedWindow("BackGround", 1);
cvNamedWindow("ForeGround", 1);
CvBGStatModel* bg_model = 0;
for( int fr = 1;tmp_frame; tmp_frame = cvQueryFrame(cap), fr++ )
{
if(!bg_model)
{
//create BG model
bg_model = cvCreateGaussianBGModel( tmp_frame );
// bg_model = cvCreateFGDStatModel( temp );
continue;
}
double t = (double)cvGetTickCount();
cvUpdateBGStatModel( tmp_frame, bg_model, update_bg_model ? -1 : 0 );
t = (double)cvGetTickCount() - t;
printf( "%d. %.1f\n", fr, t/(cvGetTickFrequency()*1000.) );
before_erode= bg_model->foreground;
cv::erode((Mat)bg_model->background, (Mat)bg_model->foreground, element );
//eroded_frame=bg_model->foreground;
//frame=(IplImage *)erode_frame.data;
cvShowImage("BackGround", bg_model->background);
cvShowImage("ForeGround", bg_model->foreground);
// cvShowImage("ForeGround", bg_model->foreground);
char k = cvWaitKey(5);
if( k == 27 ) break;
if( k == ' ' )
{
update_bg_model = !update_bg_model;
if(update_bg_model)
printf("Background update is on\n");
else
printf("Background update is off\n");
}
}
cvReleaseBGStatModel( &bg_model );
cvReleaseCapture(&cap);
return 0;
A great deal of research has been done on vehicle tracking and counting. The approach you describe appears to be quite fragile, and is unlikely to be robust or accurate. The main issue is using a count of pixels above a certain threshold, without regard for their spatial connectivity or temporal relation.
Frame differencing can be useful for separating a moving object from its background, provided the object of interest is the only (or largest) moving object.
What you really need is to first identify the object of interest, segment it from the background, and track it over time using an adaptive filter (such as a Kalman filter). Have a look at the OpenCV video reference. OpenCV provides background subtraction and object segmentation to do all the required steps.
I suggest you read up on OpenCV - Learning OpenCV is a great read. And also on more general computer vision algorithms and theory - http://homepages.inf.ed.ac.uk/rbf/CVonline/books.htm has a good list.
Normally they just put a small pneumatic pipe across the road (soft pipe semi filled with air). It is attached to a simple counter. Each vehicle passing over the pipe generates two pulses (first front, then rear wheels). The counter records the number of pulses in specified time intervals and divides by 2 to get the approx vehicle count.