cv2.cvtColor error. Is it bug? - python-2.7

I need to use some motion detection code, then I use following code, provided by this link:
http://www.steinm.com/blog/motion-detection-webcam-python-opencv-differential-images/ .
Here is the code:
import cv2
def diffImg(t0, t1, t2):
d1 = cv2.absdiff(t2, t1)
d2 = cv2.absdiff(t1, t0)
return cv2.bitwise_and(d1, d2)
cam = cv2.VideoCapture(0)
winName = "Movement Indicator"
cv2.namedWindow(winName, cv2.CV_WINDOW_AUTOSIZE)
# Read three images first:
t_minus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
while True:
cv2.imshow(winName, diffImg(t_minus, t, t_plus) )
#diff = diffImg(t_minus, t, t_plus)
# Read next image
t_minus = t
t = t_plus
t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
#cv2.imshow(winName, diff)
key = cv2.waitKey(10)
if key == 27:
cv2.destroyWindow(winName)
break
print "Goodbye"
At first, it run smoothly, but now, it gives me error :
cv2.error: ........\opencv\modules\imgproc\src\color.cpp:3737: error: (-215) scn == 3 || scn == 4 in function cv::cvtColor
i found various solutions in stackoverflow, but still the error occured. It has been said that the error occured because the source doesn’t have the right color format that the code (third argument in the function call) indicates it should.
Can anyone give me ideas why the error occured? Or is that opencv bug and there's no solution for that?

The problem is
t_minus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
# ^
When you're accessing the [1] index of an BGR image, it's no longer a colour image to be converted using cv2.COLOR_RGB2GRAY. Instead, just write cam.read(). Also note, OpenCV uses BGR by default, not RGB.

I met this trouble also, after i read above answers i tried it but have not solved it, and finally i find the path of my image was wrong, so u had better check the real path firstly.

Related

Assertion fctx error using Django & Opencv

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.

Question about how to convert a line image to a circle image

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()

skimage - Contrast stretch using python

I am trying to preform a simple contrast stretch with python skimage, on the image opened with gdal as array of type float32. I first calculate the percentile with:
p2, p98 = np.percentile(arrayF, (P1, P2))
and then try to perform the stretch with:
img_rescale = exposure.rescale_intensity(arrayF, in_range=(p2, p98))
The returned image written to .tiff with GDAL contains only 'ones' and no data.
The cause of the problem might be in data range. For this arrayF it is between 0,0352989 and 1,03559. The script works fine when stretching the array with values 0 - 255.
Here is the function:
def contrastStrecher(Raster1, p1, p2, OutDir, OutName1):
fileNameR1 = Raster1
P1 = p1
P2 =p2
outputPath = OutDir
outputName = OutName1
extension = os.path.splitext(fileNameR1)[1]
raster1 = gdal.Open(fileNameR1, GA_ReadOnly)
colsR1 = raster1.RasterXSize
rowsR1 = raster1.RasterYSize
bandsR1 = raster1.RasterCount
driverR1 = raster1.GetDriver().ShortName
geotransformR1 = raster1.GetGeoTransform()
proj1 = raster1.GetProjection()
bandF = raster1.GetRasterBand(1)
nodataF = bandF.GetNoDataValue()
newnodata = -1.
arrayF = bandF.ReadAsArray().astype("float32")
nodatamaskF = arrayF == nodataF
arrayF[nodatamaskF] = newnodata
p2, p98 = np.percentile(arrayF, (P1, P2))
img_rescale = exposure.rescale_intensity(arrayF, in_range=(p2, p98))
del arrayF
img_rescale[nodatamaskF] = newnodata
driver = gdal.GetDriverByName(driverR1)
outraster = driver.Create(outputPath + outputName + extension, colsR1, rowsR1, 1, gdal.GDT_Float32)
outraster.SetGeoTransform(geotransformR1)
outraster.SetProjection(proj1)
outband = outraster.GetRasterBand(1)
outband.WriteArray(img_rescale)
del img_rescale
outband.FlushCache()
outband.SetNoDataValue(newnodata)
del outraster, outband
I figured out that value of newnodata interferes with the calculation. Previously I assigned a velue of -9999.9 to it and the results were as described above. Now with -1. it seems that the function outputs correct results however I'm not entirely sure of that as the nodata or newnodata value should not be included in calculation.
There is a concept called percentile stretching where everything passed the bottom and top percentile designated will be mapped to 0 and 255 respectively and all pixel values in between will be stretched to improve contrast. I am not sure that is what you want but I believe that is what's done here in this example with downloadable code: https://scikit-image.org/docs/0.9.x/auto_examples/plot_equalize.html
But you many not want for some images any mapping to 0,255 so maybe use argparse() to be able to enter these as parameters or use np.amax and np.amin to designate cut-off points, try writing the images to file and build an algorithm that suits your needs.

how to use "cv2.createTrackbar()" function to resize the streaming video frame?

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;
}
}

Reading every nth frame from VideoCapture in OpenCV

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.