I'm now using VC++2008 and OpenCV2.1 on Windows 7. I'm trying out the facedetect.cpp example. When I run the program, it throws up a messagebox saying:
An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in Test Console 2.exe
Additional information: External component has thrown an exception.
Here's the entire code:
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include <iostream>
#include <cstdio>
using namespace std;
using namespace cv;
void detectAndDraw( Mat& img,
CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
double scale);
String cascadeName =
"C:/OpenCV2.1/data/haarcascades/haarcascade_frontalface_alt.xml";
String nestedCascadeName =
"C:/OpenCV2.1/data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
int main( int argc, const char** argv )
{
CvCapture* capture = 0;
Mat frame, frameCopy, image;
const String scaleOpt = "--scale=";
size_t scaleOptLen = scaleOpt.length();
const String cascadeOpt = "--cascade=";
size_t cascadeOptLen = cascadeOpt.length();
const String nestedCascadeOpt = "--nested-cascade";
size_t nestedCascadeOptLen = nestedCascadeOpt.length();
String inputName;
CascadeClassifier cascade, nestedCascade;
double scale = 1;
for( int i = 1; i < argc; i++ )
{
if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
cascadeName.assign( argv[i] + cascadeOptLen );
else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
{
if( argv[i][nestedCascadeOpt.length()] == '=' )
nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
if( !nestedCascade.load( nestedCascadeName ) )
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
}
else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
{
if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
scale = 1;
}
else if( argv[i][0] == '-' )
{
cerr << "WARNING: Unknown option %s" << argv[i] << endl;
}
else
inputName.assign( argv[i] );
}
if( !cascade.load( cascadeName ) )
{
cerr << "ERROR: Could not load classifier cascade" << endl;
cerr << "Usage: facedetect [--cascade=\"<cascade_path>\"]\n"
" [--nested-cascade[=\"nested_cascade_path\"]]\n"
" [--scale[=<image scale>\n"
" [filename|camera_index]\n" ;
return -1;
}
if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
else if( inputName.size() )
{
image = imread( inputName, 1 );
if( image.empty() )
capture = cvCaptureFromAVI( inputName.c_str() );
}
else
image = imread( "lena.jpg", 1 );
cvNamedWindow( "result", 1 );
if( capture )
{
for(;;)
{
IplImage* iplImg = cvQueryFrame( capture );
frame = iplImg;
if( frame.empty() )
break;
if( iplImg->origin == IPL_ORIGIN_TL )
frame.copyTo( frameCopy );
else
flip( frame, frameCopy, 0 );
detectAndDraw( frameCopy, cascade, nestedCascade, scale );
if( waitKey( 10 ) >= 0 )
goto _cleanup_;
}
waitKey(0);
_cleanup_:
cvReleaseCapture( &capture );
}
else
{
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale );
waitKey(0);
}
else if( !inputName.empty() )
{
/* assume it is a text file containing the
list of the image filenames to be processed - one per line */
FILE* f = fopen( inputName.c_str(), "rt" );
if( f )
{
char buf[1000+1];
while( fgets( buf, 1000, f ) )
{
int len = (int)strlen(buf), c;
while( len > 0 && isspace(buf[len-1]) )
len--;
buf[len] = '\0';
cout << "file " << buf << endl;
image = imread( buf, 1 );
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale );
c = waitKey(0);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
fclose(f);
}
}
}
cvDestroyWindow("result");
return 0;
}
The exception threw up at here:
if( !cascade.load( cascadeName ) )
{
cerr << "ERROR: Could not load classifier cascade" << endl;
cerr << "Usage: facedetect [--cascade=\"<cascade_path>\"]\n"
" [--nested-cascade[=\"nested_cascade_path\"]]\n"
" [--scale[=<image scale>\n"
" [filename|camera_index]\n" ;
return -1;
}
The rest of the code is working. When I comment the above part up, the rest of the entire code works. The camera window opens up, although obviously the face detection does not trigger.
Can someone tell me what's going on?
EDIT: I looked at the console during the exception and found this:
OpenCV error:NULL pointer <NULL filename> in unknown function , file ..\..\..\..\ocv\opencv\src\cxcore\cxpersistence.cpp, line 2568
What is that supposed to mean?
Did you load the cascade to trigger face detection ?
It seems that it cannot find the cascade path..
You need a cascade to use this face detection and write the path of this last in the command line when you run the program...
Method load() of CascadeClassifier takes a C++ std::string with the filename as input.
You are using the type String which is probably defined by Visual Studio somewhere. I'm not sure if these types are compatible, so you better stick with the one from #include <string>.
I think you should put the absolute path of the .xml file in the command line when you debug it. Because when open this kind of file a method of the standard string library is used, I think it just receive the absolute path.
Related
On Python, there is this option errors='ignore' for the open Python function:
open( '/filepath.txt', 'r', encoding='UTF-8', errors='ignore' )
With this, reading a file with invalid UTF8 characters will replace them with nothing, i.e., they are ignored. For example, a file with the characthers Føö»BÃ¥r is going to be read as FøöBår.
If a line as Føö»BÃ¥r is read with getline() from stdio.h, it will be read as Føö�Bår:
FILE* cfilestream = fopen( "/filepath.txt", "r" );
int linebuffersize = 131072;
char* readline = (char*) malloc( linebuffersize );
while( true )
{
if( getline( &readline, &linebuffersize, cfilestream ) != -1 ) {
std::cerr << "readline=" readline << std::endl;
}
else {
break;
}
}
How can I make stdio.h getline() read it as FøöBår instead of Føö�Bår, i..e, ignoring invalid UTF8 characters?
One overwhelming solution I can think of it do iterate throughout all characters on each line read and build a new readline without any of these characters. For example:
FILE* cfilestream = fopen( "/filepath.txt", "r" );
int linebuffersize = 131072;
char* readline = (char*) malloc( linebuffersize );
char* fixedreadline = (char*) malloc( linebuffersize );
int index;
int charsread;
int invalidcharsoffset;
while( true )
{
if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
{
invalidcharsoffset = 0;
for( index = 0; index < charsread; ++index )
{
if( readline[index] != '�' ) {
fixedreadline[index-invalidcharsoffset] = readline[index];
}
else {
++invalidcharsoffset;
}
}
std::cerr << "fixedreadline=" << fixedreadline << std::endl;
}
else {
break;
}
}
Related questions:
Fixing invalid UTF8 characters
Replacing non UTF8 characters
python replace unicode characters
Python unicode: how to replace character that cannot be decoded using utf8 with whitespace?
You are confusing what you see with what is really going on. The getline function does not do any replacement of characters. [Note 1]
You are seeing a replacement character (U+FFFD) because your console outputs that character when it is asked to render an invalid UTF-8 code. Most consoles will do that if they are in UTF-8 mode; that is, the current locale is UTF-8.
Also, saying that a file contains the "characters Føö»BÃ¥r" is at best imprecise. A file does not really contain characters. It contains byte sequences which may be interpreted as characters -- for example, by a console or other user presentation software which renders them into glyphs -- according to some encoding. Different encodings produce different results; in this particular case, you have a file which was created by software using the Windows-1252 encoding (or, roughly equivalently, ISO 8859-15), and you are rendering it on a console using UTF-8.
What that means is that the data read by getline contains an invalid UTF-8 sequence, but it (probably) does not contain the replacement character code. Based on the character string you present, it contains the hex character \xbb, which is a guillemot (») in Windows code page 1252.
Finding all the invalid UTF-8 sequences in a string read by getline (or any other C library function which reads files) requires scanning the string, but not for a particular code sequence. Rather, you need to decode UTF-8 sequences one at a time, looking for the ones which are not valid. That's not a simple task, but the mbtowc function can help (if you have enabled a UTF-8 locale). As you'll see in the linked manpage, mbtowc returns the number of bytes contained in a valid "multibyte sequence" (which is UTF-8 in a UTF-8 locale), or -1 to indicate an invalid or incomplete sequence. In the scan, you should pass through the bytes in a valid sequence, or remove/ignore the single byte starting an invalid sequence, and then continue the scan until you reach the end of the string.
Here's some lightly-tested example code (in C):
#include <stdlib.h>
#include <string.h>
/* Removes in place any invalid UTF-8 sequences from at most 'len' characters of the
* string pointed to by 's'. (If a NUL byte is encountered, conversion stops.)
* If the length of the converted string is less than 'len', a NUL byte is
* inserted.
* Returns the length of the possibly modified string (with a maximum of 'len'),
* not including the NUL terminator (if any).
* Requires that a UTF-8 locale be active; since there is no way to test for
* this condition, no attempt is made to do so. If the current locale is not UTF-8,
* behaviour is undefined.
*/
size_t remove_bad_utf8(char* s, size_t len) {
char* in = s;
/* Skip over the initial correct sequence. Avoid relying on mbtowc returning
* zero if n is 0, since Posix is not clear whether mbtowc returns 0 or -1.
*/
int seqlen;
while (len && (seqlen = mbtowc(NULL, in, len)) > 0) { len -= seqlen; in += seqlen; }
char* out = in;
if (len && seqlen < 0) {
++in;
--len;
/* If we find an invalid sequence, we need to start shifting correct sequences. */
for (; len; in += seqlen, len -= seqlen) {
seqlen = mbtowc(NULL, in, len);
if (seqlen > 0) {
/* Shift the valid sequence (if one was found) */
memmove(out, in, seqlen);
out += seqlen;
}
else if (seqlen < 0) seqlen = 1;
else /* (seqlen == 0) */ break;
}
*out++ = 0;
}
return out - s;
}
Notes
Aside from the possible line-end transformation of the underlying I/O library, which will replace CR-LF with a single \n on systems like Windows where the two character CR-LF sequence is used as a line-end indication.
As #rici well explains in his answer, there can be several invalid UTF-8 sequences in a byte sequence.
Possibly iconv(3) could be worth a look, e.g. see https://linux.die.net/man/3/iconv_open.
When the string "//IGNORE" is appended to tocode, characters that cannot be represented in the target character set will be silently discarded.
Example
This byte sequence, if interpreted as UTF-8, contains some invalid UTF-8:
"some invalid\xFE\xFE\xFF\xFF stuff"
If you display this you would see something like
some invalid���� stuff
When this string passes through the remove_invalid_utf8 function in the following C program, the invalid UTF-8 bytes are removed using the iconv function mentioned above.
So the result is then:
some invalid stuff
C Program
#include <stdio.h>
#include <iconv.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
char *remove_invalid_utf8(char *utf8, size_t len) {
size_t inbytes_len = len;
char *inbuf = utf8;
size_t outbytes_len = len;
char *result = calloc(outbytes_len + 1, sizeof(char));
char *outbuf = result;
iconv_t cd = iconv_open("UTF-8//IGNORE", "UTF-8");
if(cd == (iconv_t)-1) {
perror("iconv_open");
}
if(iconv(cd, &inbuf, &inbytes_len, &outbuf, &outbytes_len)) {
perror("iconv");
}
iconv_close(cd);
return result;
}
int main() {
char *utf8 = "some invalid\xFE\xFE\xFF\xFF stuff";
char *converted = remove_invalid_utf8(utf8, strlen(utf8));
printf("converted: %s to %s\n", utf8, converted);
free(converted);
return 0;
}
I also managed to fix it by trailing/cutting down all Non-ASCII characters.
This one takes about 2.6 seconds to parse 319MB:
#include <stdlib.h>
#include <iostream>
int main(int argc, char const *argv[])
{
FILE* cfilestream = fopen( "./test.txt", "r" );
size_t linebuffersize = 131072;
if( cfilestream == NULL ) {
perror( "fopen cfilestream" );
return -1;
}
char* readline = (char*) malloc( linebuffersize );
char* fixedreadline = (char*) malloc( linebuffersize );
if( readline == NULL ) {
perror( "malloc readline" );
return -1;
}
if( fixedreadline == NULL ) {
perror( "malloc fixedreadline" );
return -1;
}
char* source;
if( ( source = std::setlocale( LC_ALL, "en_US.utf8" ) ) == NULL ) {
perror( "setlocale" );
}
else {
std::cerr << "locale='" << source << "'" << std::endl;
}
int index;
int charsread;
int invalidcharsoffset;
unsigned int fixedchar;
while( true )
{
if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
{
invalidcharsoffset = 0;
for( index = 0; index < charsread; ++index )
{
fixedchar = static_cast<unsigned int>( readline[index] );
// std::cerr << "index " << std::setw(3) << index
// << " readline " << std::setw(10) << fixedchar
// << " -> '" << readline[index] << "'" << std::endl;
if( 31 < fixedchar && fixedchar < 128 ) {
fixedreadline[index-invalidcharsoffset] = readline[index];
}
else {
++invalidcharsoffset;
}
}
fixedreadline[index-invalidcharsoffset] = '\0';
// std::cerr << "fixedreadline=" << fixedreadline << std::endl;
}
else {
break;
}
}
std::cerr << "fixedreadline=" << fixedreadline << std::endl;
free( readline );
free( fixedreadline );
fclose( cfilestream );
return 0;
}
Alternative and slower version using memcpy
Using menmove does not improve much speed, so you could either one.
This one takes about 3.1 seconds to parse 319MB:
#include <stdlib.h>
#include <iostream>
#include <cstring>
#include <iomanip>
int main(int argc, char const *argv[])
{
FILE* cfilestream = fopen( "./test.txt", "r" );
size_t linebuffersize = 131072;
if( cfilestream == NULL ) {
perror( "fopen cfilestream" );
return -1;
}
char* readline = (char*) malloc( linebuffersize );
char* fixedreadline = (char*) malloc( linebuffersize );
if( readline == NULL ) {
perror( "malloc readline" );
return -1;
}
if( fixedreadline == NULL ) {
perror( "malloc fixedreadline" );
return -1;
}
char* source;
char* destination;
char* finalresult;
int index;
int lastcopy;
int charsread;
int charstocopy;
int invalidcharsoffset;
bool hasignoredbytes;
unsigned int fixedchar;
if( ( source = std::setlocale( LC_ALL, "en_US.utf8" ) ) == NULL ) {
perror( "setlocale" );
}
else {
std::cerr << "locale='" << source << "'" << std::endl;
}
while( true )
{
if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
{
hasignoredbytes = false;
source = readline;
destination = fixedreadline;
lastcopy = 0;
invalidcharsoffset = 0;
for( index = 0; index < charsread; ++index )
{
fixedchar = static_cast<unsigned int>( readline[index] );
// std::cerr << "fixedchar " << std::setw(10)
// << fixedchar << " -> '"
// << readline[index] << "'" << std::endl;
if( 31 < fixedchar && fixedchar < 128 ) {
if( hasignoredbytes ) {
charstocopy = index - lastcopy - invalidcharsoffset;
memcpy( destination, source, charstocopy );
source += index - lastcopy;
lastcopy = index;
destination += charstocopy;
invalidcharsoffset = 0;
hasignoredbytes = false;
}
}
else {
++invalidcharsoffset;
hasignoredbytes = true;
}
}
if( destination != fixedreadline ) {
charstocopy = charsread - static_cast<int>( source - readline )
- invalidcharsoffset;
memcpy( destination, source, charstocopy );
destination += charstocopy - 1;
if( *destination == '\n' ) {
*destination = '\0';
}
else {
*++destination = '\0';
}
finalresult = fixedreadline;
}
else {
finalresult = readline;
}
// std::cerr << "finalresult=" << finalresult << std::endl;
}
else {
break;
}
}
std::cerr << "finalresult=" << finalresult << std::endl;
free( readline );
free( fixedreadline );
fclose( cfilestream );
return 0;
}
Optimized solution using iconv
This takes about 4.6 seconds to parse 319MB of text.
#include <iconv.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
// Compile it with:
// g++ -o main test.cpp -O3 -liconv
int main(int argc, char const *argv[])
{
FILE* cfilestream = fopen( "./test.txt", "r" );
size_t linebuffersize = 131072;
if( cfilestream == NULL ) {
perror( "fopen cfilestream" );
return -1;
}
char* readline = (char*) malloc( linebuffersize );
char* fixedreadline = (char*) malloc( linebuffersize );
if( readline == NULL ) {
perror( "malloc readline" );
return -1;
}
if( fixedreadline == NULL ) {
perror( "malloc fixedreadline" );
return -1;
}
char* source;
char* destination;
int charsread;
size_t inchars;
size_t outchars;
if( ( source = std::setlocale( LC_ALL, "en_US.utf8" ) ) == NULL ) {
perror( "setlocale" );
}
else {
std::cerr << "locale='" << source << "'" << std::endl;
}
iconv_t conversiondescriptor = iconv_open("UTF-8//IGNORE", "UTF-8");
if( conversiondescriptor == (iconv_t)-1 ) {
perror( "iconv_open conversiondescriptor" );
}
while( true )
{
if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
{
source = readline;
inchars = charsread;
destination = fixedreadline;
outchars = charsread;
if( iconv( conversiondescriptor, &source, &inchars, &destination, &outchars ) )
{
perror( "iconv" );
}
// Trim out the new line character
if( *--destination == '\n' ) {
*--destination = '\0';
}
else {
*destination = '\0';
}
// std::cerr << "fixedreadline='" << fixedreadline << "'" << std::endl;
}
else {
break;
}
}
std::cerr << "fixedreadline='" << fixedreadline << "'" << std::endl;
free( readline );
free( fixedreadline );
if( fclose( cfilestream ) ) {
perror( "fclose cfilestream" );
}
if( iconv_close( conversiondescriptor ) ) {
perror( "iconv_close conversiondescriptor" );
}
return 0;
}
Slowest solution ever using mbtowc
This takes about 24.2 seconds to parse 319MB of text.
If you comment out the line fixedchar = mbtowc(NULL, source, charsread); and uncomment the line charsread -= fixedchar; (breaking the invalid characters removal) this will take 1.9 seconds instead of 24.2 seconds (also compiled with -O3 optimization level).
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <cstring>
#include <iomanip>
int main(int argc, char const *argv[])
{
FILE* cfilestream = fopen( "./test.txt", "r" );
size_t linebuffersize = 131072;
if( cfilestream == NULL ) {
perror( "fopen cfilestream" );
return -1;
}
char* readline = (char*) malloc( linebuffersize );
if( readline == NULL ) {
perror( "malloc readline" );
return -1;
}
char* source;
char* lineend;
char* destination;
int charsread;
int fixedchar;
if( ( source = std::setlocale( LC_ALL, "en_US.utf8" ) ) == NULL ) {
perror( "setlocale" );
}
else {
std::cerr << "locale='" << source << "'" << std::endl;
}
while( true )
{
if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
{
lineend = readline + charsread;
destination = readline;
for( source = readline; source != lineend; )
{
// fixedchar = 1;
fixedchar = mbtowc(NULL, source, charsread);
charsread -= fixedchar;
// std::ostringstream contents;
// for( int index = 0; index < fixedchar; ++index )
// contents << source[index];
// std::cerr << "fixedchar=" << std::setw(10)
// << fixedchar << " -> '"
// << contents.str().c_str() << "'" << std::endl;
if( fixedchar > 0 ) {
memmove( destination, source, fixedchar );
source += fixedchar;
destination += fixedchar;
}
else if( fixedchar < 0 ) {
source += 1;
// std::cerr << "errno=" << strerror( errno ) << std::endl;
}
else {
break;
}
}
// Trim out the new line character
if( *--destination == '\n' ) {
*--destination = '\0';
}
else {
*destination = '\0';
}
// std::cerr << "readline='" << readline << "'" << std::endl;
}
else {
break;
}
}
std::cerr << "readline='" << readline << "'" << std::endl;
if( fclose( cfilestream ) ) {
perror( "fclose cfilestream" );
}
free( readline );
return 0;
}
Fastest version from all my others above using memmove
You cannot use memcpy here because the memory regions overlap!
This takes about 2.4 seconds to parse 319MB.
If you comment out the lines *destination = *source and memmove( destination, source, 1 ) (breaking the invalid characters removal) the performance still almost the same as when memmove is being called. Here in, calling memmove( destination, source, 1 ) is a little slower than directly doing *destination = *source;
#include <stdlib.h>
#include <iostream>
#include <cstring>
#include <iomanip>
int main(int argc, char const *argv[])
{
FILE* cfilestream = fopen( "./test.txt", "r" );
size_t linebuffersize = 131072;
if( cfilestream == NULL ) {
perror( "fopen cfilestream" );
return -1;
}
char* readline = (char*) malloc( linebuffersize );
if( readline == NULL ) {
perror( "malloc readline" );
return -1;
}
char* source;
char* lineend;
char* destination;
int charsread;
unsigned int fixedchar;
if( ( source = std::setlocale( LC_ALL, "en_US.utf8" ) ) == NULL ) {
perror( "setlocale" );
}
else {
std::cerr << "locale='" << source << "'" << std::endl;
}
while( true )
{
if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
{
lineend = readline + charsread;
destination = readline;
for( source = readline; source != lineend; ++source )
{
fixedchar = static_cast<unsigned int>( *source );
// std::cerr << "fixedchar=" << std::setw(10)
// << fixedchar << " -> '" << *source << "'" << std::endl;
if( 31 < fixedchar && fixedchar < 128 ) {
*destination = *source;
++destination;
}
}
// Trim out the new line character
if( *source == '\n' ) {
*--destination = '\0';
}
else {
*destination = '\0';
}
// std::cerr << "readline='" << readline << "'" << std::endl;
}
else {
break;
}
}
std::cerr << "readline='" << readline << "'" << std::endl;
if( fclose( cfilestream ) ) {
perror( "fclose cfilestream" );
}
free( readline );
return 0;
}
Bonus
You can also use Python C Extensions (API).
It takes about 2.3 seconds to parse 319MB without converting them to cached version UTF-8 char*
And takes about 3.2 seconds to parse 319MB converting them to UTF-8 char*.
And also takes about 3.2 seconds to parse 319MB converting them to cached ASCII char*.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <iostream>
typedef struct
{
PyObject_HEAD
}
PyFastFile;
static PyModuleDef fastfilepackagemodule =
{
// https://docs.python.org/3/c-api/module.html#c.PyModuleDef
PyModuleDef_HEAD_INIT,
"fastfilepackage", /* name of module */
"Example module that wrapped a C++ object", /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module, or
-1 if the module keeps state in global variables. */
NULL, /* PyMethodDef* m_methods */
NULL, /* inquiry m_reload */
NULL, /* traverseproc m_traverse */
NULL, /* inquiry m_clear */
NULL, /* freefunc m_free */
};
// initialize PyFastFile Object
static int PyFastFile_init(PyFastFile* self, PyObject* args, PyObject* kwargs) {
char* filepath;
if( !PyArg_ParseTuple( args, "s", &filepath ) ) {
return -1;
}
int linecount = 0;
PyObject* iomodule;
PyObject* openfile;
PyObject* fileiterator;
iomodule = PyImport_ImportModule( "builtins" );
if( iomodule == NULL ) {
std::cerr << "ERROR: FastFile failed to import the io module '"
"(and open the file " << filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
PyObject* openfunction = PyObject_GetAttrString( iomodule, "open" );
if( openfunction == NULL ) {
std::cerr << "ERROR: FastFile failed get the io module open "
<< "function (and open the file '" << filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
openfile = PyObject_CallFunction(
openfunction, "ssiss", filepath, "r", -1, "ASCII", "ignore" );
if( openfile == NULL ) {
std::cerr << "ERROR: FastFile failed to open the file'"
<< filepath << "'!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
PyObject* iterfunction = PyObject_GetAttrString( openfile, "__iter__" );
Py_DECREF( openfunction );
if( iterfunction == NULL ) {
std::cerr << "ERROR: FastFile failed get the io module iterator"
<< "function (and open the file '" << filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
PyObject* openiteratorobject = PyObject_CallObject( iterfunction, NULL );
Py_DECREF( iterfunction );
if( openiteratorobject == NULL ) {
std::cerr << "ERROR: FastFile failed get the io module iterator object"
<< " (and open the file '" << filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
fileiterator = PyObject_GetAttrString( openfile, "__next__" );
Py_DECREF( openiteratorobject );
if( fileiterator == NULL ) {
std::cerr << "ERROR: FastFile failed get the io module iterator "
<< "object (and open the file '" << filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
PyObject* readline;
while( ( readline = PyObject_CallObject( fileiterator, NULL ) ) != NULL ) {
linecount += 1;
PyUnicode_AsUTF8( readline );
Py_DECREF( readline );
// std::cerr << "linecount " << linecount << " readline '" << readline
// << "' '" << PyUnicode_AsUTF8( readline ) << "'" << std::endl;
}
std::cerr << "linecount " << linecount << std::endl;
// PyErr_PrintEx(100);
PyErr_Clear();
PyObject* closefunction = PyObject_GetAttrString( openfile, "close" );
if( closefunction == NULL ) {
std::cerr << "ERROR: FastFile failed get the close file function for '"
<< filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
PyObject* closefileresult = PyObject_CallObject( closefunction, NULL );
Py_DECREF( closefunction );
if( closefileresult == NULL ) {
std::cerr << "ERROR: FastFile failed close open file '"
<< filepath << "')!" << std::endl;
PyErr_PrintEx(100);
return -1;
}
Py_DECREF( closefileresult );
Py_XDECREF( iomodule );
Py_XDECREF( openfile );
Py_XDECREF( fileiterator );
return 0;
}
// destruct the object
static void PyFastFile_dealloc(PyFastFile* self) {
Py_TYPE(self)->tp_free( (PyObject*) self );
}
static PyTypeObject PyFastFileType =
{
PyVarObject_HEAD_INIT( NULL, 0 )
"fastfilepackage.FastFile" /* tp_name */
};
// create the module
PyMODINIT_FUNC PyInit_fastfilepackage(void)
{
PyObject* thismodule;
// https://docs.python.org/3/c-api/typeobj.html
PyFastFileType.tp_new = PyType_GenericNew;
PyFastFileType.tp_basicsize = sizeof(PyFastFile);
PyFastFileType.tp_dealloc = (destructor) PyFastFile_dealloc;
PyFastFileType.tp_flags = Py_TPFLAGS_DEFAULT;
PyFastFileType.tp_doc = "FastFile objects";
PyFastFileType.tp_init = (initproc) PyFastFile_init;
if( PyType_Ready( &PyFastFileType) < 0 ) {
return NULL;
}
thismodule = PyModule_Create(&fastfilepackagemodule);
if( thismodule == NULL ) {
return NULL;
}
// Add FastFile class to thismodule allowing the use to create objects
Py_INCREF( &PyFastFileType );
PyModule_AddObject( thismodule, "FastFile", (PyObject*) &PyFastFileType );
return thismodule;
}
To built it, create the file source/fastfilewrappar.cpp with the contents of the above file and the setup.py with the following contents:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import setup, Extension
myextension = Extension(
language = "c++",
extra_link_args = ["-std=c++11"],
extra_compile_args = ["-std=c++11"],
name = 'fastfilepackage',
sources = [
'source/fastfilewrapper.cpp'
],
include_dirs = [ 'source' ],
)
setup(
name = 'fastfilepackage',
ext_modules= [ myextension ],
)
To run example, use following Python script:
import time
import datetime
import fastfilepackage
testfile = './test.txt'
timenow = time.time()
iterable = fastfilepackage.FastFile( testfile )
fastfile_time = time.time() - timenow
timedifference = datetime.timedelta( seconds=fastfile_time )
print( 'FastFile timedifference', timedifference, flush=True )
Example:
user#user-pc$ /usr/bin/pip3.6 install .
Processing /fastfilepackage
Building wheels for collected packages: fastfilepackage
Building wheel for fastfilepackage (setup.py) ... done
Stored in directory: /pip-ephem-wheel-cache-j313cpzc/wheels/e5/5f/bc/52c820
Successfully built fastfilepackage
Installing collected packages: fastfilepackage
Found existing installation: fastfilepackage 0.0.0
Uninstalling fastfilepackage-0.0.0:
Successfully uninstalled fastfilepackage-0.0.0
Successfully installed fastfilepackage-0.0.0
user#user-pc$ /usr/bin/python3.6 fastfileperformance.py
linecount 820800
FastFile timedifference 0:00:03.204614
Using std::getline
This takes about 4.7 seconds to parse 319MB.
If you remove the UTF-8 removal algorithm borrowed from the fastest benchmark using stdlib.h getline(), it takes 1.7 seconds to run.
#include <stdlib.h>
#include <iostream>
#include <locale>
#include <fstream>
#include <iomanip>
int main(int argc, char const *argv[])
{
unsigned int fixedchar;
int linecount = -1;
char* source;
char* lineend;
char* destination;
if( ( source = setlocale( LC_ALL, "en_US.ascii" ) ) == NULL ) {
perror( "setlocale" );
return -1;
}
else {
std::cerr << "locale='" << source << "'" << std::endl;
}
std::ifstream fileifstream{ "./test.txt" };
if( fileifstream.fail() ) {
std::cerr << "ERROR: FastFile failed to open the file!" << std::endl;
return -1;
}
size_t linebuffersize = 131072;
char* readline = (char*) malloc( linebuffersize );
if( readline == NULL ) {
perror( "malloc readline" );
return -1;
}
while( true )
{
if( !fileifstream.eof() )
{
linecount += 1;
fileifstream.getline( readline, linebuffersize );
lineend = readline + fileifstream.gcount();
destination = readline;
for( source = readline; source != lineend; ++source )
{
fixedchar = static_cast<unsigned int>( *source );
// std::cerr << "fixedchar=" << std::setw(10)
// << fixedchar << " -> '" << *source << "'" << std::endl;
if( 31 < fixedchar && fixedchar < 128 ) {
*destination = *source;
++destination;
}
}
// Trim out the new line character
if( *source == '\n' ) {
*--destination = '\0';
}
else {
*destination = '\0';
}
// std::cerr << "readline='" << readline << "'" << std::endl;
}
else {
break;
}
}
std::cerr << "linecount='" << linecount << "'" << std::endl;
if( fileifstream.is_open() ) {
fileifstream.close();
}
free( readline );
return 0;
}
Resume
2.6 seconds trimming UTF-8 using two buffers with indexing
3.1 seconds trimming UTF-8 using two buffers with memcpy
4.6 seconds removing invalid UTF-8 with iconv
24.2 seconds removing invalid UTF-8 with mbtowc
2.4 seconds trimming UTF-8 using one buffer with pointer direct assigning
Bonus
2.3 seconds removing invalid UTF-8 without converting them to a cached UTF-8 char*
3.2 seconds removing invalid UTF-8 converting them to a cached UTF-8 char*
3.2 seconds trimming UTF-8 and caching as ASCII char*
4.7 seconds trimming UTF-8 with std::getline() using one buffer with pointer direct assigning
The used file ./text.txt had 820.800 lines where each line was equal to:
id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char&id-é-char\r\n
And all versions where compiled with
g++ (GCC) 7.4.0
iconv (GNU libiconv 1.14)
g++ -o main test.cpp -O3 -liconv && time ./main
In the documentation for SuperResolution
The code required to output the nextframe is :
void superres::SuperResolution::nextFrame(OutputArray frame)
The input frame source has to be set with :
void superres::SuperResolution::setInput(const Ptr<FrameSource>& frameSource)
I have a code that takes frames from a video :
#include "opencv2/opencv.hpp"
#include "iostream"
using namespace cv;
using namespace std;
int main(int, char**)
{
VideoCapture cap ( "video1.mp4" ); // open the default camera
if( ! cap.isOpened () ) // check if we succeeded
return -1;
/* Mat edges; */
namedWindow ( "Video" , 1 );
double frnb ( cap.get ( CV_CAP_PROP_FRAME_COUNT ) );
std::cout << "frame count = " << frnb << endl;
for(;;)
{
Mat frame;
double fIdx;
std::cout << "frame index ? ";
std::cin >> fIdx;
if ( fIdx < 0 || fIdx >= frnb ) break;
cap.set ( CV_CAP_PROP_POS_FRAMES , fIdx );
bool success = cap.read(frame);
if ( ! success )
{
cout << "Cannot read frame " << endl;
break;
}
/* cap >> frame; // get a new frame from camera */
imshow("Video", frame);
if ( waitKey (0) == 27 ) break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
Given this I can use the frame variable as the parameter for the setInput method, but how can I initialize the OutputArray frame needed to generate the output ?
I think you cannot use frame as the parameter for the setInput and you don't need to initalize the OutputArray frame.
Check this example out:
FrameSource is created like this:
121. frameSource = createFrameSource_Video(inputVideoName);
And then the outputArray frame is used like this:
142. Mat result; // no intialization, just declaration
144. MEASURE_TIME(superRes->nextFrame(result));
I am using Hog+SVM in opencv for detecting cars in Video avi file. I am using car.xml model file.
I am not getting good results when I used LatentSvmDetetction for detecting cars
A Large number of false detections in frame.
It is very slow. It takes about 5 seconds to detect objects from a frame.
Please suggest me how to improve object detection time.
My code is below:
#include <iostream>
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#if defined(WIN32) || defined(_WIN32)
#include <io.h>
#else
#include <dirent.h>
#endif
#ifdef HAVE_CVCONFIG_H
#include <cvconfig.h>
#endif
#ifdef HAVE_TBB
#include "tbb/task_scheduler_init.h"
#endif
using namespace std;
using namespace cv;
static void detectAndDrawObjects( Mat& frame, LatentSvmDetector& detector, const vector<Scalar>& colors, float overlapThreshold, int numThreads )
{
vector<LatentSvmDetector::ObjectDetection> detections;
TickMeter tm;
tm.start();
detector.detect( frame, detections, overlapThreshold, numThreads);
tm.stop();
cout << "Detection time = " << tm.getTimeSec() << " sec" << endl;
const vector<string> classNames = detector.getClassNames();
CV_Assert( colors.size() == classNames.size() );
for( size_t i = 0; i < detections.size(); i++ )
{
const LatentSvmDetector::ObjectDetection& od = detections[i];
rectangle( frame, od.rect, colors[od.classID], 3 );
putText( frame, classNames[od.classID], Point(od.rect.x+4,od.rect.y+13), FONT_HERSHEY_SIMPLEX, 0.55, colors[od.classID], 2 );
}
}
static void readDirectory( const string& directoryName, vector<string>& filenames, bool addDirectoryName=true )
{
filenames.clear();
#if defined(WIN32) | defined(_WIN32)
struct _finddata_t s_file;
string str = directoryName + "\\*.*";
intptr_t h_file = _findfirst( str.c_str(), &s_file );
if( h_file != static_cast<intptr_t>(-1.0) )
{
do
{
if( addDirectoryName )
filenames.push_back(directoryName + "\\" + s_file.name);
else
filenames.push_back((string)s_file.name);
}
while( _findnext( h_file, &s_file ) == 0 );
}
_findclose( h_file );
#else
DIR* dir = opendir( directoryName.c_str() );
if( dir != NULL )
{
struct dirent* dent;
while( (dent = readdir(dir)) != NULL )
{
if( addDirectoryName )
filenames.push_back( directoryName + "/" + string(dent->d_name) );
else
filenames.push_back( string(dent->d_name) );
}
closedir( dir );
}
#endif
sort( filenames.begin(), filenames.end() );
}
int main()
{
string frames_folder, models_folder;
float overlapThreshold = 0.2f;
int numThreads = -1;
models_folder = "D:\\Downloads\\models_VOC2007";
VideoCapture cap("D:\\images\\videos\\vid2.AVI"); // open the video file for reading
cvNamedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
if ( !cap.isOpened() ) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
LatentSvmDetector detector( models_filenames );
if( detector.empty() )
{
cout << "Models cann't be loaded" << endl;
exit(-1);
}
vector<Scalar> colors;
generateColors( colors, detector.getClassNames().size() );
Mat frame;
while(1)
{
bool bSuccess = cap.read(frame);
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read the frame from video file" << endl;
break;
}
detectAndDrawObjects( frame, detector, colors, overlapThreshold, numThreads );
imshow( "MyVideo", frame );
//imshow("video", frame); //show the frame in "MyVideo" window
if(waitKey(30) == 27) //wait for 'esc' key press for 30 ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
I suggest you
to resize the frame to a size that 10x5 pixel is the smallest possible car in the frame;
to do a blur first; it is possible to get lots of false-positives because there is noise that generate edges that can be similar to the car;
I suppose that the detector is for side cars (I have not tested it) ant it will not detect cars rotated with more than 60 degrees and it is trained on some database that was not similar to your environment; so maybe it is better to train your own detector (car.xml).
HOG is based on edges and edges are very sensible to light and shadows. Try to preprocess (contrast enhancement) the frame before detecting the cars.
I am going through and comparing a bunch of DNA sequences to find if it is a subset of another. I remove those that are subsets of another.
I'm using a linked list and I keep getting a segmentation fault somewhere around the output of the data back to the output file.
I'd also greatly appreciate feedback on overall code structure. I know its rather messy so I figured someone could point out some things that should be improved on.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
/*
* Step 1. Load all sequences and their metadata into structures.
*
* Step 2. Start n^2 operation to compare sequences.
*
* Step 3. Output file back to a different fasta file.
*/
typedef struct sequence_structure sequence_structure;
struct sequence_structure
{
char *sequence;
char *id;
char *header;
sequence_structure *next_sequence_structure;
sequence_structure *previous_sequence_structure;
int length;
};
int main(int argc, char *argv[])
{
FILE *input_file;
ofstream output_file;
/* this is the TAIL of the linked list. This is a reversed linked list. */
sequence_structure *sequences;
int first_sequence = 0;
char *line = (char*) malloc( sizeof( char ) * 1024 );
if( argc != 3 )
{
printf("This program requires a input file and output file as its argument!\n");
return 0;
}
else
{
/* let's read the input file. */
input_file = fopen( argv[1], "r" );
}
while( !feof(input_file) )
{
string string_line;
fgets( line, 2048, input_file );
string_line = line;
if( string_line.length() <= 2 )
break;
if( string_line.at( 0 ) == '>' )
{
sequence_structure *new_sequence = (sequence_structure *) malloc( sizeof( sequence_structure ) );
new_sequence->id = (char *) malloc( sizeof( char ) * ( 14 + 1 ) );
string_line.copy( new_sequence->id, 14, 1 );
(new_sequence->id)[14] = '\0';
stringstream ss ( string_line.substr( 23, 4 ) );
ss >> new_sequence->length;
new_sequence->header = (char *) malloc( sizeof(char) * ( string_line.length() + 1 ) );
string_line.copy( new_sequence->header, string_line.length(), 0 );
(new_sequence->header)[string_line.length()] = '\0';
fgets( line, 2048, input_file );
string_line = line;
new_sequence->sequence = (char *) malloc( sizeof(char) * ( string_line.length() + 1 ) );
string_line.copy( new_sequence->sequence, string_line.length(), 0 );
(new_sequence->sequence)[string_line.length()] = '\0';
if( first_sequence == 0 )
{
sequences = new_sequence;
sequences->previous_sequence_structure = NULL;
first_sequence = 1;
}
else
{
sequences->next_sequence_structure = new_sequence;
new_sequence->previous_sequence_structure = sequences;
sequences = new_sequence;
}
}
else
{
cout << "Error: input file reading error." << endl;
}
}
fclose( input_file );
free( line );
sequence_structure *outer_sequence_node = sequences;
while( outer_sequence_node != NULL )
{
sequence_structure *inner_sequence_node = sequences;
string outer_sequence ( outer_sequence_node->sequence );
while( inner_sequence_node != NULL )
{
string inner_sequence ( inner_sequence_node->sequence );
if( outer_sequence_node->length > inner_sequence_node->length )
{
if( outer_sequence.find( inner_sequence ) != std::string::npos )
{
cout << "Deleting the sequence with id: " << inner_sequence_node->id << endl;
cout << inner_sequence_node->sequence << endl;
cout << "Found within the sequence with id: " << outer_sequence_node->id << endl;
cout << outer_sequence_node->sequence << endl;
sequence_structure *previous_sequence = inner_sequence_node->previous_sequence_structure;
sequence_structure *next_sequence = inner_sequence_node->next_sequence_structure;
free( inner_sequence_node->id );
free( inner_sequence_node->sequence );
free( inner_sequence_node->header );
if( next_sequence != NULL )
next_sequence->previous_sequence_structure = previous_sequence;
if( previous_sequence != NULL )
{
inner_sequence_node = previous_sequence;
free( previous_sequence->next_sequence_structure );
previous_sequence->next_sequence_structure = next_sequence;
}
}
}
inner_sequence_node = inner_sequence_node->previous_sequence_structure;
}
outer_sequence_node = outer_sequence_node->previous_sequence_structure;
}
output_file.open( argv[2], ios::out );
while( sequences->previous_sequence_structure != NULL )
{
sequences = sequences->previous_sequence_structure;
}
sequence_structure *current_sequence = sequences;
while( current_sequence->next_sequence_structure != NULL )
{
output_file << current_sequence->header;
output_file << current_sequence->sequence;
current_sequence = current_sequence->next_sequence_structure;
}
output_file << current_sequence->header;
output_file << current_sequence->sequence;
output_file.close();
while( sequences != NULL )
{
cout << "Freeing sequence with this id: " << sequences->id << endl;
free( sequences->id );
free( sequences->header );
free( sequences->sequence );
if( sequences->next_sequence_structure != NULL )
{
sequences = sequences->next_sequence_structure;
free( sequences->previous_sequence_structure );
}
else
{
sequences = NULL;
}
}
return 0;
}
I'm porting my code to use the new OpenCV C++ interface. I like the possibility to strictly type everything, so derive all my images and matrices from the template class:
Mat_<type> var;
Now I have problems using the distanceTransform function. My code does something like this:
Mat_<float> imgGray;
Mat_<unsigned char> imgBinary;
Mat_<float> imgDistance;
// ... fill imgGray with data ...
threshold(imgGray, imgBinary, 0.25, 255, CV_THRESH_BINARY);
distanceTransform(imgBinary, imgDistance, CV_DIST_L2, CV_DIST_MASK_PRECISE);
distanceTransform fails. It gives the following error:
Unsupported format or combination of formats (source image must be 8uC1 and the distance map must be 32fC1 (or 8uC1 in case of simple L1 distance transform)) in unknown function, file ........\src\cv\cvdistransform.cpp, line 730
I figured out that the problem is the source parameter. It doesn't pass the CV_IS_MASK_ARR(src) test.
From what I understand, threshold calls create on imgBinary to allocate the memory. So I don't have the possibility to control the exact type (should be CV_8UC1) of the imgBinary matrix, do I? How can I make sure that imgBinary is a proper binary mask to make distanceTransform happy?
Thanks for your help!
Cheers, Robert
If you wish, you can check the code below. It's a new version of DT with OpenCV C++ API
//#define CV_NO_BACKWARD_COMPATIBILITY
// if you compile the program under Windows and MSVC2008/2005
#if defined WIN32 || defined _MSC_VER
#pragma warning(disable:4786)
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
#define DEMO_MIXED_API_USE 1
using namespace cv;
using namespace std;
char wndname[] = "Distance transform";
char tbarname[] = "Threshold";
int mask_size = CV_DIST_MASK_5;
int build_voronoi = 0;
int edge_thresh = 100;
int dist_type = CV_DIST_L1;
// The output and temporary images
Mat dist;
Mat dist8u1;
Mat dist8u2;
Mat dist8u;
Mat dist32s;
Mat gray;
Mat edge;
Mat labels;
// threshold trackbar callback
void on_trackbar( int dummy, void *)
{
static const uchar colors[][3] =
{
{0,0,0},
{255,0,0},
{255,128,0},
{255,255,0},
{0,255,0},
{0,128,255},
{0,255,255},
{0,0,255},
{255,0,255}
};
int msize = mask_size;
int _dist_type = build_voronoi ? CV_DIST_L2 : dist_type;
threshold( gray, edge, (double)edge_thresh, (double)edge_thresh, CV_THRESH_BINARY );
if( build_voronoi )
msize = CV_DIST_MASK_5;
if( _dist_type == CV_DIST_L1 )
{
distanceTransform( edge, dist, _dist_type, msize );
}
else
{
build_voronoi ? distanceTransform( edge, dist, labels, _dist_type, msize ) : distanceTransform( edge, dist, _dist_type, msize ) ;
}
if( !build_voronoi )
{
// begin "painting" the distance transform result
dist.convertTo( dist, dist.type(), 5000.0, 0 ); //before--> cvConvertScale( dist, dist, 5000.0, 0 );
pow( dist, 0.5, dist ); //before--> cvPow(dist, dist, 0.5);
dist.convertTo( dist32s, dist32s.type(), 1.0, 0.5 ); //before--> cvConvertScale( dist, dist32s, 1.0, 0.5 );
bitwise_and( dist32s, Scalar::all(255), dist32s, Mat() ); //before--> cvAndS( dist32s, ScalarAll(255), dist32s, 0 );
dist32s.convertTo(dist8u1, dist8u1.type(), 1, 0 ); //before--> cvConvertScale( dist32s, dist8u1, 1, 0 );
dist32s.convertTo( dist32s, dist32s.type(), -1, 0 ); //before--> cvConvertScale( dist32s, dist32s, -1, 0 );
add( dist32s, Scalar::all(255), dist32s, Mat() ); //before--> cvAddS( dist32s, cvScalarAll(255), dist32s, 0 );
dist32s.convertTo( dist8u2, dist8u2.type(), 1, 0 ); //before--> cvConvertScale( dist32s, dist8u2, 1, 0 );
vector<Mat> Out(3);
Out[0] = dist8u1;
Out[1] = dist8u2;
Out[2] = dist8u2;
merge( Out, dist8u ); //before--> cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u );
// end "painting" the distance transform result
}
else
{
int i, j;
for( i = 0; i < labels.rows; i++ )
{
int* ll = labels.ptr<int>(i); //before--> (int*)(labels->imageData + i*labels->widthStep)
float* dd = dist.ptr<float>(i); //before--> (float*)(dist->imageData + i*dist->widthStep)
uchar* d = dist8u.ptr<uchar>(i); //before--> (uchar*)(dist8u->imageData + i*dist8u->widthStep)
for( j = 0; j < labels.cols; j++ )
{
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
int b = cvRound(colors[idx][0]); // if there is an option to cvRound in the new OpenCV C++ API, tell me please
int g = cvRound(colors[idx][1]);
int r = cvRound(colors[idx][2]);
d[j*3] = saturate_cast<uchar>(b); //before--> (uchar)b;
d[j*3+1] = saturate_cast<uchar>(g); //before--> (uchar)g;
d[j*3+2] = saturate_cast<uchar>(r); //before--> (uchar)r;
}
}
}
imshow( wndname, dist8u ); //before--> cvShowImage( wndname, dist8u );
}
int main( int argc, char* argv[] )
{
const char* filename = (argc == 2 ? argv[1] : "Debug/stuff.jpg");//lena.jpg
gray = imread( filename, 0 ); // -1 loads image full(3 channels + alpha) , 0 only in grayscale
if( gray.empty() )
return -1;
cout << "Hot keys: \n"
<< "\tESC - quit the program\n"
<< "\tC - use C/Inf metric\n"
<< "\tL1 - use L1 metric\n"
<< "\tL2 - use L2 metric\n"
<< "\t3 - use 3x3 mask\n"
<< "\t5 - use 5x5 mask\n"
<< "\t0 - use precise distance transform\n"
<< "\tv - switch Voronoi diagram mode on/off\n"
<< "\tSPACE - loop through all the modes\n" << endl;
dist = Mat( gray.size(), CV_32FC1 ); //dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 );
dist8u1 = gray.clone(); //dist8u1 = cvCloneImage( gray );
dist8u2 = gray.clone(); //dist8u2 = cvCloneImage( gray );
dist8u = Mat( gray.size(), CV_8UC3 ); //dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 );
dist32s = Mat( gray.size(), CV_32SC1 ); //dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
edge = gray.clone(); //edge = cvCloneImage( gray );
labels = Mat( gray.size(), CV_32SC1 ); //labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
namedWindow( wndname, 1 );
createTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar );
for(;;)
{
int c;
// Call to update the view
on_trackbar(0, 0);
c = waitKey(0);
if( (char)c == 27 )
break;
if( (char)c == 'c' || (char)c == 'C' )
dist_type = CV_DIST_C;
else if( (char)c == '1' )
dist_type = CV_DIST_L1;
else if( (char)c == '2' )
dist_type = CV_DIST_L2;
else if( (char)c == '3' )
mask_size = CV_DIST_MASK_3;
else if( (char)c == '5' )
mask_size = CV_DIST_MASK_5;
else if( (char)c == '0' )
mask_size = CV_DIST_MASK_PRECISE;
else if( (char)c == 'v' )
build_voronoi ^= 1;
else if( (char)c == ' ' )
{
if( build_voronoi )
{
build_voronoi = 0;
mask_size = CV_DIST_MASK_3;
dist_type = CV_DIST_C;
}
else if( dist_type == CV_DIST_C )
dist_type = CV_DIST_L1;
else if( dist_type == CV_DIST_L1 )
dist_type = CV_DIST_L2;
else if( mask_size == CV_DIST_MASK_3 )
mask_size = CV_DIST_MASK_5;
else if( mask_size == CV_DIST_MASK_5 )
mask_size = CV_DIST_MASK_PRECISE;
else if( mask_size == CV_DIST_MASK_PRECISE )
build_voronoi = 1;
}
}
return 0;
}