While collecting very large numbers of screen captures for writing documentation, I noticed that it takes far too long to filter out the junk.
To fix this, I coded up yn (source code via github). Given a list of images, it will display each one to the user, which they then include by pressing Y (yes) or exclude by pressing N (no) (hence the name yn).
The images which are selected are saved as a list, so that a script can continue by processing them in some way. This could be by copying them elsewhere, or generating a document with spaces to caption them. The example in the README.md does both of these.
The code to this early version is very simple, which makes it a good example of a simple OpenCV C++ app. I’ve stepped through it below.
The code
C++ does console input and output via the iostream library:
#include <iostream>
To use OpenCV with a GUI, you need these headers. You then need to add them to your include path, and link to OpenCV for the program to compile:
#include <cv.h>
#include <highgui.h>
This line simly tells the compiler that when we say cout (console out), we mean std::cout.
using namespace std;
The only OpenCV code is in the below function. The steps are:
- load an image from a file via imread(),
- display it in a window with imshow(),
- capture the next keypress with waitKey(), then
- delete the window with destroyWindow()
/**
* Load a file, and wait for the user to press a key.
*
* If the pressed key is 'y', print the filename.
*/
bool yn(string fn) {
cv::Mat img;
char key = 0;
img = cv::imread(fn);
if(!img.data) {
cerr << "Failed to load " << fn << endl;
} else {
cv::namedWindow(fn);
cv::imshow(fn, img);
key = cv::waitKey(0);
cv::destroyWindow(fn);
if(key == 'y') {
cout << fn << endl; // 'y' pressed
} else if(key == 0x1B) {
return false; // ESC pressed
}
}
return true;
}
So with that library usage out of the way, all we need to do is get the list of files to check, and stop popping up windows when the user has pressed the escape key.
/**
* Get list of files from command-line arguments and display them in turn
*/
int main(int argc, char** argv) {
int i;
/* Command-line arguments given */
for(i = 1; i < argc; i++) {
if(yn(string(argv[i])) == false) {
cerr << "Quitting.\n";
break;
}
}
return 0;
}
Next
The delay between images appearing can be removed by loading them in a separate thread, which I may do in a future version.