I need to capture frame by frame from a video stored in my sd card of the Android device (in this case my emulator). I am using Android and OpenCV through NDK. I pushed manually the file "SinglePerson.avi" inside the sdcard through file explorer of DDBS (eclipse) and I used the code below to read the file:
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4Mixed_VideoProcessing(JNIEnv*, jobject)
{
LOGI("INSIDE VideoProcessing ");
CvCapture* capture = cvCaptureFromAVI("/mnt/sdcard/SinglePerson.avi");
IplImage* img = 0;
if(!cvGrabFrame(capture)){ // capture a frame
LOGI("Inside the if");
printf("Could not grab a frame\n\7");
exit(0);
}
img=cvRetrieveFrame(capture);// retrieve the captured frame
cvReleaseCapture(&capture);
}
The problem is that cvGrabFrame(capture) results always false.
Any suggestion to correctly open the video and grab the frames?
Thanks in advance
Some versions of OpenCV (in package opencv2) build without video support. If it is your case you have to enable "-D WITH_FFMPEG=ON" in pkg's Makefile and recompile.
Look at "Displaying AVI Video using OpenCV" tutorial:
"You may need to ensure that ffmpeg has been successfully installed in order to allow video encoding and video decoding in different formats. Not having the ffmpeg functionality may cause problems when trying to run this simple example and produce a compilation errors".
Also check path in cvCaptureFromAVI for correctness.
Hope this will help!
The behavior you are observing is probably due to cvCaptureFromAVI() failing. You need to start coding safely and check the return of the calls you make:
CvCapture* capture = cvCaptureFromAVI("/mnt/sdcard/SinglePerson.avi");
if (!capture)
{
printf("!!! Failed to open video\n\7");
exit(0);
}
This function usually fails for 2 reasons:
When it's unable to access the file (due to wrong filesystem permissions);
Missing codecs on the system (or the video format is not supported by OpenCV).
If you are new to OpenCV, I suggest you test your OpenCV code on a desktop (PC) first.
Related
I want to save the video every 5 seconds while the video recording is ON.
I have tried many solutions but I am facing a Glitch that is, the Last Saved Frame remains in preview for around 300ms.
I think the reason is in MediaRecorder class "Once a recorder has been stopped, it will need to be completely reconfigured and prepared before being restarted."
Thanks
I think it's impossible to do that with MediaRecorder. The better approach could be encoding video by using MediaCodec and storing encoded content bt using MediaMuxer.
Grafika is a project on Google Github account which is a dumping ground for Android graphics & media hacks. In this project, you can find good examples of using both MediaCodec and MediaMuxer classes.
I forked the Grafika project and did some modifications to support sequential segmented recording. You can find it here. When you run the application, select Show + capture camera item from the list and then set Output Segment Duration for example to 5 and then press Start recording button.
Please look at VideoEncoderCore and CameraCaptureActivity classes source code to find how it works. You can find here how it segments live camera feed to different files.
"I think the reason is in MediaRecorder class, "Once a recorder has been stopped, it will need to be completely reconfigured and prepared before being restarted"."
You can use multiple mediaMuxer's to encode separate files.
The camera should send data to fill a MediaMuxer object (which itself produces an .mp4 file).
When needed, you can start writing the Camera data to a second (different) MediaMuxer thus automatically creating a second new .mp4 file (on begin usage of the muxer).
The first MediaMuxer can then close and save its file. Your first segment is ready...
If needed, try to study this code for a guide on using Camera with mediaMuxer:
https://bigflake.com/mediacodec/CameraToMpegTest.java.txt
So you have a function that handles things when the 5 second interval has passed? In that function, could cycle the recording between two muxers, giving one a chance to close its file, while the other records the next segment and then vice-versa).
Instead of something like below (using MediaRecorder.OutputFormat.MPEG_4):
this.mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
You will instead create a new muxer (with MUXER_OUTPUT_MPEG_4):
//# create a new File to ssave into
File outputFile = new File(OUTPUT_FILENAME_DIR, "/yourFolder/Segment" + "-" + mySegmentNum + ".mp4");
String outputPath = outputFile.toString();
int format = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
try { mMuxer = new MediaMuxer(outputPath, format); }
catch (IOException e) { Log.e(TAG, e.getLocalizedMessage()); }
And you stop a muxer with:
mMuxer1.stop(); mMuxer1.release();
PS:
Another option is to use Threads to run multiple MediaRecorders. It might help your situation. See the Android Background Process guide.
I am trying to pass a video to the OpenCV VideoCapture class. However when I call the VideoCapture.isOpened() method it always returns false. I have tried two methods:
Saving the video file to the internal memory, context.getFilesDir() => /data/data/package_name/files/VideoToAnalyze/Recording.mp4
and also one to environment.getExternalStorageDirectory() => sdcard/appName/Recording.mp4.
Nothing seems to work here. My question is how do I pass a video file (or what is the correct file path) to a VideoCapture OpenCV object? I've posted some code below as an example. Note that I don't get an error. The file is always found/exists, but when I call isOpened() I always get false.
UPDATE:
So it looks like everyone on the web is saying that OpenCV (I'm using 3.10) is lacking a ffmpeg backend and thus cannot process videos. I'm wondering does anyone know this as a fact ?? And is there a work around. Almost all other alternatives to process videos frame by frame is deathly slow.
String x = getApplicationContext().getFilesDir().getAbsolutePath();
File dir = new File(x + "/VideoToAnalyze");
if(dir.isDirectory()) {
videoFile = new File(dir.getAbsolutePath() + "/Recording1.mp4");
} else {
// handle error
}
if(videoFile.exits(){
String absPath = videoFile.getAbsolutePath();
VideoCapture vc = new VideoCapture();
try{
vc.open(absPath);
} catch (Exception e) {
/// handle error
}
if(!vc.isOpened(){
// this code is always hit
Log.v("VideoCapture", "failed");
} else {
Log.v("VideoCapture", "opened");
.....
Its an old question but nevertheless I had same issue.
Opencv for Android only supports MJPEG codec in AVI container. See this
Just to close this .. I downloaded JavaCV .. included .so files into the android project and then used FFMPEGFrameGrabber.
I am trying to read an image in my C++ code
LOGD("Loading image '%s' ...\n", (*inFile).c_str());;
Mat img = imread(*inFile, CV_LOAD_IMAGE_GRAYSCALE);
CV_Assert(img.data != 0);
and get the following output:
09-25 17:08:24.798: D/IRISREC(12120): Loading image '/data/data/com.example.irisrec/files/input/osoba1.jpg' ...
09-25 17:08:24.798: E/cv::error()(12120): OpenCV Error: Assertion failed (img.data != 0) in int wahet_main(int, char**), file jni/wahet.cpp, line 4208
The file exists. But strange is, that if I try to preview the image using Root File Browser it is just black. I copied the files there manually.
EDIT:
The code works fine under Windows with .png and .jpg format. I am just trying to port an existing C++ project for Iris Recognition to Android.
imread() determines the type of file based on its content not by the file extension. If the header of the file is corrupted, it makes sense that the method fails.
Here are a few things you could try:
Copy those images back to the computer and see if they can be opened by other apps. There's a chance that they are corrupted in the device;
Make sure there is a file at that location and that your user has permission to read it;
Test with types of images (jpg, png, tiff, bmp, ...);
For testing purposes it's always better to be more direct. Get rid of inFile:
Example:
Mat img = imread("/data/data/com.example.irisrec/files/input/osoba1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (!img.data) {
// Print error message and quit
}
When debugging, first try to get more data on the problem.
It's an unfortunate design that imread() doesn't provide any error info. The docs just say that it'll fail "because of missing file, improper permissions, unsupported or invalid format".
Use the debugger to step into the code if you can. Can you tell where it fails?
Search for known problems, stackoverflow.com/search?q=imread, e.g. imread not working in OpenCV.
Then generate as many hypotheses as you can. For each one, think of a way to test it. E.g.
The image file is malformed (as #karlphillip offered). -- See if other software can open the file.
The image file is not a supported format. -- Verify the file format on your desktop. Test that desktop OpenCV can read it. Check the docs to verify the image formats that AndroidCV can read.
The image file is not at the expected path. -- Write code to test if there's a file at that path, and verify its length.
The image file does not have read permission. -- Write code to open the file for reading.
A problem with the imread() arguments. -- Try defaulting the second argument.
I was able to solve this issue only by copying the image files in code.I stored them in my asset folder first and copied them to internal storage following this example.
If someone can explain this to me please do this.
It could be a permission issue.You would have to request the permission from Java code in your Activity class like this in Android 6.0 or above. Also make sure that in your AndroidManifest.xml, you have the the following line :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
In your activity file add this:
if (PermissionUtils.requestPermission(
this,
HOME_SCREEN_ACTIVITY,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
Mat image = Imgcodecs.imread(filePath,Imgcodecs.IMREAD_COLOR);
}
I struggled a long time to find this and I was getting Mat object null for all the time before.
I'm using this code to save an image in the Android's Camera roll, unfortunately to date without any luck.
put mergStoragePath("pictures") into a
put a & "/myphoto.jpg" into pathFile
put the long id of image "myPhoto" into longIDofImage
export longIDofImage to file pathFile as JPEG
All suggestions will be appreciate.
I think the problem here is that the media scanner isn't scanning the file. I have a command coming to do that mergStorageScanFile. However, to do what you want to do there's actually a built in LiveCode command mobileExportImageToAlbum.
I have this question: how can I load, in Android, a video file stored in my device, and how can I split it into frames?
I'm using IntelliJ and I want to split the video into frames in order to process them with some image processing techniques (with OpenCv for Android library).
You don't strictly need to use OpenCV for this. You can use the MediaMetaDataRetreiver class provided by the SDK. It provides methods to extract metadata from all kinds of media files. You can try something like:
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(file.getAbsolutePath());
imgView.setImageBitmap(retriever.getFrameAtTime(TIME_OFFSET,MediaMetadataRetriever.OPTION_CLOSEST));
where TIME_OFFSET is in microseconds.
Grabbing a video frame in OpenCV is pretty easy. There are lots of examples on OpenCV site. However crucial thing is to set-up opencv on andriod. You can follow this link on getting started with Opencv on andriod.
http://opencv.org/android
Once you have opencv installed on andriod. You can easily load video file and grab frame in Mat structure and then do some processing on it.
Here is the sample one. It will need some modification to run it on andriod. I think you will need to used NDK on andriod for this.
int main(int argc, char*argv[])
{
char *my_file = "C:\\vid_an2\\desp_me.avi";
std::cout<<"Video File "<<my_file<<std::endl;
cv::VideoCapture input_video;
if(input_video.open(my_file))
{
std::cout<<"Video file open "<<std::endl;
}
else
{
std::cout<<"Not able to Video file open "<<std::endl;
}
namedWindow("My_Win",1);
namedWindow("Segemented", 1);
Mat cap_img;
for(;;)
{
input_video >> cap_img;
imshow("My_Win", cap_img);
waitKey(0);
}
return 0;
}