00001
00007
00008
00009
00010
00011
00012
00013
00014
00015 #define VL_MSER_DRIVER_VERSION 0.2
00016
00017 #include "generic-driver.h"
00018
00019 #include <vl/generic.h>
00020 #include <vl/stringop.h>
00021 #include <vl/pgm.h>
00022 #include <vl/mser.h>
00023 #include <vl/getopt_long.h>
00024
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <assert.h>
00028
00029
00030
00031 char const help_message [] =
00032 "Usage: %s [options] files ...\n"
00033 "\n"
00034 "Options include:\n"
00035 " --verbose -v Be verbose\n"
00036 " --help -h Print this help message\n"
00037 " --seeds Specify seeds file\n"
00038 " --frames Specify frames file\n"
00039 " --meta Specify meta file\n"
00040 " --delta -d Specify MSER delta paramter\n"
00041 " --epsilon -e Specify MSER epsilon parameter\n"
00042 " --no-dups Remove duplicate\n"
00043 " --dups Keep duplicates\n"
00044 " --max-area Specify maximum region (relative) area\n"
00045 " --min-area Specify minimum region (relative) area\n"
00046 " --max-variation Specify maximum absolute region stability\n"
00047 " --bright-on-dark Enable or disable bright-on-dark regions (default 1)\n"
00048 " --dark-on-bright Enable or disable dark-on-bright regions (default 1)\n"
00049 "\n" ;
00050
00051
00052
00053 enum {
00054 opt_seed = 1000,
00055 opt_frame,
00056 opt_meta,
00057 opt_max_area,
00058 opt_min_area,
00059 opt_max_variation,
00060 opt_min_diversity,
00061 opt_bright,
00062 opt_dark
00063 } ;
00064
00065
00066 char const opts [] = "vhd:" ;
00067
00068
00069 struct option const longopts [] = {
00070 { "verbose", no_argument, 0, 'v' },
00071 { "help", no_argument, 0, 'h' },
00072 { "delta", required_argument, 0, 'd' },
00073 { "seeds", optional_argument, 0, opt_seed },
00074 { "frames", optional_argument, 0, opt_frame },
00075 { "meta", optional_argument, 0, opt_meta },
00076 { "max-area", required_argument, 0, opt_max_area },
00077 { "min-area", required_argument, 0, opt_min_area },
00078 { "max-variation", required_argument, 0, opt_max_variation },
00079 { "min-diversity", required_argument, 0, opt_min_diversity },
00080 { "bright-on-dark", required_argument, 0, opt_bright },
00081 { "dark-on-bright", required_argument, 0, opt_dark },
00082 { 0, 0, 0, 0 }
00083 } ;
00084
00085
00086
00089 int
00090 main(int argc, char **argv)
00091 {
00092
00093 double delta = -1 ;
00094 double max_area = -1 ;
00095 double min_area = -1 ;
00096 double max_variation = -1 ;
00097 double min_diversity = -1 ;
00098 int bright_on_dark = 1 ;
00099 int dark_on_bright = 1 ;
00100
00101 vl_bool err = VL_ERR_OK ;
00102 char err_msg [1024] ;
00103 int n ;
00104 int exit_code = 0 ;
00105 int verbose = 0 ;
00106
00107 VlFileMeta frm = {0, "%.frame", VL_PROT_ASCII, "", 0} ;
00108 VlFileMeta piv = {0, "%.mser", VL_PROT_ASCII, "", 0} ;
00109 VlFileMeta met = {0, "%.meta", VL_PROT_ASCII, "", 0} ;
00110
00111 #define ERRF(msg, arg) { \
00112 err = VL_ERR_BAD_ARG ; \
00113 snprintf(err_msg, sizeof(err_msg), msg, arg) ; \
00114 break ; \
00115 }
00116
00117 #define ERR(msg) { \
00118 err = VL_ERR_BAD_ARG ; \
00119 snprintf(err_msg, sizeof(err_msg), msg) ; \
00120 break ; \
00121 }
00122
00123
00124
00125
00126 while (!err) {
00127 int ch = getopt_long(argc, argv, opts, longopts, 0) ;
00128
00129
00130 if (ch == -1 && argc - optind == 0)
00131 ch = 'h';
00132
00133
00134 if (ch == -1) break;
00135
00136
00137 switch (ch) {
00138
00139
00140 case '?' :
00141 ERRF("Invalid option '%s'.", argv [optind - 1]) ;
00142 break ;
00143
00144 case ':' :
00145 ERRF("Missing mandatory argument for option '%s'.",
00146 argv [optind - 1]) ;
00147 break ;
00148
00149 case 'h' :
00150 printf (help_message, argv [0]) ;
00151 printf ("MSERs filespec: `%s'\n", piv.pattern) ;
00152 printf ("Frames filespec: `%s'\n", frm.pattern) ;
00153 printf ("Meta filespec: `%s'\n", met.pattern) ;
00154 printf ("Version: driver %s; libvl %s\n",
00155 VL_XSTRINGIFY(VL_MSER_DRIVER_VERSION),
00156 vl_get_version_string()) ;
00157 exit (0) ;
00158 break ;
00159
00160 case 'v' :
00161 ++ verbose ;
00162 break ;
00163
00164
00165 case 'd' :
00166 n = sscanf (optarg, "%lf", &delta) ;
00167 if (n == 0 || delta < 0)
00168 ERRF("The argument of '%s' must be a non-negative number.",
00169 argv [optind - 1]) ;
00170 break ;
00171
00172
00173 case opt_max_area :
00174 n = sscanf (optarg, "%lf", &max_area) ;
00175 if (n == 0 || max_area < 0 || max_area > 1)
00176 ERR("max-area argument must be in the [0,1] range.") ;
00177 break ;
00178
00179 case opt_min_area :
00180 n = sscanf (optarg, "%lf", &min_area) ;
00181 if (n == 0 || min_area < 0 || min_area > 1)
00182 ERR("min-area argument must be in the [0,1] range.") ;
00183 break ;
00184
00185 case opt_max_variation :
00186 n = sscanf (optarg, "%lf", &max_variation) ;
00187 if (n == 0 || max_variation < 0)
00188 ERR("max-variation argument must be non-negative.") ;
00189 break ;
00190
00191 case opt_min_diversity :
00192 n = sscanf (optarg, "%lf", &min_diversity) ;
00193 if (n == 0 || min_diversity < 0 || min_diversity > 1)
00194 ERR("min-diversity argument must be in the [0,1] range.") ;
00195 break ;
00196
00197
00198 case opt_frame :
00199 err = vl_file_meta_parse (&frm, optarg) ;
00200 if (err)
00201 ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
00202 break ;
00203
00204 case opt_seed :
00205 err = vl_file_meta_parse (&piv, optarg) ;
00206 if (err)
00207 ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
00208 break ;
00209
00210 case opt_meta :
00211 err = vl_file_meta_parse (&met, optarg) ;
00212 if (err)
00213 ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
00214
00215 if (met.protocol != VL_PROT_ASCII)
00216 ERR("meta file supports only ASCII protocol") ;
00217 break ;
00218
00219 case opt_bright :
00220 n = sscanf (optarg, "%d", &bright_on_dark) ;
00221 if (n == 0 || (bright_on_dark != 0 && bright_on_dark != 1))
00222 ERR("bright_on_dark must be 0 or 1.") ;
00223 break ;
00224
00225 case opt_dark :
00226 n = sscanf (optarg, "%d", &dark_on_bright) ;
00227 if (n == 0 || (dark_on_bright != 0 && dark_on_bright != 1))
00228 ERR("dark_on_bright must be 0 or 1.") ;
00229 break ;
00230
00231
00232 case 0 :
00233 default :
00234 abort() ;
00235 }
00236 }
00237
00238
00239 if (err) {
00240 fprintf(stderr, "%s: error: %s (%d)\n",
00241 argv [0],
00242 err_msg, err) ;
00243 exit (1) ;
00244 }
00245
00246
00247 argc -= optind ;
00248 argv += optind ;
00249
00250
00251 if (piv.active == 0 && frm.active == 0) {
00252 frm.active = 1 ;
00253 }
00254
00255 if (verbose > 1) {
00256 printf("mser: frames output\n") ;
00257 printf("mser: active %d\n", frm.active ) ;
00258 printf("mser: pattern %s\n", frm.pattern) ;
00259 printf("mser: protocol %s\n", vl_string_protocol_name (frm.protocol)) ;
00260 printf("mser: seeds output\n") ;
00261 printf("mser: active %d\n", piv.active ) ;
00262 printf("mser: pattern %s\n", piv.pattern) ;
00263 printf("mser: protocol %s\n", vl_string_protocol_name (piv.protocol)) ;
00264 printf("mser: meta output\n") ;
00265 printf("mser: active %d\n", met.active ) ;
00266 printf("mser: pattern %s\n", met.pattern) ;
00267 printf("mser: protocol %s\n", vl_string_protocol_name (met.protocol)) ;
00268 }
00269
00270
00271
00272
00273
00274 while (argc--) {
00275
00276 char basename [1024] ;
00277 char const *name = *argv++ ;
00278 VlMserFilt *filt = 0 ;
00279 VlMserFilt *filtinv = 0 ;
00280 vl_uint8 *data = 0 ;
00281 vl_uint8 *datainv = 0 ;
00282 VlPgmImage pim ;
00283 vl_uint const *regions ;
00284 vl_uint const *regionsinv ;
00285 float const *frames ;
00286 float const *framesinv ;
00287 enum {ndims = 2} ;
00288 int dims [ndims] ;
00289 int nregions = 0, nregionsinv = 0, nframes = 0, nframesinv =0;
00290 int i, j, dof ;
00291 vl_size q ;
00292 FILE *in = 0 ;
00293
00294
00295
00296
00297 q = vl_string_basename (basename, sizeof(basename), name, 1) ;
00298 err = (q >= sizeof(basename)) ;
00299 if (err) {
00300 snprintf(err_msg, sizeof(err_msg),
00301 "Basename of '%s' is too long", name);
00302 err = VL_ERR_OVERFLOW ;
00303 goto done ;
00304 }
00305
00306 if (verbose) {
00307 printf("mser: processing '%s'\n", name) ;
00308 }
00309
00310 if (verbose > 1) {
00311 printf("mser: basename is '%s'\n", basename) ;
00312 }
00313
00314 #define WERR(name) \
00315 if (err == VL_ERR_OVERFLOW) { \
00316 snprintf(err_msg, sizeof(err_msg), \
00317 "Output file name too long.") ; \
00318 goto done ; \
00319 } else if (err) { \
00320 snprintf(err_msg, sizeof(err_msg), \
00321 "Could not open '%s' for writing.", name) ; \
00322 goto done ; \
00323 }
00324
00325
00326 in = fopen (name, "rb") ;
00327 if (!in) {
00328 err = VL_ERR_IO ;
00329 snprintf(err_msg, sizeof(err_msg),
00330 "Could not open '%s' for reading.", name) ;
00331 goto done ;
00332 }
00333
00334
00335 err = vl_file_meta_open (&piv, basename, "w") ; WERR(piv.name) ;
00336 err = vl_file_meta_open (&frm, basename, "w") ; WERR(frm.name) ;
00337 err = vl_file_meta_open (&met, basename, "w") ; WERR(met.name) ;
00338
00339 if (verbose > 1) {
00340 if (piv.active) printf("mser: writing seeds to '%s'\n", piv.name);
00341 if (frm.active) printf("mser: writing frames to '%s'\n", frm.name);
00342 if (met.active) printf("mser: writing meta to '%s'\n", met.name);
00343 }
00344
00345
00346
00347
00348 err = vl_pgm_extract_head (in, &pim) ;
00349 if (err) {
00350 err = VL_ERR_IO ;
00351 snprintf(err_msg, sizeof(err_msg),
00352 "PGM header corrputed.") ;
00353 goto done ;
00354 }
00355
00356 if (verbose) {
00357 printf("mser: image is %" VL_FMT_SIZE " by %" VL_FMT_SIZE " pixels\n",
00358 pim. width,
00359 pim. height) ;
00360 }
00361
00362
00363 data = malloc(vl_pgm_get_npixels (&pim) *
00364 vl_pgm_get_bpp (&pim)) ;
00365
00366 if (!data) {
00367 err = VL_ERR_ALLOC ;
00368 snprintf(err_msg, sizeof(err_msg),
00369 "Could not allocate enough memory.") ;
00370 goto done ;
00371 }
00372
00373
00374 err = vl_pgm_extract_data (in, &pim, data) ;
00375 if (err) {
00376 snprintf(err_msg, sizeof(err_msg),
00377 "PGM body corrputed.") ;
00378 goto done ;
00379 }
00380
00381
00382 dims[0] = pim.width ;
00383 dims[1] = pim.height ;
00384
00385 filt = vl_mser_new (ndims, dims) ;
00386 filtinv = vl_mser_new (ndims, dims) ;
00387
00388 if (!filt || !filtinv) {
00389 snprintf(err_msg, sizeof(err_msg),
00390 "Could not create an MSER filter.") ;
00391 goto done ;
00392 }
00393
00394 if (delta >= 0) vl_mser_set_delta (filt, (vl_mser_pix) delta) ;
00395 if (max_area >= 0) vl_mser_set_max_area (filt, max_area) ;
00396 if (min_area >= 0) vl_mser_set_min_area (filt, min_area) ;
00397 if (max_variation >= 0) vl_mser_set_max_variation (filt, max_variation) ;
00398 if (min_diversity >= 0) vl_mser_set_min_diversity (filt, min_diversity) ;
00399 if (delta >= 0) vl_mser_set_delta (filtinv, (vl_mser_pix) delta) ;
00400 if (max_area >= 0) vl_mser_set_max_area (filtinv, max_area) ;
00401 if (min_area >= 0) vl_mser_set_min_area (filtinv, min_area) ;
00402 if (max_variation >= 0) vl_mser_set_max_variation (filtinv, max_variation) ;
00403 if (min_diversity >= 0) vl_mser_set_min_diversity (filtinv, min_diversity) ;
00404
00405
00406 if (verbose) {
00407 printf("mser: parameters:\n") ;
00408 printf("mser: delta = %d\n", vl_mser_get_delta (filt)) ;
00409 printf("mser: max_area = %g\n", vl_mser_get_max_area (filt)) ;
00410 printf("mser: min_area = %g\n", vl_mser_get_min_area (filt)) ;
00411 printf("mser: max_variation = %g\n", vl_mser_get_max_variation (filt)) ;
00412 printf("mser: min_diversity = %g\n", vl_mser_get_min_diversity (filt)) ;
00413 }
00414
00415 if (dark_on_bright)
00416 {
00417 vl_mser_process (filt, (vl_mser_pix*) data) ;
00418
00419
00420 nregions = vl_mser_get_regions_num (filt) ;
00421 regions = vl_mser_get_regions (filt) ;
00422
00423 if (piv.active) {
00424 for (i = 0 ; i < nregions ; ++i) {
00425 fprintf(piv.file, "%d ", regions [i]) ;
00426 }
00427 }
00428
00429 if (frm.active) {
00430 vl_mser_ell_fit (filt) ;
00431
00432 nframes = vl_mser_get_ell_num (filt) ;
00433 dof = vl_mser_get_ell_dof (filt) ;
00434 frames = vl_mser_get_ell (filt) ;
00435 for (i = 0 ; i < nframes ; ++i) {
00436 for (j = 0 ; j < dof ; ++j) {
00437 fprintf(frm.file, "%f ", *frames++) ;
00438 }
00439 fprintf(frm.file, "\n") ;
00440 }
00441 }
00442 }
00443 if (bright_on_dark)
00444 {
00445
00446 datainv = malloc(vl_pgm_get_npixels (&pim) *
00447 vl_pgm_get_bpp (&pim)) ;
00448 for (i = 0; i < (signed)vl_pgm_get_npixels (&pim); i++) {
00449 datainv[i] = ~data[i];
00450 }
00451
00452 if (!datainv) {
00453 err = VL_ERR_ALLOC ;
00454 snprintf(err_msg, sizeof(err_msg),
00455 "Could not allocate enough memory.") ;
00456 goto done ;
00457 }
00458
00459 vl_mser_process (filtinv, (vl_mser_pix*) datainv) ;
00460
00461
00462 nregionsinv = vl_mser_get_regions_num (filtinv) ;
00463 regionsinv = vl_mser_get_regions (filtinv) ;
00464
00465 if (piv.active) {
00466 for (i = 0 ; i < nregionsinv ; ++i) {
00467 fprintf(piv.file, "%d ", -regionsinv [i]) ;
00468 }
00469 }
00470
00471 if (frm.active) {
00472 vl_mser_ell_fit (filtinv) ;
00473
00474 nframesinv = vl_mser_get_ell_num (filtinv) ;
00475 dof = vl_mser_get_ell_dof (filtinv) ;
00476 framesinv = vl_mser_get_ell (filtinv) ;
00477 for (i = 0 ; i < nframesinv ; ++i) {
00478 for (j = 0 ; j < dof ; ++j) {
00479 fprintf(frm.file, "%f ", *framesinv++) ;
00480 }
00481 fprintf(frm.file, "\n") ;
00482 }
00483 }
00484 }
00485
00486 if (met.active) {
00487 fprintf(met.file, "<mser\n") ;
00488 fprintf(met.file, " input = '%s'\n", name) ;
00489 if (piv.active) {
00490 fprintf(met.file, " seeds = '%s'\n", piv.name) ;
00491 }
00492 if (frm.active) {
00493 fprintf(met.file," frames = '%s'\n", frm.name) ;
00494 }
00495 fprintf(met.file, ">\n") ;
00496 }
00497
00498
00499 done :
00500
00501 if (filt) {
00502 vl_mser_delete (filt) ;
00503 filt = 0 ;
00504 }
00505 if (filtinv) {
00506 vl_mser_delete (filtinv) ;
00507 filtinv = 0 ;
00508 }
00509
00510
00511 if (data) {
00512 free (data) ;
00513 data = 0 ;
00514 }
00515 if (datainv) {
00516 free (datainv) ;
00517 datainv = 0 ;
00518 }
00519
00520
00521 if (in) {
00522 fclose (in) ;
00523 in = 0 ;
00524 }
00525
00526 vl_file_meta_close (&frm) ;
00527 vl_file_meta_close (&piv) ;
00528 vl_file_meta_close (&met) ;
00529
00530
00531 if (err) {
00532 fprintf
00533 (stderr,
00534 "mser: err: %s (%d)\n",
00535 err_msg,
00536 err) ;
00537 exit_code = 1 ;
00538 }
00539 }
00540
00541
00542 return exit_code ;
00543 }