Book Image

Learning OpenCV 3 Application Development

By : Samyak Datta
Book Image

Learning OpenCV 3 Application Development

By: Samyak Datta

Overview of this book

Computer vision and machine learning concepts are frequently used in practical computer vision based projects. If you’re a novice, this book provides the steps to build and deploy an end-to-end application in the domain of computer vision using OpenCV/C++. At the outset, we explain how to install OpenCV and demonstrate how to run some simple programs. You will start with images (the building blocks of image processing applications), and see how they are stored and processed by OpenCV. You’ll get comfortable with OpenCV-specific jargon (Mat Point, Scalar, and more), and get to know how to traverse images and perform basic pixel-wise operations. Building upon this, we introduce slightly more advanced image processing concepts such as filtering, thresholding, and edge detection. In the latter parts, the book touches upon more complex and ubiquitous concepts such as face detection (using Haar cascade classifiers), interest point detection algorithms, and feature descriptors. You will now begin to appreciate the true power of the library in how it reduces mathematically non-trivial algorithms to a single line of code! The concluding sections touch upon OpenCV’s Machine Learning module. You will witness not only how OpenCV helps you pre-process and extract features from images that are relevant to the problems you are trying to solve, but also how to use Machine Learning algorithms that work on these features to make intelligent predictions from visual data!
Table of Contents (16 chapters)
Learning OpenCV 3 Application Development
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface

Introduction to command-line arguments


Most of the OpenCV programs that we have written so far require explicitly taking some input from the user. For example, it is highly likely that an OpenCV program would require an image (or video) to operate upon, and hence, requires a path to that multimedia file as an input. Alternatively, similar to the case we discussed just now, our code might need to read some text file to obtain the input, and the program needs to know the path of that text file. Most of the image processing and vision algorithms come with a set of parameters that need to be a specified-size of filters used in smoothing, threshold values for image thresholding or edge detectors, pre-trained classifier files for face detection, and so on. These parameter values also need to be passed to our code, and command-line arguments are an effective tool to accomplish that.

We will motivate the need for command-line arguments using a small dummy example. Let's say that we need to write a piece of code that adds two numbers. What do you think such a code will require from the user as input parameters? The two numbers to add, of course. Now, assuming that you haven't heard of command-line arguments, how would you go about accomplishing this task? There are a couple of different techniques that come to mind:

  1. We could try hardcoding the values of the parameters in the source code itself (an approach we have been following throughout the major parts of the book).

  2. We could have the user type in the value of the parameters in response to a program-generated prompt after the code has begun its execution.

Let's see how both these approaches look for our small example. We'll start with approach (1):

#include<iostream> 
usingnamespacestd; 
 
int add(int x,int y) { 
    return(x + y); 
} 
 
int main() 
{ 
intnum1=10,num2=20; 
cout<<"Sum = "<< add(num1,num2)<<"\n"; 
    return0; 
} 

The problem with approach (1) is quite evident. If I want to test this code with 1000 different pairs of integers, I will have to make changes to the source code 1000 times and do as many re-compilations to get the outputs. Clearly, not something that can be scaled to a large data!

Now, moving on to approach (2), here is the same code, modified to take input through runtime prompts:

#include<iostream> 
usingnamespacestd; 
 
int add(int x,int y) { 
    return(x + y); 
} 
 
int main() 
{ 
intnum1,num2; 
cout<<"Enter 1st number : "; 
cin>>num1; 
 
cout<<"Enter 2nd number : "; 
cin>>num2; 
 
cout<<"Sum = "<< add(num1,num2)<<"\n"; 
    return0; 
} 

Now, the preceding approach obviously counters the drawback in (1)--we no longer need a separate re-compilation every single time. However, there is an added hassle of writing out the prompt messages, which can make your source code quite messy. In fact, there is a bigger reason for not being in support of (2). It doesn't resonate with the design principles of developing good, clean, and reusable software code. Imagine what happens when you call, say, the blur() function in OpenCV to smooth an image. Does it throw out messages during the course of its execution urging you to pass the necessary parameter values? No, you quietly pass all that blur() might need in the form of arguments along with the function call. There is an implicit understanding between the user (any entity that calls the blur() function) and the function itself, where the user knows the number and the kind of arguments that the function is expecting. This is the design principle that we had been alluding to.

How do we port the same design principle to the case of the source codes that we write? In Linux (or any UNIX-based system), when we want to execute a C++ program, we generally follow this sequence of steps:

  1. Compile the source code file by running, g++ addNumbers.cpp -o addNumbers.cpp. I have assumed that the preceding source code has been saved in a file, named addNumbers.cpp. This step should produce an executable file, named addNumbers.

  2. Run the executable file generated in the previous step by running the command:./addNumbers.

Now, wouldn't it be nice if we could somehow pass the arguments (parameters) to our source codes while we are running the executable from our command-line. This is exactly what command-line arguments accomplish! When we are using command-line arguments, we would run the executable by writing a command, such as:

./addNumbers 1020

The 10 and 20 here are the command-line arguments. They offer a much more orderly, compact, and convenient method to supply parameters in comparison to any of the previous techniques. Also, it is quite easy to see that the mechanism of command-line arguments is not conceptually very different from passing arguments to functions in C++.

Parsing command-line arguments

Keep in mind that the job is half-done. We still need to incorporate the logic to parse the command-line arguments in our source code. Here is how it's done:

#include<iostream> 
#include<cstdlib> 
 
usingnamespacestd; 
 
int add(int x,int y) { 
    return(x + y); 
} 
 
int main(intargc,char**argv) 
{ 
intnum1=atoi(argv[1]),num2=atoi(argv[2]); 
cout<<"Sum = "<< add(num1,num2)<<"\n"; 
    return0; 
} 

You might be seeing the argc and the argv variables for the first time. These are the two variables that allow us to access the arguments that were supplied from the command-line (the 10 and the 20) inside our source code. When we execute our program, the operating system calls the main() function and also provides the command-line arguments as parameters to main() (remember, main()is just like any other C++ function; it can accept parameters and return values).

The argc integer variable holds the number of command-line arguments and the argv is an array of string (char*) values that contain the command-line arguments as strings. Now, there is one more nuance to this. If you try printing the value of argc for the preceding piece of code, you will see a value of 3 instead of the 2 that you were expecting. Why does this happen? This is because the operating system treats the program name as one of the arguments as well! Refer to the following illustration:

This is the reason that the two numbers have been pulled out from argv[1] and argv[2] in our code (as shown in the illustration). The argv[0]variable is reserved for the program name.

There is another issue with the preceding code. The logic we have implemented assumes that the user will supply two arguments while running the program from the command line. What happens if the arguments are not provided to our code or if only one argument is provided? It is evident that in such a scenario, either argv[1]or argv[2] (or both) would be undefined, and hence, the preceding code will throw an exception. How do we overcome such a scenario? We will make use of the argc argument. Recall that argc holds the number of command-line parameters that have actually been passed to the program during execution. So, we check whether argc is equal to the number of expected arguments. If not, then we simply display an informative error message and quit! The code for the same has been shown as follows:

#include<iostream> 
#include<cstdlib> 
 
usingnamespacestd; 
 
int add(int x,int y) { 
    return(x + y); 
} 
 
int main(intargc,char**argv) 
{ 
if (arg != 2) { 
cout<< "The program expects two integer parameters.\n"; 
        return -1; 
 } 
 
intnum1=atoi(argv[1]),num2=atoi(argv[2]); 
cout<<"Sum = "<< add(num1,num2)<<"\n"; 
    return0; 
}