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

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

Related

Video frame returning !_src.empty() in function 'cvtColor' error [duplicate]

This question already has answers here:
imread returns None, violating assertion !_src.empty() in function 'cvtColor' error
(22 answers)
Closed 8 months ago.
I am trying to convert frames from a video to Tensors as the video is playing. This is my code:
#include <iostream>
#include "src/VideoProcessing.h"
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
typedef cv::Point3_<float> Pixel;
const uint WIDTH = 224;
const uint HEIGHT = 224;
const uint CHANNEL = 3;
const uint OUTDIM = 128;
void normalize(Pixel &pixel){
pixel.x = (pixel.x / 255.0 - 0.5) * 2.0;
pixel.y = (pixel.y / 255.0 - 0.5) * 2.0;
pixel.z = (pixel.z / 255.0 - 0.5) * 2.0;
}
int main() {
int fps = VideoProcessing::getFPS("trainer.mp4");
unsigned long size = VideoProcessing::getSize("trainer.mp4");
cv::VideoCapture cap("trainer.mp4");
//Check if input video exists
if(!cap.isOpened()){
std::cout<<"Error opening video stream or file"<<std::endl;
return -1;
}
//Create a window to show input video
cv::namedWindow("input video", cv::WINDOW_NORMAL);
//Keep playing video until video is completed
while(true){
cv::Mat frame;
frame.convertTo(frame, CV_32FC3);
cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB); // convert to float; BGR -> RGB
// normalize to -1 & 1
auto* pixel = frame.ptr<Pixel>(0,0);
const Pixel* endPixel = pixel + frame.cols * frame.rows;
for (; pixel != endPixel; pixel++){normalize(*pixel);}
// resize image as model input
cv::resize(frame, frame, cv::Size(WIDTH, HEIGHT));
//Capture frame by frame
bool success = cap.read(frame);
//If frame is empty then break the loop
if (!success){
std::cout << "Found the end of the video" << std::endl;
break;
}
//Show the current frame
cv::imshow("input video", frame);
if (cv::waitKey(10) == 27){
std::cout << "Esc key is pressed by user. Stopping the video" << std::endl;
break;
}
}
//Close window after input video is completed
cap.release();
//Destroy all the opened windows
cv::destroyAllWindows();
std::cout << "Video file FPS: " << fps << std::endl;
std::cout << "Video file size: " << size << std::endl;
return 0;
}
My goal (down the road) is to run inference on each frame to get landmarks. However, at this stage, I see this error:
terminate called after throwing an instance of 'cv::Exception'
what(): OpenCV(4.1.0) /home/onur/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
Aborted (core dumped)
Where am I going wrong?
You will have to read the frame before performing any conversion.
Move the part
//Capture frame by frame
bool success = cap.read(frame);
//If frame is empty then break the loop
if (!success){
std::cout << "Found the end of the video" << std::endl;
break;
}
Just after
cv::Mat frame;

Can't cat image from the videostream opencv

Other questions did't help me, so i ask mine
Can't get any image from my videocam using the latest opencv library.
void ShowCam(int CameraToBeOpened)
{
int i = 0;
cv::Mat frame;
cv::VideoCapture cap(CameraToBeOpened);
cvNamedWindow("Camera", CV_WINDOW_NORMAL);
while (true) {
if (cap.read(frame))
imshow("Camera", frame);
char c = cvWaitKey(50);
if (c == 27)
break;
if (c == 32) {
char filename[200];
sprintf_s(filename, "\Test pictures\test_%d.jpg", i);
i++;
cv::imwrite(filename, frame);
std::cout << "Image has been captured" << std::endl;
}
}
It doesn't generate mistakes, just can't find images in the folder.

Capturing video with monochrome camera in aruco opencv

I'm currently trying to use a monochrome camera with the aruco and opencv libraries in order to accelerate the computation and get better marker capturing. The problem i am having is that the monochrome feed is being tripled on screen when running the aruco_test program and so the resolution in diminished by two thirds and the markers are being detected three times each instead of one.
I saw feeds which talk about similar problems with monochrome cameras in opencv. Some answers suggested cropping the image (which fixes the tripling problem but not the smaller resolution) but it all seems to be caused by the conversion from either BGR2GRAY or GRAY2BGR.
Any help on what exactly is causing the images being tripled and how to bypass that part either in the aruco source code or opencv source code would be appreciated.
INFO :
Driver Info (not using libv4l2):
Driver name : uvcvideo
Card type : oCam-1MGN-U
Bus info : usb-0000:00:1d.0-1.5
Driver version: 3.13.11
Capabilities : 0x84000001
Video Capture
Streaming
Device Capabilities
Device Caps : 0x04000001
Video Capture
Streaming
Priority: 2
Video input : 0 (Camera 1: ok)
Format Video Capture:
Width/Height : 1280/960
Pixel Format : 'GREY'
Field : None
Bytes per Line: 1280
Size Image : 1228800
Colorspace : Unknown (00000000)
Crop Capability Video Capture:
Bounds : Left 0, Top 0, Width 1280, Height 960
Default : Left 0, Top 0, Width 1280, Height 960
Pixel Aspect: 1/1
Streaming Parameters Video Capture:
Capabilities : timeperframe
Frames per second: 30.000 (30/1)
Read buffers : 0
brightness (int) : min=0 max=127 step=1 default=64 value=64
exposure_absolute (int) : min=1 max=625 step=1 default=39 value=39
Using Aruco 2.0.19 and OpenCV 3.2
Pixel Format not being YUYV i cannot simply take the Y channel from the camera feed.
code executed :
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include "aruco.h"
#include "cvdrawingutils.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace aruco;
MarkerDetector MDetector;
VideoCapture TheVideoCapturer;
vector< Marker > TheMarkers;
Mat TheInputImage, TheInputImageCopy;
CameraParameters TheCameraParameters;
void cvTackBarEvents(int pos, void *);
pair< double, double > AvrgTime(0, 0); // determines the average time required for detection
int iThresParam1, iThresParam2;
int waitTime = 0;
class CmdLineParser{int argc; char **argv; public: CmdLineParser(int _argc,char **_argv):argc(_argc),argv(_argv){} bool operator[] ( string param ) {int idx=-1; for ( int i=0; i<argc && idx==-1; i++ ) if ( string ( argv[i] ) ==param ) idx=i; return ( idx!=-1 ) ; } string operator()(string param,string defvalue="-1"){int idx=-1; for ( int i=0; i<argc && idx==-1; i++ ) if ( string ( argv[i] ) ==param ) idx=i; if ( idx==-1 ) return defvalue; else return ( argv[ idx+1] ); }};
cv::Mat resize(const cv::Mat &in,int width){
if (in.size().width<=width) return in;
float yf=float( width)/float(in.size().width);
cv::Mat im2;
cv::resize(in,im2,cv::Size(width,float(in.size().height)*yf));
return im2;
}
int main(int argc, char **argv) {
try {
CmdLineParser cml(argc,argv);
if (argc < 2 || cml["-h"]) {
cerr << "Invalid number of arguments" << endl;
cerr << "Usage: (in.avi|live[:idx_cam=0]) [-c camera_params.yml] [-s marker_size_in_meters] [-d dictionary:ARUCO by default] [-h]" << endl;
cerr<<"\tDictionaries: "; for(auto dict:aruco::Dictionary::getDicTypes()) cerr<<dict<<" ";cerr<<endl;
cerr<<"\t Instead of these, you can directly indicate the path to a file with your own generated dictionary"<<endl;
return false;
}
/////////// PARSE ARGUMENTS
string TheInputVideo = argv[1];
// read camera parameters if passed
if (cml["-c"] ) TheCameraParameters.readFromXMLFile(cml("-c"));
float TheMarkerSize = std::stof(cml("-s","-1"));
//aruco::Dictionary::DICT_TYPES TheDictionary= Dictionary::getTypeFromString( cml("-d","ARUCO") );
/////////// OPEN VIDEO
// read from camera or from file
if (TheInputVideo.find("live") != string::npos) {
int vIdx = 0;
// check if the :idx is here
char cad[100];
if (TheInputVideo.find(":") != string::npos) {
std::replace(TheInputVideo.begin(), TheInputVideo.end(), ':', ' ');
sscanf(TheInputVideo.c_str(), "%s %d", cad, &vIdx);
}
cout << "Opening camera index " << vIdx << endl;
TheVideoCapturer.open(vIdx);
waitTime = 10;
}
else TheVideoCapturer.open(TheInputVideo);
// check video is open
if (!TheVideoCapturer.isOpened()) throw std::runtime_error("Could not open video");
///// CONFIGURE DATA
// read first image to get the dimensions
TheVideoCapturer >> TheInputImage;
if (TheCameraParameters.isValid())
TheCameraParameters.resize(TheInputImage.size());
MDetector.setDictionary(cml("-d","ARUCO"));//sets the dictionary to be employed (ARUCO,APRILTAGS,ARTOOLKIT,etc)
MDetector.setThresholdParams(7, 7);
MDetector.setThresholdParamRange(2, 0);
// MDetector.setCornerRefinementMethod(aruco::MarkerDetector::SUBPIX);
//gui requirements : the trackbars to change this parameters
iThresParam1 = MDetector.getParams()._thresParam1;
iThresParam2 = MDetector.getParams()._thresParam2;
cv::namedWindow("in");
cv::createTrackbar("ThresParam1", "in", &iThresParam1, 25, cvTackBarEvents);
cv::createTrackbar("ThresParam2", "in", &iThresParam2, 13, cvTackBarEvents);
//go!
char key = 0;
int index = 0;
// capture until press ESC or until the end of the video
do {
TheVideoCapturer.retrieve(TheInputImage);
// copy image
double tick = (double)getTickCount(); // for checking the speed
// Detection of markers in the image passed
TheMarkers= MDetector.detect(TheInputImage, TheCameraParameters, TheMarkerSize);
// chekc the speed by calculating the mean speed of all iterations
AvrgTime.first += ((double)getTickCount() - tick) / getTickFrequency();
AvrgTime.second++;
cout << "\rTime detection=" << 1000 * AvrgTime.first / AvrgTime.second << " milliseconds nmarkers=" << TheMarkers.size() << std::endl;
// print marker info and draw the markers in image
TheInputImage.copyTo(TheInputImageCopy);
for (unsigned int i = 0; i < TheMarkers.size(); i++) {
cout << TheMarkers[i]<<endl;
TheMarkers[i].draw(TheInputImageCopy, Scalar(0, 0, 255));
}
// draw a 3d cube in each marker if there is 3d info
if (TheCameraParameters.isValid() && TheMarkerSize>0)
for (unsigned int i = 0; i < TheMarkers.size(); i++) {
CvDrawingUtils::draw3dCube(TheInputImageCopy, TheMarkers[i], TheCameraParameters);
CvDrawingUtils::draw3dAxis(TheInputImageCopy, TheMarkers[i], TheCameraParameters);
}
// DONE! Easy, right?
// show input with augmented information and the thresholded image
cv::imshow("in", resize(TheInputImageCopy,1280));
cv::imshow("thres", resize(MDetector.getThresholdedImage(),1280));
key = cv::waitKey(waitTime); // wait for key to be pressed
if(key=='s') waitTime= waitTime==0?10:0;
index++; // number of images captured
} while (key != 27 && (TheVideoCapturer.grab() ));
} catch (std::exception &ex)
{
cout << "Exception :" << ex.what() << endl;
}
}
void cvTackBarEvents(int pos, void *) {
(void)(pos);
if (iThresParam1 < 3) iThresParam1 = 3;
if (iThresParam1 % 2 != 1) iThresParam1++;
if (iThresParam1 < 1) iThresParam1 = 1;
MDetector.setThresholdParams(iThresParam1, iThresParam2);
// recompute
MDetector.detect(TheInputImage, TheMarkers, TheCameraParameters);
TheInputImage.copyTo(TheInputImageCopy);
for (unsigned int i = 0; i < TheMarkers.size(); i++)
TheMarkers[i].draw(TheInputImageCopy, Scalar(0, 0, 255));
// draw a 3d cube in each marker if there is 3d info
if (TheCameraParameters.isValid())
for (unsigned int i = 0; i < TheMarkers.size(); i++)
CvDrawingUtils::draw3dCube(TheInputImageCopy, TheMarkers[i], TheCameraParameters);
cv::imshow("in", resize(TheInputImageCopy,1280));
cv::imshow("thres", resize(MDetector.getThresholdedImage(),1280));
}

extract frame from a video for detection with opencv

i'm developing a program to detect object in video or image.
It works with the image, but now i want to use it with video. I use a specific folder to pick the image so i wanted to save frames from video in that folder before the detection.
The variable video and salvataggio are alredy setted.
In the following code i navigate throw the folder to analize the video:
DIR *dir;
dir = opendir(video.c_str());
string vidName;
struct dirent *ent;
if (dir != NULL) {
while ((ent = readdir (dir)) != NULL) {
vidName= ent->d_name;
if(vidName.compare(".")!= 0 && vidName.compare("..")!= 0)
{
//string vidPath(neg + vidName);
estraiframe(video, vidName, salvataggio);
}
}
closedir (dir);
}
else {
cout<<"directory "<< video << " not present"<<endl;
}
}
The function estraiframe save the frame in the output folder.
void estraiframe(string path, string vidName, string output){
string vidPath(path + vidName);
VideoCapture cap(vidPath);
if( !cap.isOpened()){
cout << "Cannot open the video file" << endl;
return;
}
double count = cap.get(CV_CAP_PROP_FRAME_COUNT);
double rate = cap.get(CV_CAP_PROP_FPS);
int counter = 0;
for (int i=1; i< count; i+=rate*5)
{
cap.set(CV_CAP_PROP_POS_FRAMES,i);
Mat frame;
cap.read(frame);
counter++;
string nomeframe = to_string(counter) + "-frame_from"+vidName+".jpg";
string percorso (output+nomeframe);
cout << percorso;
imwrite(percorso,frame);
}
}
Apparently it works but after the last frame it gave me the following error:
Assertion stream_index < ogg->nstreams failed at libavformat/oggdec.c:898
I locked for it but i didin't find where is the error
Your video contains various stream indexes, e.g. 3 audios, and 1 video stream would result in 4 stream indexes. I recommend that you check the amount of streams your video contains and print ogg->nstreams to check if this corresponds. Looking at the source code in oggdec.c at line 898
static int ogg_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + stream_index;
int ret;
av_assert0(stream_index < ogg->nstreams); /* Line 898 */
You're clearly going out of bounds here.
Apparently I manage to solve it, I modified the function that extract the frame.
void estraiframe(string path, string vidName, string output){
string vidPath(path + vidName);
VideoCapture cap(vidPath);
if( !cap.isOpened()){
cout << "Cannot open the video file" << endl;
return;
}
double rate = cap.get(CV_CAP_PROP_FPS);
int counter = 0;
Mat frame;
int i=1;
while(1)
{
cap.read ( frame);
if( frame.empty()) break;
counter++;
if (counter == rate*5*i){
i++;
string nomeframe = to_string(counter) + "-frame_from"+vidName+".jpg";
string percorso (output+nomeframe);
imwrite(percorso, frame);
}
char key = waitKey(10);
if ( key == 27) break;
}
}

Write/save videostream if detection true

I want to write a videostream after detection is found true.
I use this link as Videowrite example
My code implementation looks like that:
int main(int argc, const char** argv) {
bool detection = false;
VideoCapture cap(-1);
if (!cap.isOpened())
{
printf("ERROR: Cannot open the video file");
}
namedWindow("MyVideo", 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 record ("/home/hacker/MyVideo.avi", CV_FOURCC('P','I','M','1'),
30, frameSize, true);
if (!record.isOpened())
{
printf("Error: Failed to write the video");
return -1;
}
while (true)
{
Mat frame;
if (!frame.empty())
{
detectAndDisplay(frame);
}
else
{
printf(" --(!) No captured frame -- Break!"); break;
}
if (detection == true)
{
record.write(frame);
}
char c = cvWaitKey(33);
if (c == 27) { break; }
}
return 0;
}
In my home directory I can see the Myvideo.avi but it's empty.
I got the following errors on command line:
VIDIOC_QUERMENU: Invalid argument
VIDIOC_QUERMENU: Invalid argument
Frame size: 640x480 Output #0, avi, to '/home/hacker/MyVideo.avi":
Stream #0.0: Video: mpeg1video (hq), yvu420p, 640x480, q=2-31, 19660
kb/s, 9ok tbn, 23,98 tbc
--(!) No captured frame -- Break! Process returned 0 (0x0) execution time: 0,75 s
You should release videowriter ( record.Release(); ). It closes file.
I try to solve it like this:
But i have 2 problems:
I want to save the MyVideo.avi if detecAndDisplay(frame) == true. But he saves it anyway(with an empty video record). And if that save the video recording is running faster.
int main( int argc, const char** argv ) {
Mat frame;
VideoCapture capture(-1); // open the default camera
if( !capture.isOpened() )
{
printf("Camera failed to open!\n");
return -1;
}
capture >> frame; // get first frame for size
for(;;)
{
// get a new frame from camera
capture >> frame;
//-- 3. Apply the classifier to the frame
if( !frame.empty() )
{
detectAndDisplay( frame );
}
if(detectAndDisplay(frame)==true)
{
// record video
VideoWriter record("MyVideo.avi", CV_FOURCC('D','I','V','X'), 30, frame.size(), true);
if( !record.isOpened() )
{
printf("VideoWriter failed to open!\n");
return -1;
}
// add frame to recorded
record << frame;
}
if(waitKey(30) >= 0) break;
}
return 0;
}
/** #function detectAndDisplay */
/** this function detect face draw a rectangle around and detect eye & mouth and draw a circle around */
bool detectAndDisplay( Mat frame ) {
...
...
return true;
}
This might be why your video file was empty.
bool detection = false;
...
if (detection == true)
{
record.write(frame);
}