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()
Related
I am building an Android app to create panoramas. The user captures a set of images and those images
are sent to my native stitch function that was based on https://github.com/opencv/opencv/blob/master/samples/cpp/stitching_detailed.cpp.
Since the images are in order, I would like to match each image only to the next image in the vector.
I found an Intel article that was doing just that with following code:
vector<MatchesInfo> pairwise_matches;
BestOf2NearestMatcher matcher(try_gpu, match_conf);
Mat matchMask(features.size(),features.size(),CV_8U,Scalar(0));
for (int i = 0; i < num_images -1; ++i)
{
matchMask.at<char>(i,i+1) =1;
}
matcher(features, pairwise_matches,matchMask);
matcher.collectGarbage();
Problem is, this wont compile. Im guessing its because im using OpenCV 3.1.
Then I found somewhere that this code would do the same:
int range_width = 2;
BestOf2NearestRangeMatcher matcher(range_width, try_cuda, match_conf);
matcher(features, pairwise_matches);
matcher.collectGarbage();
And for most of my samples this works fine. However sometimes, especially when im stitching
a large set of images (around 15), some objects appear on top of eachother and in places they shouldnt.
I've also noticed that the "beginning" (left side) of the end result is not the first image in the vector either
which is strange.
I am using "orb" as features_type and "ray" as ba_cost_func. Seems like I cant use SURF on OpenCV 3.1.
The rest of my initial parameters look like this:
bool try_cuda = false;
double compose_megapix = -1; //keeps resolution for final panorama
float match_conf = 0.3f; //0.3 default for orb
string ba_refine_mask = "xxxxx";
bool do_wave_correct = true;
WaveCorrectKind wave_correct = detail::WAVE_CORRECT_HORIZ;
int blend_type = Blender::MULTI_BAND;
float blend_strength = 5;
double work_megapix = 0.6;
double seam_megapix = 0.08;
float conf_thresh = 0.5f;
int expos_comp_type = ExposureCompensator::GAIN_BLOCKS;
string seam_find_type = "dp_colorgrad";
string warp_type = "spherical";
So could anyone enlighten me as to why this is not working and how I should match my features? Any help or direction would be much appreciated!
TL;DR : I want to stitch images in the order they were taken, but above codes are not working for me, how can I do that?
So I found out that the issue here is not with the order the images are stitched but rather the rotation that is estimated for the camera parameters in the Homography Based Estimator and the Bundle Ray Adjuster.
Those rotation angles are estimated considering a self rotating camera and my use case envolves an user rotating the camera (which means that will be some translation too.
Because of that (i guess) horizontal angles (around Y axis) are highly overestimated which means that the algorithm considers the set of images cover >= 360 degrees which results in some overlapped areas that shouldnt be overlapped.
Still havent found a solution for that problem though.
matcher() takes UMat as mask instead of Mat object, so try the following code:
vector<MatchesInfo> pairwise_matches;
BestOf2NearestMatcher matcher(try_gpu, match_conf);
Mat matchMask(features.size(),features.size(),CV_8U,Scalar(0));
for (int i = 0; i < num_images -1; ++i)
{
matchMask.at<char>(i,i+1) =1;
}
UMat umask = matchMask.getUMat(ACCESS_READ);
matcher(features, pairwise_matches, umask);
matcher.collectGarbage();
I am trying to implement the spectral approach to get the saliency of an image with CImg, but I'm having trouble getting there.
This might seems like a repost from this question (spectral residual saliency detection in C++ with CImg) but I think I got right the two mistakes from this question (atan2 and FFT arguments).
Here's my code:
int main(int argc, char * argv[]) {
const char * input_file = "img/pic.png";
CImg<float> input = CImg<float>(input_file);
const CImg<float> mask(3,3,1,1,1.0f/9.0f);
resize_fft(input); // Resize for fft
CImg<float> gray = any2gray(input); // to single channel grayscale
CImgList<float> fft = gray.get_FFT();
CImg<float> amp = (fft[0].get_pow(2) + fft[1].get_pow(2)).get_sqrt();
CImg<float> amp_log = (amp + 1.0f).get_log().get_normalize(0, 255);
CImg<float> phase = fft[1].get_atan2(fft[0]);
CImg<float> residual = amp_log - amp_log.get_convolve(mask);
CImg<float> real = residual.get_exp();
CImg<float>::FFT(real, phase, true);
real.save("img/001.png");
real.normalize(0, 255).save("img/002.png");
return 1;
}
Both save pictures 001 and 002 end up being noise-like picture, like still in the frequency space.
I don't what's something wrong with what I'm doing, if yuo guys can help me ?
Thanks.
Firstly, It is obvious that you forget to smooth real with Gaussian filter.
Secondly, the line CImg<float>::FFT(real, phase, true); is suspectable. I don't know about CImg library but I can understand what you are expressing. When you do inverse fft, I think that both the real part and the imaginary part are wrong. The formulae in the paper are kind of misleading, reading the matlab code is clearer.
If you are familiar with complex number, you will find that getting variable phase is not necessary here.
The pseudo code replacing the line are here:
fft[0] = fft[0] ./ amp .* residual;
fft[1] = fft[1] ./ amp .* residual;
//Inverse Fourier Transform
CImg<float>::FFT(fft[0], fft[1], true);
real = fft[0].get_pow(2) + fft[1].get_pow(2);
real.get_convolve(Gaussian filter with sigma = 8)
All the operators with left dot mean element-wise operation.
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;
}
}
My goal is to remove shadows from image. I use C++ and OpenCV. Sure I lack enough math background and not being native English speaker makes everything harder to understand.
After reading different approaches to remove shadows I found method which should work for me but it relies on something they call "2D chromaticity" and "2D log-chromaticity space" but even this term seems to be inconsistent in different sources. Many papers on topic, few are listed here:
http://www.cs.cmu.edu/~efros/courses/LBMV09/Papers/finlayson-eccv-04.pdf
http://www2.cmp.uea.ac.uk/Research/compvis/Papers/DrewFinHor_ICCV03.pdf
http://www.cvc.uab.es/adas/publications/alvarez_2008.pdf
http://ivrgwww.epfl.ch/alumni/fredemba/papers/FFICPR06.pdf
I teared Google into strips by searching right words and explanations. Best I found is Illumination invariant image which did not help me much.
I tried to repeat formula log(G/R), log(B/R) described in first paper, page 3 to get figures similar to 2b.
As input I used http://en.wikipedia.org/wiki/File:Gretag-Macbeth_ColorChecker.jpg
Output I get is
My source code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main( int argc, char** argv ) {
Mat src;
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
Mat image( 600, 600, CV_8UC3, Scalar(127,127,127) );
int cn = src.channels();
uint8_t* pixelPtr = (uint8_t*)src.data;
for(int i=0 ; i< src.rows;i++) {
for(int j=0 ; j< src.cols;j++) {
Scalar_<uint8_t> bgrPixel;
bgrPixel.val[0] = pixelPtr[i*src.cols*cn + j*cn + 0]; // B
bgrPixel.val[1] = pixelPtr[i*src.cols*cn + j*cn + 1]; // G
bgrPixel.val[2] = pixelPtr[i*src.cols*cn + j*cn + 2]; // R
if(bgrPixel.val[2] !=0 ) { // avoid division by zero
float a= image.cols/2+50*(log((float)bgrPixel.val[0] / (float)bgrPixel.val[2])) ;
float b= image.rows/2+50*(log((float)bgrPixel.val[1] / (float)bgrPixel.val[2])) ;
if(!isinf(a) && !isinf(b))
image.at<Vec3b>(a,b)=Vec3b(255,2,3);
}
}
}
imshow("log-chroma", image );
imwrite("log-chroma.png", image );
waitKey(0);
}
What I am missing or misunderstand?
By reading the paper Recovery of Chromaticity Image Free from Shadows via Illumination Invariance that you've posted, and your code, I guess the problem is that your coordinate system (X/Y axis) are linear while in the paper the coordinate system are log(R/G) by log(B/G).
This is the closest I can figure. Reading through this:
http://www2.cmp.uea.ac.uk/Research/compvis/Papers/DrewFinHor_ICCV03.pdf
I came across the sentence:
"Fig. 2(a) shows log-chromaticities for the 24 surfaces of a Macbeth ColorChecker Chart, (the six neutral patches all belong to the same
cluster). If we now vary the lighting and plot median values
for each patch, we see the curves in Fig. 2(b)."
If you look closely at the log-chromaticity plot, you see 19 blobs, corresponding to each of the 18 colors in the Macbeth chart, plus the sum of all the 6 grayscale targets in the bottom row:
Explanation of Log Chromaticities
Explanation of Log Chromaticities
With 1 picture, we can only get 1 point of each blob: We take the median value inside each target and plot it. To get plot from the paper, we would have to create multiple images with different lighting. We might be able to do this by varying the temperature of the image in an image editor.
For now, I just looked at the color patches in the original image and plotted the points:
Input:
Color Patches Used
Output:
Log Chromaticity
The graph dots are not all in the same place as the paper, but I figure it's fairly close. Would someone please check my work to see if this makes sense?
In that OpenCV code I got a "undefined Identifier error" for the function ifinf() and I solved it by replacing it with _finite(). That might be the issue with the Visual studio version.
if(!isinf(a) && !isinf(b)) ----> if(_finite(a) && _finite(b))
Include this header:
#include<float.h>
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.