0

I want to call the cv::VideoCapture constructor conditionally. If argc == 2, then the user has specified a video file and I want to load that. Otherwise use the default camera.

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;

int main(int argc, char* argv[])
{
    VideoCapture cap(argc == 2 ? argv[1] : 0);

    return 0;
}

I compile and run it

$ g++ -g -Wall -o main main.cpp `pkg-config opencv --cflags --libs`
$ ./main

But sadly it doesn't seem to work and I get

OpenCV: Couldn't read movie file ""

The ternary operator returns a string in one case and an integer in another. I reckon this won't work because of some idiosyncrasy of C++ constructors I'm not aware of.

What's the cleanest way to do what I want? Can I do it without using new so that I don't have to free memory myself at the end of the program?

fabiomaia
  • 592
  • 9
  • 19
  • 1
    Have you tried looping throgh each arg to make sure the second one is actually the arg you expect? It looks like even though you dont parse any args when running the executable you still get a total of 2 args. Maybe try args==3 and args[2] –  Dec 05 '17 at 21:42
  • @stav I checked, `argc` is 1 when I don't pass the program any arguments and `2` when I pass it a filename. I also looped through `argv` and it looks alright. – fabiomaia Dec 05 '17 at 21:58

2 Answers2

5

You're over-complicating this. Use open:

VideoCapture cap;
if(argc == 2) {
    cap.open(argv[1]); // calls: open(const String& filename)
} else {
    cap.open(0);       // calls: open(int index) 
}

In the ternary operator the two operands must be of the same type. See here for details. But yours have type int and char*, so, even of the code may compile, it can result in runtime errors.

Miki
  • 40,887
  • 13
  • 123
  • 202
  • Thanks, that works well! Truthfully I just wanted to get this over with. Your answer fixes the fundamental issue at hand and is arguably cleaner than my "hack". However the question itself is about why calling the constructor like that doesn't work. And I'm actually curious as to why now. So I think I'll wait for an answer to that. – fabiomaia Dec 06 '17 at 00:16
1

Expression A ? B : C has a return type of B and C must be implicitly convertible to B. Some compilers will not compile (best behavior), some will. In your case, B = char * and C = int. I believe 0 is interpreted as pointer to address 0 or NULL whose byte equal '\0' i.e. null-termination character that marks the end of a C-style string hence the empty string.

If you insist on a one-liner, then:

std::unique_ptr<VideoCapture> capture = (argc == 2 ? std::make_unique<VideoCapture>(argv[1]) : std::make_unique<VideoCapture>(0));
RCYR
  • 1,452
  • 13
  • 28