capture multiple pictures per second,and name use time and frame number - c++

I use this code to detect motion and save pictures name with system time, like 2013-11-26_01:20, but only can 1 picture per second. I want to take multiple pictures name like 2013-11-26_01:20-1,2013-11-26_01:20-2 ... 2013-11-26_01:21-1,2013-11-26_01:22-2.
bool saveImg(Mat image, const string DIRECTORY, const string EXTENSION, const char * DIR_FORMAT, const char * FILE_FORMAT){
stringstream ss;
time_t seconds;
struct tm * timeinfo;
char TIME[80];
time (&seconds);
timeinfo = localtime (&seconds);
// convert dir...
strftime (TIME,80,DIR_FORMAT,timeinfo);
ss.str("");
ss << DIRECTORY << TIME;
if(!directoryExists(ss.str().c_str()))
mkdir(ss.str().c_str(), 0777);
// convert image name
strftime (TIME,80,FILE_FORMAT,timeinfo);
ss.str("");
ss << DIRECTORY << TIME << EXTENSION;
// save image
return imwrite(ss.str().c_str(), image);
}
int main (int argc, char * const argv[]) {
// const
const string DIR = "/home/balice/Desktop/";
const string EXT = ".jpg";
const int DELAY = 100; // mseconds
string DIR_FORMAT = "%d-%m-%Y";
string FILE_FORMAT = DIR_FORMAT + "/" + "%d-%m-%Y_%H:%M:%S";
// create all necessary instances
CvCapture * camera = cvCaptureFromCAM(CV_CAP_ANY);
Mat original = cvQueryFrame(camera);
Mat next_frame = original;
Mat current_frame = cvQueryFrame(camera);
Mat prev_frame = cvQueryFrame(camera);
cvtColor(current_frame, current_frame, CV_RGB2GRAY);
cvtColor(prev_frame, prev_frame, CV_RGB2GRAY);
cvtColor(next_frame, next_frame, CV_RGB2GRAY);
Mat d1, d2, result;
int window = 200;
bool movement;
while (true){
movement = false;
absdiff(next_frame, current_frame, d1);
absdiff(current_frame, prev_frame, d2);
bitwise_xor(d1, d2, result);
int middle_y = result.rows/2;
int middle_x = result.cols/2;
// Center window
threshold(result, result, 140, 255, CV_THRESH_BINARY);
for(int i = middle_x-window; i < middle_x+window; i++)
for(int j = middle_y-window; j < middle_y+window; j++)
if(result.at<int>(j,i)>0)
{
movement = true;
break;
}
if(movement==true)
saveImg(original,DIR,EXT,DIR_FORMAT.c_str(),FILE_FORMAT.c_str());
imshow("Motion", result);
prev_frame = current_frame;
current_frame = next_frame;
// get image from webcam
next_frame = cvQueryFrame(camera);
cvtColor(next_frame, next_frame, CV_RGB2GRAY);
break;
}
return 0;
}

Your problem is filenames limit. All images, taken in the same second have the same filenames. As solution I can suggest use milliseconds, or add some counter incrementing after image written to disk, and resetind every new second. You need add this counter value to filename.

Related

std::thread and ros::ok() do not work in ROS

I have a function that is executing by std::thread. I want it works until the user closes the terminal that running roscore by pressing Ctrl+C. Because of that I use this inside the thread:
void publish_camera_on_topic(std::vector<Camera> cameras, const std::vector<ros::Publisher> publishers, const int camera_index)
{
int frameSize;
BYTE *imagePtr;
// frame id
int frame_id = 0;
cv_bridge::CvImage img_bridge;
sensor_msgs::Image img_msg;
while (ros::ok()) {
// Grab and display a single image from each camera
imagePtr = cameras[camera_index].getRawImage();
frameSize = cameras[camera_index].getFrameSize();
cameras[camera_index].createRGBImage(imagePtr,frameSize);
unsigned char* pImage = cameras[camera_index].getImage();
if (NULL != pImage) {
Mat image(cameras[camera_index].getMatSize(), CV_8UC3, pImage, Mat::AUTO_STEP);
// release asap
cameras[camera_index].releaseImage();
//cvtColor(image, image, CV_BGR2RGB,3);
// publish on ROS topic
std_msgs::Header header; // empty header
header.seq = frame_id; // user defined counter
header.stamp = ros::Time::now(); // time
img_bridge = cv_bridge::CvImage(header, sensor_msgs::image_encodings::RGB8, image);
img_bridge.toImageMsg(img_msg); // from cv_bridge to sensor_msgs::Image
publishers[camera_index].publish(img_msg); // ros::Publisher pub_img = node.advertise<sensor_msgs::Image>("topic", queuesize);
}
// increase frame Id
frame_id = frame_id + 1;
}
std::cout << "ROS closing for thread of camera " << camera_index << " recieved." << std::endl;
}
Also, I create thread like this:
// image publisher
// for each camera create an publisher
std::vector<ros::Publisher> publishers;
for (size_t i = 0; i < cameras.size(); i++) {
char topic_name[200];
sprintf(topic_name, "/lumenera_camera_package/%d", i + 1);
publishers.push_back(nh.advertise<sensor_msgs::Image>(topic_name, 10));
}
// work with each camera on a seprate thread
std::vector<std::thread> thread_vector;
for(size_t i=0; i < cameras.size(); i++) {
thread_vector.push_back(std::thread(publish_camera_on_topic, cameras, publishers, i));
}
ros::spin();
std::for_each(thread_vector.begin(), thread_vector.end(), [](std::thread &t){t.join(); });
for(size_t i=0; i < cameras.size(); i++) {
cameras[i].stopStreaming();
}
ROS_INFO("Node: [lumenera_camera_node] has been Ended.");
However, when I press Ctrl+C in the terminal and stop the roscore, the threads keep running, and the value of ros::ok() does not change.
The problem is solved. The issue is ros::ok() does not check for ROS master. Instead of this line:
while (ros::ok()) { //do sth}
This line should be used:
while (ros::ok() && ros::master::check()) { // do sth}

Debug glibc free(): invalid pointer

I'm trying to debug code that eventually throws
*** glibc detected *** ./build/smonitor: free(): invalid pointer:
Its challenging because I don't use free... I've seen the other SO posts that have examples replicating the issue.. I need help on how to debug. First off, I'm a C/C++ n00b so my pointer skills are in-development but I'm not doing much dynamic memory allocation (I think).
I'm starting to write my own 'security' application where I take snapshots from cameras and write them to a NFS share, I'll eventually have a display of each camera's snapshot. Right now, I take captures from 1 camera and cycle them through my display window (using opencv). I can run for a while (~hour) before I get the core dump. I create a thread to run the window, I should loop until my run flag gets set to false and then I call cvReleaseImage.. I have no idea why this is failing, any guidance is greatly appreciated!
// will be replaced with camera X filename on NFS share
std::string generate_filename()
{
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
std::string filename = "";
std::stringstream ss;
for (int i = 0; i < 10; i++)
{
ss << alphanum[rand() % (sizeof(alphanum) - 1)];
}
ss << ".jpg";
printf("Generated filename: %s\n", ss.str().c_str());
return ss.str();
}
std::string generate_file_path()
{
std::stringstream ss;
ss << CAPTURES_PATH << generate_filename();
return ss.str();
}
void capture_photo(std::string& filepath)
{
time_t now;
time_t end;
double seconds;
bool cancelCapture = false;
int count = 0;
CvCapture* capture = cvCreateCameraCapture(0);
printf(“Opened camera capture\n");
IplImage* frame;
while(1)
{
frame = cvQueryFrame(capture);
if (!frame)
{
fprintf(stderr, "Could not read frame from video stream\n\n");
} else
{
cvShowImage(WINDOW, frame);
cvWaitKey(100);
if (get_snapshot_enabled()) // simulate delay between snapshots
{
filepath = generate_file_path();
printf("Saving image\n");
cvSaveImage(filepath.c_str(), frame);
break;
}
}
}
printf("Ending camera capture\n");
cvReleaseCapture(&capture);
}
void* manage_window(void* arg)
{
time_t now;
time_t end;
double seconds = 0;
double stateSec;
int i = 0;
int rem = 0;
IplImage* images[10];
time_t lastUpdate;
time_t tDiff; // time diff
cvNamedWindow(WINDOW, CV_WINDOW_FREERATIO);
cvSetWindowProperty(WINDOW, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
std::string filepath;
time(&now);
int lastPos = 0;
while (1)
{
if (get_snapshot_enabled())
{
write_console_log("Going to capture photo\n");
// camera was selected
filepath = generate_file_path();
printf("Generated filepath: %s\n", filepath.c_str());
capture_photo(filepath);
if (!filepath.empty())
{
printf("Received filepath: %s\n", filepath.c_str());
time(&now);
images[lastPos] = cvLoadImage(filepath.c_str());
cvShowImage(WINDOW, images[lastPos]);
cvWaitKey(100);
if (lastPos == 10) lastPos = 0;
else lastPos++;
}
}
time(&end);
seconds = difftime(end, now);
if (seconds >= 5)
{
cvShowImage(WINDOW, images[ i % 10])
cvWaitKey(100);
i++;
time(&now);
}
// check if we're running
if (!get_running())
{
// log some error we're not running...
write_logs("Window thread exiting, not running...");
break;
}
}
for (i=0; i < 10; i++)
cvReleaseImage(&images[i]);
pthread_exit(NULL);
}
In void* manage_window(void* arg) there are lines
IplImage* images[10];
and
images[lastPos] = cvLoadImage(filepath.c_str());
if (lastPos == 10) lastPos = 0;
else lastPos++;
where lastPos can be incremented to 10, leading to
images[10] = cvLoadImage(filepath.c_str());
i.e. invalid write beyond the end of array. I think something like valgrind would have detected this.

Read an image from a qrc using imread() of OpenCV

I want to read an image from a qrc using imread() of OpenCV in this way:
Mat img = imread(":/TempIcons/logo.png");
but the final img size is [0x0]. I have also tried:
Mat img = imread("qrc://TempIcons/logo.png");
but the size I get is the same. I don't want to load the image in a QImage to then transform it in a cv::Mat. Is there a way to do this in a easy way?. If it is, how can I do it?.
Thank you
As #TheDarkKnight pointed out, imread is not aware of Qt resources. You can however write your own loader, that uses QFile to retrieve the binary data from the resource, and uses imdecode (as done internally by imread) to read the image:
Mat loadFromQrc(QString qrc, int flag = IMREAD_COLOR)
{
//double tic = double(getTickCount());
QFile file(qrc);
Mat m;
if(file.open(QIODevice::ReadOnly))
{
qint64 sz = file.size();
std::vector<uchar> buf(sz);
file.read((char*)buf.data(), sz);
m = imdecode(buf, flag);
}
//double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
//qDebug() << "OpenCV loading time: " << toc;
return m;
}
You can call it like:
Mat m = loadFromQrc("qrc_path");
or specifying a flag:
Mat m = loadFromQrc("qrc_path", IMREAD_GRAYSCALE);
Performance
I tried loading the image with loadFromQrc, and loading the QImage and converting to Mat using this code, both with and without cloning. loadFromQrc results to be 10 time faster then loading a QImage and convert it to Mat.
Results in ms:
Load Mat : 4.85965
QImage to Mat (no clone): 49.3999
QImage to Mat (clone) : 49.8497
Test code:
#include <vector>
#include <iostream>
#include <QDebug>
#include <QtWidgets>
#include <opencv2/opencv.hpp>
using namespace cv;
Mat loadFromQrc(QString qrc, int flag = IMREAD_COLOR)
{
QFile file(qrc);
Mat m;
if(file.open(QIODevice::ReadOnly))
{
qint64 sz = file.size();
std::vector<uchar> buf(sz);
file.read((char*)buf.data(), sz);
m = imdecode(buf, flag);
}
return m;
}
cv::Mat QImageToCvMat( const QImage &inImage, bool inCloneImageData = true )
{
switch ( inImage.format() )
{
// 8-bit, 4 channel
case QImage::Format_RGB32:
{
cv::Mat mat( inImage.height(), inImage.width(), CV_8UC4, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine() );
return (inCloneImageData ? mat.clone() : mat);
}
// 8-bit, 3 channel
case QImage::Format_RGB888:
{
if ( !inCloneImageData )
qWarning() << "ASM::QImageToCvMat() - Conversion requires cloning since we use a temporary QImage";
QImage swapped = inImage.rgbSwapped();
return cv::Mat( swapped.height(), swapped.width(), CV_8UC3, const_cast<uchar*>(swapped.bits()), swapped.bytesPerLine() ).clone();
}
// 8-bit, 1 channel
case QImage::Format_Indexed8:
{
cv::Mat mat( inImage.height(), inImage.width(), CV_8UC1, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine() );
return (inCloneImageData ? mat.clone() : mat);
}
default:
qWarning() << "ASM::QImageToCvMat() - QImage format not handled in switch:" << inImage.format();
break;
}
return cv::Mat();
}
int main(int argc, char *argv[])
{
QString url = "...";
{
double tic = double(getTickCount());
Mat m1 = loadFromQrc(url);
double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
qDebug() << "Load Mat: " << toc;
if(m1.data != NULL)
{
imshow("m1", m1);
waitKey(1);
}
}
// {
// double tic = double(getTickCount());
// QImage img;
// img.load(url);
// Mat m2 = QImageToCvMat(img, false);
// double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
// qDebug() << "QImage to Mat (no clone): " << toc;
// if(m2.data != NULL)
// {
// imshow("m2", m2);
// waitKey(1);
// }
// }
// {
// double tic = double(getTickCount());
// QImage img;
// img.load(url);
// Mat m3 = QImageToCvMat(img, true);
// double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
// qDebug() << "QImage to Mat (clone): " << toc;
// if(m3.data != NULL)
// {
// imshow("m3", m3);
// waitKey(1);
// }
// }
waitKey();
return 0;
}
The problem here is that imread() loads an image from a file.
In contrast, Qt's resource system compiles the data from images directly into the program's executable. Qt's QFile operations know that when they are provided a path starting with ":/", it refers to the embedded resources, rather than on disk.
Therefore, I don't think you will be able to use imread() to directly access a file that has been placed in Qt's resources.

opencv imshow with waitKey too slow on Mac OS X 10.10.2 (using c++)

I am using opencv c++ on Mac OS X 10.10.2 to process video frames and display them. The performance of imshow with waitKey to display the video is extremely slow.
I have the following code which displays HD (1920x1080) grayscale frames correctly, except that it runs about 10 times too slow (i.e. 2 to 3 frames per second instead of 30 frames per second).
cv::Mat framebuf[TEST_COUNT];
//--- Code here to allocate and fill the frame buffer with about 4 seconds of video. This part works correctly.
//--- This loop runs too slow by factor of approximately 10x
for (int f = 0; f < TEST_COUNT; f++)
{
cv::imshow(windowName, framebuf[f]);
cv::waitKey(33);
}
Can anyone suggest how to get real-time or near real-time performance from opencv imshow()? I have seen many posts that state that they are displaying video in real-time or even faster than real-time, so I am not sure what I am doing wrong. Any help would be greatly appreciated.
I could be wrong but for me the problem is not with your code, but with your os/configuration. I've written a small test:
import cv2
import numpy as np
from random import randrange
img = np.zeros((1920, 1080), dtype = np.uint8)
counter = 0
while counter < 1000:
cv2.line(img, (randrange(0, 1920), randrange(0, 1080)), (randrange(0, 1920), randrange(0, 1080)), (randrange(0, 255)))
cv2.imshow('test', img)
temp = cv2.waitKey(1)
counter += 1
print counter
On my machine (Core 2 duo 2,6Ghz x64, 8gb ram, ssd) it took about 30 seconds for this test to complete. Run it and if you will get significantly bigger time than definitelly something is wrong with your laptop/opencv configuration/etc. I've used OpenCV 2.4.x on Mac OS X (it was 10.9 i think) and it was running fine. Reinstalling OpenCV is the most obvious solution which comes to my mind. When you remove OpenCV, use brew to install it again - brew install opencv --with-tbb --with-python --with-ffpmeg (or something similar - check using brew options opencv) should be fine. First options tells brew to build opencv with tbb(thread building block - library for multithreading, sometimes can significantly improve speed), second to install python wrappers, and the last one to install ffmpeg(handle codecs etc).
You would have to reduce the input to the function wait key. Try using a lower number in the range of 2-5. It also depends on the other processes you have running simultaneously, try shutting down other processes and see if it improves
you can create your own window to show the image. Add MyWindow.m MyWindow.h file to project.
MyWindow.h
#ifndef MY_WINDOW_H
#define MY_WINDOW_H
#ifdef __cplusplus
extern "C" {
#endif
void* createNSWindow(int x, int y, int w, int h);
void renderNSWindow(void* inwindow, void* data, int w, int h, int c);
void processNSEvent();
#ifdef __cplusplus
}
#endif
#endif
usage, in main.cpp, do not forget waitKey
#include "MyWindow.h"
// need create a cv window and do nothing
cv::namedWindow("xxx", 1);
// create window
void* w = createNSWindow(0, 0, 0, 0);
// frame image
cv::Mat frameImage;
// render loop
renderNSWindow(w, frameImage.data, frameImage.cols, frameImage.rows, frameImage.channels());
// need waitKey to display window
processNSEvent();
implement, in MyWindow.m, delete import "MyWindow.h"
#import <Cocoa/Cocoa.h>
#interface MyWindow : NSWindow
#property(nonatomic, strong) NSImageView *imgv;
#end
#implementation MyWindow
#end
static NSImage* _createNSImage(void* data, int w, int h, int c);
void* createNSWindow(int x, int y, int w, int h) {
NSRect screenFrame = [[NSScreen mainScreen] frame];
NSRect frame = NSMakeRect(x, y, w, h);
if (w == 0 || h == 0) {
frame = screenFrame;
}
MyWindow* window = [[MyWindow alloc] initWithContentRect:frame
styleMask:NSWindowStyleMaskBorderless
backing:NSBackingStoreBuffered
defer:NO] ;
//_initApp(window);
[window makeKeyAndOrderFront:NSApp];
window.titleVisibility = TRUE;
window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled |NSWindowStyleMaskFullSizeContentView;
window.imgv = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
[window.contentView addSubview:window.imgv];
return (void*)CFBridgingRetain(window);
}
static NSImage* _createNSImage(void* data, int w, int h, int c) {
size_t bufferLength = w * h * c;
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, bufferLength, NULL);
size_t bitsPerComponent = 8;
size_t bitsPerPixel = c * bitsPerComponent;
size_t bytesPerRow = c * w;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast;
if (c < 4) {
bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNone;
unsigned char* buf = data;
for(int i = 0; i < w*h; i++) {
unsigned char temp = buf[i*c];
buf[i*c] = buf[i*c+c-1];
buf[i*c+c-1] = temp;
}
}
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef iref = CGImageCreate(w,
h,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorSpaceRef,
bitmapInfo,
provider, // data provider
NULL, // decode
YES, // should interpolate
renderingIntent);
NSImage* image = [[NSImage alloc] initWithCGImage:iref size:NSMakeSize(w, h)];
return image;
}
void renderNSWindow(void* inwindow, void* data, int w, int h, int c) {
MyWindow* window = (__bridge MyWindow*)inwindow;
window.imgv.image = _createNSImage(data, w, h, c);
}
void processNSEvent() {
for (;;)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event == nil)
break;
[NSApp sendEvent:event];
}
}
other things, the waitKey now take about 20ms, you can do OpenCV in background thread, and show window in main thread. Also use processNSEvent instead of waitKey that only take about 10ms.
full source code:
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <dispatch/dispatch.h>
#include "MyWindow.h"
using namespace std;
using namespace cv;
int opencvfunc(int argc, const char *argv[]);
bool newFrame = false;
cv::Mat back_frame;
int main(int argc, const char * argv[]) {
cv::namedWindow("render", 1);
void* w = createNSWindow(0, 0, 0, 0);
dispatch_queue_t opencvq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_async(opencvq, ^{
opencvfunc(argc, argv);
});
while(true) {
usleep(3*1000);
if(newFrame) {
std::chrono::system_clock::time_point starttime = std::chrono::system_clock::now();
renderNSWindow(w, back_frame.data, back_frame.cols, back_frame.rows, back_frame.channels());
newFrame = false;
//auto key = cv::waitKey(1);
//if (key == 'q') {
// break;
//}
processNSEvent();
std::chrono::system_clock::time_point endtime = std::chrono::system_clock::now();
std::cout << "imshow:" << std::chrono::duration_cast<std::chrono::duration<double>>(endtime-starttime).count()*1000 << std::endl;
}
}
return 0;
}
int opencvfunc(int argc, const char *argv[]) {
cv::VideoCapture cap;
cap.open(0);
if (!cap.isOpened()) {
std::cout << "Couldn't open camera 0." << endl;
return EXIT_FAILURE;
}
Mat frame, unmodified_frame;
for (;;) {
cap >> frame; // get a new frame from camera
if (frame.empty()) { // stop if we're at the end of the video
break;
}
//unmodified_frame = frame.clone();
// ...
back_frame = frame.clone();
newFrame = true;
}
return EXIT_SUCCESS;
}
OpenCV 4 had resolved this issue, please update to new version.
One more thing, process video and show video in two thread.
#include <stdio.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <dispatch/dispatch.h>
using namespace cv;
using namespace std;
bool newFrame = false;
Mat back_frame;
int opencvmain(int argc, char** argv ) {
// open camear
cv::VideoCapture cap;
cap.open(0);
if (!cap.isOpened()) {
std::cout << "Couldn't open camera 0." << std::endl;
return EXIT_FAILURE;
}
// define frame images
cv::Mat frame;
// frame loop
for (;;) {
// get video frame
cap >> frame;
if (frame.empty()) {
break;
}
// render
back_frame = frame.clone();
newFrame = true;
}
return 0;
}
int main(int argc, char** argv ) {
namedWindow("video", WINDOW_AUTOSIZE );
dispatch_queue_t opencvq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(opencvq, ^{
opencvmain(argc, argv);
});
while(true) {
usleep(3*1000);
if(newFrame) {
imshow("video", back_frame);
auto key = cv::waitKey(1);
if (key == ' ') {
break;
}
newFrame = false;
}
}
return 0;
}

How can I know if a image is RGB in OpenCV?

I've made a program in c++ using OpenCV library. The program record video from webcam and then split it in frames. I want to know if the frames are in RGB beacuse i want to access the RGB properties of every pixel. The codec for capture is CV_FOURCC('M','J','P','G'). How can i get the frames in RGB colorspace?
int main() {
Mat image;
VideoCapture cap(0);
cap.set(CV_CAP_PROP_FPS, 10);
if ( !cap.isOpened() ) {
cout << "ERROR : Cannot open the video file"<<endl;
return -1;
}
namedWindow("MyWindow", CV_WINDOW_AUTOSIZE);
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "Frame size :" << dWidth << "x" << dHeight << endl;
Size frameSize(static_cast<int>(dWidth), static_cast<int>(dHeight));
VideoWriter oVideoWriter("E:/myVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 10, frameSize, true);
if (!oVideoWriter.isOpened()) {
cout << "ERROR : Failed to write the video"<<endl;
return - 1;
}
while (1) {
Mat image;
bool bSuccess = cap.read(image);
if (!bSuccess) {
cout << "ERROR : Cannot read a frame from video file" << endl;
break;
}
oVideoWriter.write(image);
imshow("MyWindow", image);
if (waitKey(10) == 27) {
saveImages();
cout << "ESC key is pressed by user" << endl;
break
}
}
return 0;
}
int saveImages() {
CvCapture *capture = cvCaptureFromFile("E:/myVideo.avi");
if(!capture)
{
cout<<"!!! cvCaptureFromAVI failed (file not found?)"<<endl;
return -1;
}
int fps = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
IplImage* frame = NULL;
int frame_number = 0;
char key = 0;
while (key != 'q')
{
frame = cvQueryFrame(capture);
if (!frame)
{
cout<<"!!! cvQueryFrame failed: no frame"<<endl;
break;
}
char filename[100];
strcpy(filename, "frame_");
char frame_id[30];
_itoa(frame_number, frame_id, 10);
strcat(filename, frame_id);
strcat(filename, ".jpg");
printf("* Saving: %s\n", filename);
if (!cvSaveImage(filename, frame))
{
cout<<"!!! cvSaveImage failed"<<endl;
break;
}
frame_number++;
key = cvWaitKey(1000 / fps);
}
cvReleaseCapture(&capture);
return 0;
}
When OpenCV loads colored images (i.e. 3 channel) from the disk, camera, or a video file, the image data will be stored in the BGR format. This is a simple test that you can do:
/* Code using the C++ API */
cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cout << "!!! Failed to open webcam" << std::endl;
return -1;
}
if (!cap.read(frame)) {
std::cout << "!!! Failed to read a frame from the camera" << std::endl;
return -1;
}
bool is_colored = false;
if (frame.channels() == 3) {
is_colored = true;
}
// Do something with is_colored
// ...
Unless you have a weird camera, the frames will always be colored (and as result, stored as BGR).
When cv::imwrite() (C++ API) or cvSaveImage() (C API) are called, OpenCV does the proper magic tricks to ensure the data is saved in a compatible way with requested output format (JPG, PNG, AVI, etc) and during this process it automatically converts the data to RGB if it needs to.
Nevertheless, if for some reason you need to convert the image to RGB you can call:
cv::Mat img_rgb;
cv::cvtColor(frame, img_rgb, CV_BGR2RGB);
Please note that OpenCV has a C API and also a C++ API, and they shouldn't be mixed:
If you use IplImage then stick with the rest of the C API.
If you decide to go with cv::Mat, then keep using the C++ API.
There are different ways to access the pixels of a cv::Mat, here is one of them:
unsigned char* pixels = (unsigned char*)(frame.data);
for (int i = 0; i < frame.rows; i++)
{
for (int j = 0; j < frame.cols; j++)
{
char b = pixels[frame.step * j + i] ;
char g = pixels[frame.step * j + i + 1];
char r = pixels[frame.step * j + i + 2];
}
}