diff --git a/3rdparty/ffmpeg/make.bat b/3rdparty/ffmpeg/make.bat index 6c965c57cb..f4f9592683 100644 --- a/3rdparty/ffmpeg/make.bat +++ b/3rdparty/ffmpeg/make.bat @@ -1,2 +1,3 @@ +rem gcc -Wall -shared -o opencv_ffmpeg.dll -O3 -x c++ -I../include -I../include/ffmpeg_ -I../../modules/highgui/src ffopencv.c -L../lib -lavformat -lavcodec -lavdevice -lswscale -lavutil -lwsock32 -lpthreadGE2 gcc -Wall -shared -o opencv_ffmpeg.dll -O2 -x c++ -I../include -I../include/ffmpeg_ -I../../modules/highgui/src ffopencv.c -L../lib -lavformat -lavcodec -lavdevice -lswscale -lavutil -lwsock32 set path=c:\apps\mingw64\bin;%path% & gcc -Wall -shared -o opencv_ffmpeg_64.dll -O2 -x c++ -I../include -I../include/ffmpeg_ -I../../modules/highgui/src ffopencv.c -L../lib -lavformat64 -lavcodec64 -lavdevice64 -lswscale64 -lavutil64 -lavcore64 -lwsock32 \ No newline at end of file diff --git a/3rdparty/lib/armeabi-v7a/libnative_camera_r2.2.2.so b/3rdparty/lib/armeabi-v7a/libnative_camera_r2.2.2.so new file mode 100644 index 0000000000..b36b97a36a Binary files /dev/null and b/3rdparty/lib/armeabi-v7a/libnative_camera_r2.2.2.so differ diff --git a/3rdparty/lib/armeabi-v7a/libnative_camera_r2.3.3.so b/3rdparty/lib/armeabi-v7a/libnative_camera_r2.3.3.so new file mode 100644 index 0000000000..28c567672b Binary files /dev/null and b/3rdparty/lib/armeabi-v7a/libnative_camera_r2.3.3.so differ diff --git a/3rdparty/lib/armeabi/libnative_camera_r2.2.2.so b/3rdparty/lib/armeabi/libnative_camera_r2.2.2.so new file mode 100755 index 0000000000..5209ce29d0 Binary files /dev/null and b/3rdparty/lib/armeabi/libnative_camera_r2.2.2.so differ diff --git a/3rdparty/lib/armeabi/libnative_camera_r2.3.3.so b/3rdparty/lib/armeabi/libnative_camera_r2.3.3.so new file mode 100755 index 0000000000..af006de71b Binary files /dev/null and b/3rdparty/lib/armeabi/libnative_camera_r2.3.3.so differ diff --git a/3rdparty/lib/libnative_camera_r2.2.2.so b/3rdparty/lib/libnative_camera_r2.2.2.so deleted file mode 100644 index 0866e4348a..0000000000 Binary files a/3rdparty/lib/libnative_camera_r2.2.2.so and /dev/null differ diff --git a/3rdparty/lib/libnative_camera_r2.3.3.so b/3rdparty/lib/libnative_camera_r2.3.3.so deleted file mode 100644 index 54e6c09b26..0000000000 Binary files a/3rdparty/lib/libnative_camera_r2.3.3.so and /dev/null differ diff --git a/3rdparty/libjasper/CMakeLists.txt b/3rdparty/libjasper/CMakeLists.txt index 4a5a2faf4e..a381dbedf9 100644 --- a/3rdparty/libjasper/CMakeLists.txt +++ b/3rdparty/libjasper/CMakeLists.txt @@ -45,7 +45,7 @@ set_target_properties(${the_target} PROPERTIES OUTPUT_NAME "${the_target}" DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/${OPENCV_LIB_INSTALL_PATH}" ) if(ENABLE_SOLUTION_FOLDERS) @@ -54,5 +54,5 @@ endif() if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} - ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) + ARCHIVE DESTINATION share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH} COMPONENT main) endif() diff --git a/3rdparty/libjpeg/CMakeLists.txt b/3rdparty/libjpeg/CMakeLists.txt index c78bfc369c..b432701455 100644 --- a/3rdparty/libjpeg/CMakeLists.txt +++ b/3rdparty/libjpeg/CMakeLists.txt @@ -37,7 +37,7 @@ endif() set_target_properties(${the_target} PROPERTIES OUTPUT_NAME "${the_target}" DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty/lib + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty/${OPENCV_LIB_INSTALL_PATH} ) if(ENABLE_SOLUTION_FOLDERS) @@ -46,5 +46,5 @@ endif() if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} - ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) + ARCHIVE DESTINATION share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH} COMPONENT main) endif() diff --git a/3rdparty/libpng/CMakeLists.txt b/3rdparty/libpng/CMakeLists.txt index 4eda135002..e7e91da2ab 100644 --- a/3rdparty/libpng/CMakeLists.txt +++ b/3rdparty/libpng/CMakeLists.txt @@ -38,7 +38,7 @@ endif() set_target_properties(${the_target} PROPERTIES OUTPUT_NAME "${the_target}" DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/${OPENCV_LIB_INSTALL_PATH}" ) if(ENABLE_SOLUTION_FOLDERS) @@ -47,5 +47,5 @@ endif() if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} - ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) + ARCHIVE DESTINATION share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH} COMPONENT main) endif() diff --git a/3rdparty/libtiff/CMakeLists.txt b/3rdparty/libtiff/CMakeLists.txt index 899ff987fd..924c22e8a5 100644 --- a/3rdparty/libtiff/CMakeLists.txt +++ b/3rdparty/libtiff/CMakeLists.txt @@ -92,7 +92,7 @@ set_target_properties(${the_target} PROPERTIES OUTPUT_NAME "${the_target}" DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib/" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/${OPENCV_LIB_INSTALL_PATH}" ) if(ENABLE_SOLUTION_FOLDERS) @@ -101,5 +101,5 @@ endif() if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} - ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) + ARCHIVE DESTINATION share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH} COMPONENT main) endif() diff --git a/3rdparty/libtiff/tif_color.c b/3rdparty/libtiff/tif_color.c index 02eb346b06..da140030c8 100644 --- a/3rdparty/libtiff/tif_color.c +++ b/3rdparty/libtiff/tif_color.c @@ -1,4 +1,4 @@ -/* $Id: tif_color.c,v 1.12.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ +/* $Id: tif_color.c,v 1.12.2.2 2010-12-14 02:23:09 faxguy Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -183,13 +183,18 @@ void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr, uint32 *r, uint32 *g, uint32 *b) { + int32 i; + /* XXX: Only 8-bit YCbCr input supported for now */ Y = HICLAMP(Y, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255); - *r = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]]; - *g = ycbcr->clamptab[ycbcr->Y_tab[Y] - + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT)]; - *b = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]]; + i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]; + *r = CLAMP(i, 0, 255); + i = ycbcr->Y_tab[Y] + + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT); + *g = CLAMP(i, 0, 255); + i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]; + *b = CLAMP(i, 0, 255); } /* diff --git a/3rdparty/libtiff/tif_dir.c b/3rdparty/libtiff/tif_dir.c index ac44b381f8..335ee58f41 100644 --- a/3rdparty/libtiff/tif_dir.c +++ b/3rdparty/libtiff/tif_dir.c @@ -1,4 +1,4 @@ -/* $Id: tif_dir.c,v 1.75.2.5 2010-06-09 21:15:27 bfriesen Exp $ */ +/* $Id: tif_dir.c,v 1.75.2.6 2010-07-02 09:49:23 dron Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -163,7 +163,9 @@ _TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) * work in with its normal work. */ if (tif->tif_flags & TIFF_SWAB) { - if (td->td_bitspersample == 16) + if (td->td_bitspersample == 8) + tif->tif_postdecode = _TIFFNoPostDecode; + else if (td->td_bitspersample == 16) tif->tif_postdecode = _TIFFSwab16BitData; else if (td->td_bitspersample == 24) tif->tif_postdecode = _TIFFSwab24BitData; diff --git a/3rdparty/libtiff/tif_dirread.c b/3rdparty/libtiff/tif_dirread.c index 0fb205beb5..a9da79769d 100644 --- a/3rdparty/libtiff/tif_dirread.c +++ b/3rdparty/libtiff/tif_dirread.c @@ -1,4 +1,4 @@ -/* $Id: tif_dirread.c,v 1.92.2.9 2010-06-14 00:21:46 fwarmerdam Exp $ */ +/* $Id: tif_dirread.c,v 1.92.2.15 2010-12-31 16:12:40 olivier Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -54,7 +54,7 @@ static float TIFFFetchRational(TIFF*, TIFFDirEntry*); static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*); static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, uint16*); static int TIFFFetchPerSampleLongs(TIFF*, TIFFDirEntry*, uint32*); -static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*, double*); static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*); static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**); static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*); @@ -83,6 +83,7 @@ TIFFReadDirectory(TIFF* tif) const TIFFFieldInfo* fip; size_t fix; uint16 dircount; + uint16 previous_tag = 0; int diroutoforderwarning = 0, compressionknown = 0; int haveunknowntags = 0; @@ -105,7 +106,20 @@ TIFFReadDirectory(TIFF* tif) tif->tif_name, tif->tif_nextdiroff); return 0; } - + { + TIFFDirEntry* ma; + uint16 mb; + for (ma=dir, mb=0; mbtdir_tag==na->tdir_tag) + na->tdir_tag=IGNORE; + } + } + } tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ /* * Setup default value and then make a pass over @@ -163,23 +177,24 @@ TIFFReadDirectory(TIFF* tif) if (dp->tdir_tag == IGNORE) continue; - if (fix >= tif->tif_nfields) - fix = 0; /* * Silicon Beach (at least) writes unordered * directory tags (violating the spec). Handle * it here, but be obnoxious (maybe they'll fix it?). */ - if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) { + if (dp->tdir_tag < previous_tag) { if (!diroutoforderwarning) { TIFFWarningExt(tif->tif_clientdata, module, "%s: invalid TIFF directory; tags are not sorted in ascending order", tif->tif_name); diroutoforderwarning = 1; } - fix = 0; /* O(n^2) */ } + previous_tag = dp->tdir_tag; + if (fix >= tif->tif_nfields || + dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) + fix = 0; /* O(n^2) */ while (fix < tif->tif_nfields && tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) fix++; @@ -465,11 +480,18 @@ TIFFReadDirectory(TIFF* tif) } break; case TIFFTAG_SMINSAMPLEVALUE: + { + double minv = 0.0, maxv = 0.0; + if (!TIFFFetchPerSampleAnys(tif, dp, &minv, &maxv) || + !TIFFSetField(tif, dp->tdir_tag, minv)) + goto bad; + } + break; case TIFFTAG_SMAXSAMPLEVALUE: { - double dv = 0.0; - if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || - !TIFFSetField(tif, dp->tdir_tag, dv)) + double minv = 0.0, maxv = 0.0; + if (!TIFFFetchPerSampleAnys(tif, dp, &minv, &maxv) || + !TIFFSetField(tif, dp->tdir_tag, maxv)) goto bad; } break; @@ -593,8 +615,7 @@ TIFFReadDirectory(TIFF* tif) } if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) { - if ((td->td_photometric==PHOTOMETRIC_RGB) - || (td->td_photometric==PHOTOMETRIC_YCBCR)) + if (td->td_photometric==PHOTOMETRIC_RGB) { TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory", @@ -603,13 +624,22 @@ TIFFReadDirectory(TIFF* tif) if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) goto bad; } - else if ((td->td_photometric==PHOTOMETRIC_MINISWHITE) - || (td->td_photometric==PHOTOMETRIC_MINISBLACK)) + if (td->td_photometric==PHOTOMETRIC_YCBCR) { TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory", "SamplesPerPixel tag is missing, " - "assuming correct SamplesPerPixel value is 1"); + "applying correct SamplesPerPixel value of 3"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) + goto bad; + } + else if ((td->td_photometric==PHOTOMETRIC_MINISWHITE) + || (td->td_photometric==PHOTOMETRIC_MINISBLACK)) + { + /* + * SamplesPerPixel tag is missing, but is not required + * by spec. Assume correct SamplesPerPixel value of 1. + */ if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1)) goto bad; } @@ -620,8 +650,14 @@ TIFFReadDirectory(TIFF* tif) */ if (td->td_photometric == PHOTOMETRIC_PALETTE && !TIFFFieldSet(tif, FIELD_COLORMAP)) { - MissingRequired(tif, "Colormap"); - goto bad; + if ( tif->tif_dir.td_bitspersample>=8 && tif->tif_dir.td_samplesperpixel==3) + tif->tif_dir.td_photometric = PHOTOMETRIC_RGB; + else if (tif->tif_dir.td_bitspersample>=8) + tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK; + else { + MissingRequired(tif, "Colormap"); + goto bad; + } } /* * OJPEG hack: @@ -1086,6 +1122,7 @@ CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count) "incorrect count for field \"%s\" (%u, expecting %u); tag trimmed", _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, dir->tdir_count, count); + dir->tdir_count = count; return (1); } return (1); @@ -1413,14 +1450,14 @@ TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir) case TIFF_BYTE: case TIFF_SBYTE: { - uint8 v[4]; + uint8 v[4]={0,0,0,0}; return TIFFFetchByteArray(tif, dir, v) && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); } case TIFF_SHORT: case TIFF_SSHORT: { - uint16 v[2]={0,0}; + uint16 v[2]={0,0}; return TIFFFetchShortArray(tif, dir, v) && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); } @@ -1822,11 +1859,11 @@ TIFFFetchPerSampleLongs(TIFF* tif, TIFFDirEntry* dir, uint32* pl) } /* - * Fetch samples/pixel ANY values for the specified tag and verify that all - * values are the same. + * Fetch samples/pixel ANY values for the specified tag and returns their min + * and max. */ static int -TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl) +TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* minv, double* maxv) { uint16 samples = tif->tif_dir.td_samplesperpixel; int status = 0; @@ -1844,17 +1881,16 @@ TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl) if( samples < check_count ) check_count = samples; + *minv = *maxv = v[0]; for (i = 1; i < check_count; i++) - if (v[i] != v[0]) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Cannot handle different per-sample values for field \"%s\"", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - goto bad; - } - *pl = v[0]; + { + if (v[i] < *minv) + *minv = v[i]; + if (v[i] > *maxv) + *maxv = v[i]; + } status = 1; } - bad: if (v && v != buf) _TIFFfree(v); } diff --git a/3rdparty/libtiff/tif_dirwrite.c b/3rdparty/libtiff/tif_dirwrite.c index 8d308c4292..6f298399c2 100644 --- a/3rdparty/libtiff/tif_dirwrite.c +++ b/3rdparty/libtiff/tif_dirwrite.c @@ -1,4 +1,4 @@ -/* $Id: tif_dirwrite.c,v 1.37.2.7 2010-06-08 18:50:42 bfriesen Exp $ */ +/* $Id: tif_dirwrite.c,v 1.37.2.9 2011-02-25 15:28:30 dron Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -42,6 +42,7 @@ extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*); static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*); static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32); static void TIFFSetupShort(TIFF*, ttag_t, TIFFDirEntry*, uint16); +static int TIFFSetupBytePair(TIFF*, ttag_t, TIFFDirEntry*); static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*); static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*); static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*); @@ -291,12 +292,6 @@ _TIFFWriteDirectory(TIFF* tif, int done) _TIFFSampleToTagType(tif), fip->field_tag, dir)) goto bad; break; - case FIELD_PAGENUMBER: - case FIELD_HALFTONEHINTS: - case FIELD_YCBCRSUBSAMPLING: - if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) - goto bad; - break; case FIELD_INKNAMES: if (!TIFFWriteInkNames(tif, dir)) goto bad; @@ -336,12 +331,22 @@ _TIFFWriteDirectory(TIFF* tif, int done) } break; default: - /* XXX: Should be fixed and removed. */ - if (fip->field_tag == TIFFTAG_DOTRANGE) { - if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) - goto bad; - } - else if (!TIFFWriteNormalTag(tif, dir, fip)) + /* + * XXX: Should be fixed and removed. See comments + * related to these tags in tif_dir.c. + */ + if (fip->field_tag == TIFFTAG_PAGENUMBER + || fip->field_tag == TIFFTAG_HALFTONEHINTS + || fip->field_tag == TIFFTAG_YCBCRSUBSAMPLING + || fip->field_tag == TIFFTAG_DOTRANGE) { + if (fip->field_type == TIFF_BYTE) { + if (!TIFFSetupBytePair(tif, fip->field_tag, dir)) + goto bad; + } else if (fip->field_type == TIFF_SHORT) { + if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) + goto bad; + } + } else if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; break; } @@ -875,6 +880,23 @@ TIFFWritePerSampleAnys(TIFF* tif, } #undef NITEMS +/* + * Setup a pair of bytes that are returned by + * value, rather than as a reference to an array. + */ +static int +TIFFSetupBytePair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) +{ + char v[2]; + + TIFFGetField(tif, tag, &v[0], &v[1]); + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (uint16) TIFF_BYTE; + dir->tdir_count = 2; + return (TIFFWriteByteArray(tif, dir, v)); +} + /* * Setup a pair of shorts that are returned by * value, rather than as a reference to an array. @@ -1019,7 +1041,7 @@ TIFFWriteRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v) while (fv < 1L<<(31-3) && den < 1L<<(31-3)) fv *= 1<<3, den *= 1L<<3; } - t[2*i+0] = (uint32) (sign * (fv + 0.5)); + t[2*i+0] = (uint32) (sign * (int32)(fv + 0.5)); t[2*i+1] = den; } status = TIFFWriteData(tif, dir, (char *)t); diff --git a/3rdparty/libtiff/tif_fax3.h b/3rdparty/libtiff/tif_fax3.h index 40718bcfa7..d7d7723a6a 100644 --- a/3rdparty/libtiff/tif_fax3.h +++ b/3rdparty/libtiff/tif_fax3.h @@ -1,4 +1,4 @@ -/* $Id: tif_fax3.h,v 1.5.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ +/* $Id: tif_fax3.h,v 1.5.2.3 2011-03-10 20:22:33 fwarmerdam Exp $ */ /* * Copyright (c) 1990-1997 Sam Leffler @@ -478,6 +478,12 @@ done1d: \ break; \ case S_VL: \ CHECK_b1; \ + if (b1 <= (int) (a0 + TabEnt->Param)) { \ + if (b1 < (int) (a0 + TabEnt->Param) || pa != thisrun) { \ + unexpected("VL", a0); \ + goto eol2d; \ + } \ + } \ SETVALUE(b1 - a0 - TabEnt->Param); \ b1 -= *--pb; \ break; \ diff --git a/3rdparty/libtiff/tif_getimage.c b/3rdparty/libtiff/tif_getimage.c index 38455fbc07..11d59e06e6 100644 --- a/3rdparty/libtiff/tif_getimage.c +++ b/3rdparty/libtiff/tif_getimage.c @@ -1,4 +1,4 @@ -/* $Id: tif_getimage.c,v 1.63.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ +/* $Id: tif_getimage.c,v 1.63.2.6 2010-07-02 13:38:27 dron Exp $ */ /* * Copyright (c) 1991-1997 Sam Leffler @@ -1846,6 +1846,7 @@ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) DECLAREContigPutFunc(putcontig8bitYCbCr22tile) { uint32* cp2; + int32 incr = 2*toskew+w; (void) y; fromskew = (fromskew / 2) * 6; cp2 = cp+w+toskew; @@ -1872,8 +1873,8 @@ DECLAREContigPutFunc(putcontig8bitYCbCr22tile) cp2 ++ ; pp += 6; } - cp += toskew*2+w; - cp2 += toskew*2+w; + cp += incr; + cp2 += incr; pp += fromskew; h-=2; } @@ -1939,6 +1940,7 @@ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) DECLAREContigPutFunc(putcontig8bitYCbCr12tile) { uint32* cp2; + int32 incr = 2*toskew+w; (void) y; fromskew = (fromskew / 2) * 4; cp2 = cp+w+toskew; @@ -1953,8 +1955,8 @@ DECLAREContigPutFunc(putcontig8bitYCbCr12tile) cp2 ++; pp += 4; } while (--x); - cp += toskew*2+w; - cp2 += toskew*2+w; + cp += incr; + cp2 += incr; pp += fromskew; h-=2; } @@ -2397,7 +2399,7 @@ PickContigCase(TIFFRGBAImage* img) } break; case PHOTOMETRIC_YCBCR: - if (img->bitspersample == 8) + if ((img->bitspersample==8) && (img->samplesperpixel==3)) { if (initYCbCrConversion(img)!=0) { diff --git a/3rdparty/libtiff/tif_jpeg.c b/3rdparty/libtiff/tif_jpeg.c index a967827e74..7fc3e95929 100644 --- a/3rdparty/libtiff/tif_jpeg.c +++ b/3rdparty/libtiff/tif_jpeg.c @@ -1,4 +1,4 @@ -/* $Id: tif_jpeg.c,v 1.50.2.9 2010-06-14 02:47:16 fwarmerdam Exp $ */ +/* $Id: tif_jpeg.c,v 1.50.2.17 2011-01-04 02:51:17 faxguy Exp $ */ /* * Copyright (c) 1994-1997 Sam Leffler @@ -988,8 +988,15 @@ JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) tsize_t nrows; (void) s; - /* data is expected to be read in multiples of a scanline */ - if ( (nrows = sp->cinfo.d.image_height) ) { + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read"); + + if( nrows > (int) sp->cinfo.d.image_height ) + nrows = sp->cinfo.d.image_height; + + /* data is expected to be read in multiples of a scanline */ + if (nrows) { /* Cb,Cr both have sampling factors 1, so this is correct */ JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width; int samples_per_clump = sp->samplesperclump; @@ -1064,7 +1071,7 @@ JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) } } else - { // 12-bit + { /* 12-bit */ int value_pairs = (sp->cinfo.d.output_width * sp->cinfo.d.num_components) / 2; int iPair; @@ -1087,8 +1094,7 @@ JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) * TODO: resolve this */ buf += sp->bytesperline; cc -= sp->bytesperline; - nrows -= sp->v_sampling; - } while (nrows > 0); + } while (--nrows > 0); #ifdef JPEG_LIB_MK1 _TIFFfree(tmpbuf); @@ -1352,8 +1358,15 @@ JPEGPreEncode(TIFF* tif, tsample_t s) sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; } else { - sp->cinfo.c.in_color_space = JCS_UNKNOWN; - if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1) + sp->cinfo.c.in_color_space = JCS_GRAYSCALE; + else if (td->td_photometric == PHOTOMETRIC_RGB) + sp->cinfo.c.in_color_space = JCS_RGB; + else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4) + sp->cinfo.c.in_color_space = JCS_CMYK; + else + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space)) return (0); /* jpeg_set_colorspace set all sampling factors to 1 */ } @@ -1523,7 +1536,7 @@ JPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) sp->scancount = 0; } tif->tif_row += sp->v_sampling; - buf += sp->bytesperline; + buf += bytesperclumpline; nrows -= sp->v_sampling; } return (1); diff --git a/3rdparty/libtiff/tif_ojpeg.c b/3rdparty/libtiff/tif_ojpeg.c index 9ae856cfde..9eba6d5c6a 100644 --- a/3rdparty/libtiff/tif_ojpeg.c +++ b/3rdparty/libtiff/tif_ojpeg.c @@ -1,4 +1,4 @@ -/* $Id: tif_ojpeg.c,v 1.24.2.6 2010-06-08 23:29:51 bfriesen Exp $ */ +/* $Id: tif_ojpeg.c,v 1.24.2.8 2010-12-11 21:25:04 faxguy Exp $ */ /* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0 specification is now totally obsolete and deprecated for new applications and @@ -1537,7 +1537,6 @@ OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id) OJPEGReadSkip(sp,4); else { - /* TODO: probably best to also add check on allowed upper bound, especially x, may cause buffer overflow otherwise i think */ /* Y: Number of lines */ if (OJPEGReadWord(sp,&p)==0) return(0); @@ -1555,6 +1554,11 @@ OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id) TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width"); return(0); } + if ((uint32)p>sp->strile_width) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data image width exceeds expected image width"); + return(0); + } sp->sof_x=p; } /* Nf: Number of image components in frame */ @@ -1918,8 +1922,14 @@ OJPEGReadBufferFill(OJPEGState* sp) { if (sp->in_buffer_file_pos>=sp->file_size) sp->in_buffer_file_pos=0; + else if (sp->tif->tif_dir.td_stripbytecount==NULL) + sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; else { + if (sp->tif->tif_dir.td_stripbytecount == 0) { + TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip byte counts are missing"); + return(0); + } sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile]; if (sp->in_buffer_file_togo==0) sp->in_buffer_file_pos=0; diff --git a/3rdparty/libtiff/tif_open.c b/3rdparty/libtiff/tif_open.c index 3b3b2ce67b..4ad04d2cf9 100644 --- a/3rdparty/libtiff/tif_open.c +++ b/3rdparty/libtiff/tif_open.c @@ -1,4 +1,4 @@ -/* $Id: tif_open.c,v 1.33.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ +/* $Id: tif_open.c,v 1.33.2.2 2010-12-06 16:54:22 faxguy Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -304,7 +304,7 @@ TIFFClientOpen( /* * Read in TIFF header. */ - if (tif->tif_mode & O_TRUNC || + if ((m & O_TRUNC) || !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeader))) { if (tif->tif_mode == O_RDONLY) { TIFFErrorExt(tif->tif_clientdata, name, diff --git a/3rdparty/libtiff/tif_print.c b/3rdparty/libtiff/tif_print.c index d9e4435c50..ce563cbe06 100644 --- a/3rdparty/libtiff/tif_print.c +++ b/3rdparty/libtiff/tif_print.c @@ -1,4 +1,4 @@ -/* $Id: tif_print.c,v 1.36.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ +/* $Id: tif_print.c,v 1.36.2.5 2010-07-06 14:05:30 dron Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -115,8 +115,6 @@ static int _TIFFPrettyPrintField(TIFF* tif, FILE* fd, ttag_t tag, uint32 value_count, void *raw_data) { - //TIFFDirectory *td = &tif->tif_dir; - switch (tag) { case TIFFTAG_INKSET: @@ -132,10 +130,6 @@ _TIFFPrettyPrintField(TIFF* tif, FILE* fd, ttag_t tag, break; } return 1; - case TIFFTAG_DOTRANGE: - fprintf(fd, " Dot Range: %u-%u\n", - ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]); - return 1; case TIFFTAG_WHITEPOINT: fprintf(fd, " White Point: %g-%g\n", ((float *)raw_data)[0], ((float *)raw_data)[1]); return 1; diff --git a/3rdparty/libtiff/tif_strip.c b/3rdparty/libtiff/tif_strip.c index 63dec6bdac..0542d004fa 100644 --- a/3rdparty/libtiff/tif_strip.c +++ b/3rdparty/libtiff/tif_strip.c @@ -1,4 +1,4 @@ -/* $Id: tif_strip.c,v 1.19.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ +/* $Id: tif_strip.c,v 1.19.2.3 2010-12-15 00:50:30 faxguy Exp $ */ /* * Copyright (c) 1991-1997 Sam Leffler @@ -124,9 +124,9 @@ TIFFVStripSize(TIFF* tif, uint32 nrows) uint16 ycbcrsubsampling[2]; tsize_t w, scanline, samplingarea; - TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, - ycbcrsubsampling + 0, - ycbcrsubsampling + 1 ); + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling + 0, + ycbcrsubsampling + 1); samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1]; if (samplingarea == 0) { @@ -234,27 +234,23 @@ TIFFScanlineSize(TIFF* tif) && !isUpSampled(tif)) { uint16 ycbcrsubsampling[2]; - TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, - ycbcrsubsampling + 0, - ycbcrsubsampling + 1); + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling + 0, + ycbcrsubsampling + 1); - if (ycbcrsubsampling[0] == 0) { + if (ycbcrsubsampling[0]*ycbcrsubsampling[1] == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); return 0; } - scanline = TIFFroundup(td->td_imagewidth, + /* number of sample clumps per line */ + scanline = TIFFhowmany(td->td_imagewidth, ycbcrsubsampling[0]); - scanline = TIFFhowmany8(multiply(tif, scanline, - td->td_bitspersample, - "TIFFScanlineSize")); - return ((tsize_t) - summarize(tif, scanline, - multiply(tif, 2, - scanline / ycbcrsubsampling[0], - "TIFFVStripSize"), - "TIFFVStripSize")); + /* number of samples per line */ + scanline = multiply(tif, scanline, + ycbcrsubsampling[0]*ycbcrsubsampling[1] + 2, + "TIFFScanlineSize"); } else { scanline = multiply(tif, td->td_imagewidth, td->td_samplesperpixel, @@ -308,9 +304,9 @@ TIFFNewScanlineSize(TIFF* tif) && !isUpSampled(tif)) { uint16 ycbcrsubsampling[2]; - TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, - ycbcrsubsampling + 0, - ycbcrsubsampling + 1); + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling + 0, + ycbcrsubsampling + 1); if (ycbcrsubsampling[0]*ycbcrsubsampling[1] == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, diff --git a/3rdparty/libtiff/tif_thunder.c b/3rdparty/libtiff/tif_thunder.c index 8e7a125841..62e4bc75ed 100644 --- a/3rdparty/libtiff/tif_thunder.c +++ b/3rdparty/libtiff/tif_thunder.c @@ -1,4 +1,4 @@ -/* $Id: tif_thunder.c,v 1.5.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ +/* $Id: tif_thunder.c,v 1.5.2.2 2011-03-21 16:01:28 fwarmerdam Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -25,6 +25,7 @@ */ #include "tiffiop.h" +#include #ifdef THUNDER_SUPPORT /* * TIFF Library. @@ -55,12 +56,32 @@ static const int twobitdeltas[4] = { 0, 1, 0, -1 }; static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 }; -#define SETPIXEL(op, v) { \ - lastpixel = (v) & 0xf; \ - if (npixels++ & 1) \ - *op++ |= lastpixel; \ - else \ +#define SETPIXEL(op, v) { \ + lastpixel = (v) & 0xf; \ + if ( npixels < maxpixels ) \ + { \ + if (npixels++ & 1) \ + *op++ |= lastpixel; \ + else \ op[0] = (tidataval_t) (lastpixel << 4); \ + } \ +} + +static int +ThunderSetupDecode(TIFF* tif) +{ + static const char module[] = "ThunderSetupDecode"; + + if( tif->tif_dir.td_bitspersample != 4 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample.", + (int) tif->tif_dir.td_bitspersample ); + return 0; + } + + + return (1); } static int @@ -142,7 +163,8 @@ ThunderDecodeRow(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) occ -= tif->tif_scanlinesize; row += tif->tif_scanlinesize; } - return (1); + + return (1); } int @@ -151,6 +173,7 @@ TIFFInitThunderScan(TIFF* tif, int scheme) (void) scheme; tif->tif_decoderow = ThunderDecodeRow; tif->tif_decodestrip = ThunderDecodeRow; + tif->tif_setupdecode = ThunderSetupDecode; return (1); } #endif /* THUNDER_SUPPORT */ @@ -163,3 +186,4 @@ TIFFInitThunderScan(TIFF* tif, int scheme) * fill-column: 78 * End: */ + diff --git a/3rdparty/libtiff/tiffiop.h b/3rdparty/libtiff/tiffiop.h index a064039f6b..f65f8550ea 100644 --- a/3rdparty/libtiff/tiffiop.h +++ b/3rdparty/libtiff/tiffiop.h @@ -1,4 +1,4 @@ -/* $Id: tiffiop.h,v 1.51.2.6 2010-06-12 02:55:16 bfriesen Exp $ */ +/* $Id: tiffiop.h,v 1.51.2.7 2011-03-21 21:09:19 fwarmerdam Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -59,10 +59,13 @@ extern void *lfind(const void *, const void *, size_t *, size_t, /* Libtiff itself does not require a 64-bit type, but bundled TIFF - utilities may use it. + utilities may use it. */ + +#if !defined(__xlC__) && !defined(__xlc__) // Already defined there (#2301) typedef TIFF_INT64_T int64; typedef TIFF_UINT64_T uint64; +#endif #include "tiffio.h" #include "tif_dir.h" diff --git a/3rdparty/libtiff/tiffvers.h b/3rdparty/libtiff/tiffvers.h index 314a22a0ae..a5607aafa9 100644 --- a/3rdparty/libtiff/tiffvers.h +++ b/3rdparty/libtiff/tiffvers.h @@ -1,4 +1,4 @@ -#define TIFFLIB_VERSION_STR "LIBTIFF, Version 3.9.4\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 3.9.5\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." /* * This define can be used in code that requires * compilation-related definitions specific to a @@ -6,4 +6,4 @@ * version checking should be done based on the * string returned by TIFFGetVersion. */ -#define TIFFLIB_VERSION 20100615 +#define TIFFLIB_VERSION 20110409 diff --git a/3rdparty/readme.txt b/3rdparty/readme.txt index b06f83d93e..5fdd2145bf 100644 --- a/3rdparty/readme.txt +++ b/3rdparty/readme.txt @@ -11,7 +11,6 @@ libjpeg 6b (6.2) - The Independent JPEG Group's JPEG software. HAVE_JPEG preprocessor flag must be set to make highgui use libjpeg. On UNIX systems configure script takes care of it. - ------------------------------------------------------------------------------------ libpng 1.4.3 - Portable Network Graphics library. Copyright (C) 1998-2010, Glenn Randers-Pehrson. @@ -20,15 +19,13 @@ libpng 1.4.3 - Portable Network Graphics library. HAVE_PNG preprocessor flag must be set to make highgui use libpng. On UNIX systems configure script takes care of it. - ------------------------------------------------------------------------------------ -libtiff 3.9.4 - Tag Image File Format (TIFF) Software +libtiff 3.9.5 - Tag Image File Format (TIFF) Software Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. See libtiff home page http://www.libtiff.org for details and links to the source code - HAVE_TIFF preprocessor flag must be set to make highgui use libtiff. On UNIX systems configure script takes care of it. @@ -42,9 +39,7 @@ zlib 1.2.5 - General purpose LZ77 compression library No preprocessor definition is needed to make highgui use this library - it is included automatically if either libpng or libtiff are used. - ------------------------------------------------------------------------------------ - jasper-1.900.1 - JasPer is a collection of software (i.e., a library and application programs) for the coding and manipulation of images. This software can handle image data in a @@ -61,9 +56,7 @@ jasper-1.900.1 - JasPer is a collection of software (lib/libjasper*). To get the latest source code, please, visit the project homepage: http://www.ece.uvic.ca/~mdadams/jasper/ - ------------------------------------------------------------------------------------ - openexr-1.4.0 - OpenEXR is a high dynamic-range (HDR) image file format developed by Industrial Light & Magic for use in computer imaging applications. @@ -73,34 +66,15 @@ openexr-1.4.0 - OpenEXR is a high dynamic-range (HDR) image file format develope The project homepage: http://www.openexr.com/ - OpenCV on Windows does not include openexr codec by default. - To add it, you will need to recompile highgui with OpenEXR support - using VS.NET2003 or VS.NET2005 (MSVC6 can not compile it): - 1) download binaries (e.g. openexr-1.4.0-vs2005.zip) - from the official site. - 2) copy - half.lib, iex.lib, ilmimf.lib ilmthread.lib imath.lib to - _graphics/lib - 3) copy include/openexr/*.h to _graphics/include/openexr - 4) open _make/opencv.sln - 5) in highgui/_highgui.h uncomment - #define HAVE_ILMIMF 1 - 6) build debug/release configurations of highgui. - + OpenCV does not include openexr codec. + To add it, you will need install OpenEXR, reconfigure OpenCV + using CMake (make sure OpenEXR library is found) and the rebuild OpenCV. ------------------------------------------------------------------------------------ - -ffmpeg-0.6.0 - FFmpeg is a complete, cross-platform solution to record, +ffmpeg-0.8.0 - FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video. It includes libavcodec - the leading audio/video codec library, and also libavformat, libavutils and other helper libraries that are used by OpenCV (in highgui module) to read and write video files. The project homepage: http://ffmpeg.org/ - ------------------------------------------------------------------------------------- - -videoInput-0.1995 - Video capturing library for Windows using DirectShow as backend - Written by Theodore Watson - http://muonics.net/school/spring05/videoInput/ - ------------------------------------------------------------------------------------ diff --git a/3rdparty/zlib/CMakeLists.txt b/3rdparty/zlib/CMakeLists.txt index 1fc3c5d14f..1964af039d 100644 --- a/3rdparty/zlib/CMakeLists.txt +++ b/3rdparty/zlib/CMakeLists.txt @@ -29,7 +29,7 @@ set_target_properties(${the_target} PROPERTIES OUTPUT_NAME "${the_target}" DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/${OPENCV_LIB_INSTALL_PATH}" ) if(ENABLE_SOLUTION_FOLDERS) @@ -38,5 +38,5 @@ endif() if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} - ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) + ARCHIVE DESTINATION share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH} COMPONENT main) endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index c4fbbdb15e..9e1347b61c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,24 +11,39 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) -# Add these standard paths to the search paths for FIND_LIBRARY -# to find libraries from these locations first -if(UNIX) - set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /lib /usr/lib) -endif() +# Following block can broke build in case of cross-compilng +# but CMAKE_CROSSCOMPILING variable will be set only on project(OpenCV) command +# so we will try to detect crosscompiling by presense of CMAKE_TOOLCHAIN_FILE +if(NOT CMAKE_TOOLCHAIN_FILE) + # Add these standard paths to the search paths for FIND_LIBRARY + # to find libraries from these locations first + if(UNIX) + set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /lib /usr/lib) + endif() + # it _must_ go before PROJECT(OpenCV) in order to work + if(WIN32) + set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Installation Directory") + else() + set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Installation Directory") + endif() -# it _must_ go before PROJECT(OpenCV) in order to work -if(WIN32) - set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Installation Directory") -else() - set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Installation Directory") -endif() + if(MSVC) + set(CMAKE_USE_RELATIVE_PATHS ON CACHE INTERNAL "" FORCE) + endif() +endif(NOT CMAKE_TOOLCHAIN_FILE) -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +# -------------------------------------------------------------- +# Top level OpenCV project +# -------------------------------------------------------------- +cmake_minimum_required(VERSION 2.4) +project(OpenCV) set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE) +if(DEFINED CMAKE_BUILD_TYPE) + set_property( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES} ) +endif() + set(CMAKE_C_FLAGS_MINSIZEREL "" CACHE INTERNAL "" FORCE) set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "" FORCE) set(CMAKE_CXX_FLAGS_MINSIZEREL "" CACHE INTERNAL "" FORCE) @@ -40,30 +55,10 @@ set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "" FORCE) set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "" FORCE) set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "" FORCE) set(CMAKE_VERBOSE OFF CACHE BOOL "Verbose mode") - - -if (WIN32) - if(${CMAKE_GENERATOR} MATCHES "(MinGW)|(MSYS)") - set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG" CACHE STRING "") - endif() -endif() - if(CMAKE_VERBOSE) set(CMAKE_VERBOSE_MAKEFILE 1) endif() - -project(OpenCV) - - -cmake_minimum_required(VERSION 2.4) - - -if(MSVC) - set(CMAKE_USE_RELATIVE_PATHS ON CACHE INTERNAL "" FORCE) -endif() - - # -------------------------------------------------------------- # Indicate CMake 2.7 and above that we don't want to mix relative # and absolute paths in linker lib lists. @@ -86,18 +81,21 @@ set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries (.dll/.so) instead o set(BUILD_WITH_DEBUG_INFO ON CACHE BOOL "Include debug info into debug libs") # ---------------------------------------------------------------------------- -# Current version number: +# Get actual OpenCV version number from sources # ---------------------------------------------------------------------------- -set(OPENCV_VERSION "2.3.0") - -string(REGEX MATCHALL "[0-9]" OPENCV_VERSION_PARTS "${OPENCV_VERSION}") - -list(GET OPENCV_VERSION_PARTS 0 OPENCV_VERSION_MAJOR) -list(GET OPENCV_VERSION_PARTS 1 OPENCV_VERSION_MINOR) -list(GET OPENCV_VERSION_PARTS 2 OPENCV_VERSION_PATCH) +SET(OPENCV_VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/modules/core/include/opencv2/core/version.hpp") +FILE(STRINGS "${OPENCV_VERSION_FILE}" OPENCV_VERSION_PARTS REGEX "#define CV_.+OR_VERSION[ ]+[0-9]+" ) +string(REGEX REPLACE ".+CV_MAJOR_VERSION[ ]+([0-9]+).*" "\\1" OPENCV_VERSION_MAJOR "${OPENCV_VERSION_PARTS}") +string(REGEX REPLACE ".+CV_MINOR_VERSION[ ]+([0-9]+).*" "\\1" OPENCV_VERSION_MINOR "${OPENCV_VERSION_PARTS}") +string(REGEX REPLACE ".+CV_SUBMINOR_VERSION[ ]+([0-9]+).*" "\\1" OPENCV_VERSION_PATCH "${OPENCV_VERSION_PARTS}") +set(OPENCV_VERSION "${OPENCV_VERSION_MAJOR}.${OPENCV_VERSION_MINOR}.${OPENCV_VERSION_PATCH}") set(OPENCV_SOVERSION "${OPENCV_VERSION_MAJOR}.${OPENCV_VERSION_MINOR}") +# create a dependency on version file +# we will never use output of the following command but cmake will rerun if version file changes +configure_file("${OPENCV_VERSION_FILE}" "${CMAKE_BINARY_DIR}/junk/version.junk" COPYONLY) + if(WIN32) # Postfix of DLLs: set(OPENCV_DLLVERSION "${OPENCV_VERSION_MAJOR}${OPENCV_VERSION_MINOR}${OPENCV_VERSION_PATCH}") @@ -108,12 +106,56 @@ else() set(OPENCV_DEBUG_POSTFIX) endif() +#name mangling +set(OPENCV_INCLUDE_PREFIX include) +if(UNIX AND NOT ANDROID AND BUILD_SHARED_LIBS) + option(OPENCV_MANGLED_INSTALL_PATHS "Enables mangled install paths, that help with side by side installs." False) + if(OPENCV_MANGLED_INSTALL_PATHS) + set(OPENCV_INCLUDE_PREFIX include/opencv-${OPENCV_VERSION}) + endif() +endif() + +# SUBDIRECTORIES: +# Save libs and executables in the same place +set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Output directory for libraries" ) +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Output directory for applications" ) + +if(ANDROID OR WIN32) + set(OPENCV_DOC_INSTALL_PATH doc) +elseif(OPENCV_MANGLED_INSTALL_PATHS) + set(OPENCV_DOC_INSTALL_PATH share/OpenCV-${OPENCV_VERSION}/doc) +else() + set(OPENCV_DOC_INSTALL_PATH share/OpenCV/doc) +endif() + +if(ANDROID) + set(OPENCV_LIB_INSTALL_PATH libs/${ARMEABI_NDK_NAME}) +else() + set(OPENCV_LIB_INSTALL_PATH lib${LIB_SUFFIX}) +endif() + +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# search packages for host system instead of packages for target system +# in case of cross compilation thess macro should be defined by toolchain file +if(NOT COMMAND find_host_package) + macro(find_host_package) + find_package(${ARGN}) + endmacro() +endif() +if(NOT COMMAND find_host_program) + macro(find_host_program) + find_program(${ARGN}) + endmacro() +endif() + # ---------------------------------------------------------------------------- # Use statically or dynamically linked CRT? # Default: dynamic # ---------------------------------------------------------------------------- if(WIN32 AND NOT BUILD_SHARED_LIBS) - option (BUILD_WITH_STATIC_CRT "Enables use of staticaly linked CRT" OFF) + option (BUILD_WITH_STATIC_CRT "Enables use of staticaly linked CRT" ON) endif() if(MSVC) @@ -125,18 +167,15 @@ if(MSVC) CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - endif(${flag_var} MATCHES "/MD") - + endif() if(${flag_var} MATCHES "/MDd") string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") - endif(${flag_var} MATCHES "/MDd") + endif() endforeach(flag_var) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcrtd.lib") - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:libcmtd.lib") - else(BUILD_WITH_STATIC_CRT) foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE @@ -145,30 +184,28 @@ if(MSVC) CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MT") string(REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}") - endif(${flag_var} MATCHES "/MT") - + endif() if(${flag_var} MATCHES "/MTd") string(REGEX REPLACE "/MTd" "/MDd" ${flag_var} "${${flag_var}}") - endif(${flag_var} MATCHES "/MTd") + endif() endforeach(flag_var) - endif(BUILD_WITH_STATIC_CRT) if(NOT BUILD_WITH_DEBUG_INFO) string(REPLACE "/debug" "" CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") string(REPLACE "/DEBUG" "" CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") string(REPLACE "/INCREMENTAL:YES" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") - string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") + string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO " CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") string(REPLACE "/debug" "" CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}") string(REPLACE "/DEBUG" "" CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}") string(REPLACE "/INCREMENTAL:YES" "/INCREMENTAL:NO" CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}") - string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO" CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}") + string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO " CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}") string(REPLACE "/debug" "" CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") string(REPLACE "/DEBUG" "" CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") string(REPLACE "/INCREMENTAL:YES" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") - string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") + string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO " CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") string(REPLACE "/Zi" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "/Zi" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") @@ -186,24 +223,23 @@ set(PACKAGE_STRING "${PACKAGE} ${OPENCV_VERSION}") set(PACKAGE_TARNAME "${PACKAGE}") set(PACKAGE_VERSION "${OPENCV_VERSION}") - # ---------------------------------------------------------------------------- # Autodetect if we are in a SVN repository # ---------------------------------------------------------------------------- -find_program(SVNVERSION_PATH svnversion) +find_host_program(SVNVERSION_PATH svnversion) mark_as_advanced(force SVNVERSION_PATH) if(SVNVERSION_PATH) message(STATUS "Extracting svn version, please wait...") execute_process(COMMAND ${SVNVERSION_PATH} -n ${OpenCV_SOURCE_DIR} OUTPUT_VARIABLE SVNVERSION_RESULT) if(SVNVERSION_RESULT MATCHES "exported") - # This is NOT a svn repository: - set(OPENCV_SVNVERSION "") + # This is NOT a svn repository: + set(OPENCV_SVNVERSION "") + message(STATUS "SVNVERSION: exported") else() set(OPENCV_SVNVERSION " svn:${SVNVERSION_RESULT}") + message(STATUS "SVNVERSION: ${OPENCV_SVNVERSION}") endif() - - message(STATUS "SVNVERSION: ${OPENCV_SVNVERSION}") else() # We don't have svnversion: set(OPENCV_SVNVERSION "") @@ -229,11 +265,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) OUTPUT_STRIP_TRAILING_WHITESPACE) # Typical output in CMAKE_OPENCV_GCC_VERSION_FULL: "c+//0 (whatever) 4.2.3 (...)" - # Look for the version number - string(REGEX MATCH "[0-9].[0-9].[0-9]" CMAKE_GCC_REGEX_VERSION "${CMAKE_OPENCV_GCC_VERSION_FULL}") + # Look for the version number + string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" CMAKE_GCC_REGEX_VERSION "${CMAKE_OPENCV_GCC_VERSION_FULL}") # Split the three parts: - string(REGEX MATCHALL "[0-9]" CMAKE_OPENCV_GCC_VERSIONS "${CMAKE_GCC_REGEX_VERSION}") + string(REGEX MATCHALL "[0-9]+" CMAKE_OPENCV_GCC_VERSIONS "${CMAKE_GCC_REGEX_VERSION}") list(GET CMAKE_OPENCV_GCC_VERSIONS 0 CMAKE_OPENCV_GCC_VERSION_MAJOR) list(GET CMAKE_OPENCV_GCC_VERSIONS 1 CMAKE_OPENCV_GCC_VERSION_MINOR) @@ -250,10 +286,8 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(MINGW64 1) endif() endif() - endif() - # ---------------------------------------------------------------------------- # Detect Intel ICC compiler -- for -fPIC in 3rdparty ( UNIX ONLY ): # see include/opencv/cxtypes.h file for related ICC & CV_ICC defines. @@ -278,7 +312,6 @@ if(UNIX) endif() endif() - # ---------------------------------------------------------------------------- # CHECK FOR SYSTEM LIBRARIES, OPTIONS, ETC.. # ---------------------------------------------------------------------------- @@ -288,6 +321,9 @@ endif() set(BUILD_EXAMPLES OFF CACHE BOOL "Build all examples") set(INSTALL_C_EXAMPLES OFF CACHE BOOL "Install C examples") set(INSTALL_PYTHON_EXAMPLES OFF CACHE BOOL "Install Python examples") +if(ANDROID) + set(INSTALL_ANDROID_EXAMPLES OFF CACHE BOOL "Install Android examples") +endif() # Build tests: # =================================================== @@ -303,6 +339,9 @@ endif() include(OpenCVPCHSupport.cmake REQUIRED) include(OpenCVModule.cmake REQUIRED) +if(ANDROID) + include(OpenCVAndroidProject.cmake REQUIRED) +endif() if(PCHSupport_FOUND) SET(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Use precompiled headers") @@ -316,32 +355,28 @@ if(UNIX) include(CheckIncludeFile) endif() -#if(MSVC) -# set(DEFAULT_ENABLE_OPENMP ON) -#else() -# set(DEFAULT_ENABLE_OPENMP OFF) -#endif() -#set(ENABLE_OPENMP ${DEFAULT_ENABLE_OPENMP} CACHE BOOL "") - if(CMAKE_COMPILER_IS_GNUCXX) set(ENABLE_PROFILING OFF CACHE BOOL "Enable profiling in the GCC compiler (Add flags: -g -pg)") set(USE_OMIT_FRAME_POINTER ON CACHE BOOL "Enable -fomit-frame-pointer for GCC") - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES amd64*|x86_64*) + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES amd64.*|x86_64.*) set(X86_64 1) endif() - - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686*|i386*|x86*) + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686.*|i386.*|x86.*) set(X86 1) endif() - - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES powerpc*) + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES powerpc.*) set(ENABLE_POWERPC ON CACHE BOOL "Enable PowerPC for GCC") endif () if(X86 OR X86_64) # enable everything, since the available set of instructions is checked at runtime - set(USE_FAST_MATH ON CACHE BOOL "Enable -ffast-math") + IF ("${CMAKE_GCC_REGEX_VERSION}" VERSION_GREATER 4.5) + SET(_USE_FAST_MATH OFF) + ELSE() + SET(_USE_FAST_MATH ON) + ENDIF() + set(USE_FAST_MATH ${_USE_FAST_MATH} CACHE BOOL "Enable -ffast-math (not recommended for GCC 4.6.x)") set(ENABLE_SSE ON CACHE BOOL "Enable SSE instructions") set(ENABLE_SSE2 ON CACHE BOOL "Enable SSE2 instructions") set(ENABLE_SSE3 OFF CACHE BOOL "Enable SSE3 instructions") @@ -393,6 +428,7 @@ set(WITH_EIGEN ON CACHE BOOL "Include Eigen2/Eigen3 support") set(WITH_CUDA ON CACHE BOOL "Include NVidia Cuda Runtime support") set(WITH_OPENNI OFF CACHE BOOL "Include OpenNI support") +set(WITH_XIMEA OFF CACHE BOOL "Include XIMEA cameras support") # =================================================== # Macros that checks if module have been installed. @@ -552,10 +588,10 @@ if(UNIX) set(HAVE_CAMV4L2 FALSE) endif() - if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD" AND NOT ANDROID) - set(OPENCV_LINKER_LIBS m pthread) - elseif(ANDROID) + if(ANDROID) set(OPENCV_LINKER_LIBS dl m log) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") + set(OPENCV_LINKER_LIBS m pthread) else() set(OPENCV_LINKER_LIBS dl m pthread rt) endif() @@ -580,6 +616,10 @@ if(WITH_JASPER AND NOT JASPER_FOUND) set(JASPER_LIBRARIES libjasper) endif() +if(NOT ZLIB_FOUND) + set(ZLIB_LIBRARY zlib) +endif() + #message(STATUS "Graphic libraries: ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARIES} ${JASPER_LIBRARIES}") if(WITH_OPENEXR) @@ -599,39 +639,46 @@ if (WIN32) set(BUILD_NEW_PYTHON_SUPPORT OFF) endif() endif() + if(ANDROID) set(BUILD_NEW_PYTHON_SUPPORT OFF) endif() # Always try to find python # =================================================== -find_package(PythonInterp) -find_package(PythonLibs) +find_host_package(PythonInterp) +find_host_package(PythonLibs) # cmake 2.4 (at least on Ubuntu 8.04 (hardy)) don't define PYTHONLIBS_FOUND if(NOT PYTHONLIBS_FOUND AND PYTHON_INCLUDE_PATH) set(PYTHONLIBS_FOUND ON) -endif(NOT PYTHONLIBS_FOUND AND PYTHON_INCLUDE_PATH) +endif() execute_process(COMMAND ${PYTHON_EXECUTABLE} --version ERROR_VARIABLE PYTHON_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) -string(REGEX MATCH "[0-9].[0-9]" PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_FULL}") -if(UNIX) - set(PYTHON_PLUGIN_INSTALL_PATH lib/python${PYTHON_VERSION_MAJOR_MINOR}/site-packages/opencv) - if(APPLE) +string(REGEX MATCH "[0-9]+.[0-9]+" PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_FULL}") +if(CMAKE_HOST_UNIX) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import *; print get_python_lib()" + RESULT_VARIABLE PYTHON_CVPY_PROCESS + OUTPUT_VARIABLE PYTHON_STD_PACKAGES_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + if("${PYTHON_STD_PACKAGES_PATH}" MATCHES "site-packages") set(PYTHON_PACKAGES_PATH lib/python${PYTHON_VERSION_MAJOR_MINOR}/site-packages CACHE PATH "Where to install the python packages.") else() #debian based assumed, install to the dist-packages. - set(PYTHON_PACKAGES_PATH lib/python${PYTHON_VERSION_MAJOR_MINOR}/dist-packages CACHE PATH "Where to install the python packages.") + set(PYTHON_PACKAGES_PATH lib/python${PYTHON_VERSION_MAJOR_MINOR}/dist-packages CACHE PATH "Where to install the python packages.") endif() endif() -if(WIN32) +if(CMAKE_HOST_WIN32) get_filename_component(PYTHON_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${PYTHON_VERSION_MAJOR_MINOR}\\InstallPath]" ABSOLUTE CACHE) - set(PYTHON_PLUGIN_INSTALL_PATH "${PYTHON_PATH}/Lib/site-packages/opencv") set(PYTHON_PACKAGES_PATH "${PYTHON_PATH}/Lib/site-packages") endif() +IF ("${PYTHON_VERSION_MAJOR_MINOR}" VERSION_GREATER 2.4) + SET(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} -B) +ENDIF() + # Attempt to discover the NumPy include directory. If this succeeds, then build python API with NumPy execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import os; os.environ['DISTUTILS_USE_SDK']='1'; import numpy.distutils; print numpy.distutils.misc_util.get_numpy_include_dirs()[0]" RESULT_VARIABLE PYTHON_NUMPY_PROCESS @@ -654,13 +701,137 @@ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import sphinx; print sphinx.__v set(HAVE_SPHINX 0) if(SPHINX_PROCESS EQUAL 0) - find_program(SPHINX_BUILD sphinx-build) + find_host_program(SPHINX_BUILD sphinx-build) if(SPHINX_BUILD) set(HAVE_SPHINX 1) message(STATUS " Found Sphinx ${SPHINX_VERSION}: ${SPHINX_BUILD}") endif() endif() +# Java support +# =================================================== +if (PYTHON_EXECUTABLE AND ANDROID AND ANDROID_API_LEVEL GREATER 7) + option(BUILD_JAVA_SUPPORT "Build with Java support" TRUE) +endif() + +if (BUILD_JAVA_SUPPORT) + file(TO_CMAKE_PATH "$ENV{ANT_DIR}" ANT_DIR_ENV_PATH) + file(TO_CMAKE_PATH "$ENV{ProgramFiles}" ProgramFiles_ENV_PATH) + + if(ANDROID) + file(TO_CMAKE_PATH "$ENV{ANDROID_SDK}" ANDROID_SDK_ENV_PATH) + + #find android SDK + find_host_program(ANDROID_EXECUTABLE + NAMES android.bat android + PATHS "${ANDROID_SDK_ENV_PATH}/tools/" + "${ProgramFiles_ENV_PATH}/Android/android-sdk/tools/" + "/opt/android-sdk/tools/" + "/opt/android-sdk-linux_x86/tools/" + "/opt/android-sdk-mac_x86/tools/" + "/opt/android-sdk-linux_86/tools/" + "/opt/android-sdk-mac_86/tools/" + ) + if(ANDROID_EXECUTABLE) + message(STATUS " Found android tool: ${ANDROID_EXECUTABLE}") + + get_filename_component(ANDROID_SDK_TOOLS_PATH "${ANDROID_EXECUTABLE}" PATH) + + #read source.properties + if (EXISTS "${ANDROID_SDK_TOOLS_PATH}/source.properties") + file(STRINGS "${ANDROID_SDK_TOOLS_PATH}/source.properties" ANDROID_SDK_TOOLS_SOURCE_PROPERTIES_LINES REGEX "^[ ]*[^#].*$") + foreach(line ${ANDROID_SDK_TOOLS_SOURCE_PROPERTIES_LINES}) + string(REPLACE "\\:" ":" line ${line}) + string(REPLACE "=" ";" line ${line}) + list(GET line 0 line_name) + list(GET line 1 line_value) + string(REPLACE "." "_" line_name ${line_name}) + SET(ANDROID_TOOLS_${line_name} "${line_value}") + MARK_AS_ADVANCED(ANDROID_TOOLS_${line_name}) + endforeach() + endif() + if (NOT ANDROID_TOOLS_Pkg_Revision) + SET(ANDROID_TOOLS_Pkg_Revision "Unknown") + MARK_AS_ADVANCED(ANDROID_TOOLS_Pkg_Revision) + endif() + if (NOT ANDROID_TOOLS_Pkg_Desc) + SET(ANDROID_TOOLS_Pkg_Desc "Android SDK Tools, revision ${ANDROID_TOOLS_Pkg_Revision}.") + if (NOT ANDROID_TOOLS_Pkg_Revision GREATER 11) + SET(ANDROID_TOOLS_Pkg_Desc "${ANDROID_TOOLS_Pkg_Desc} It is recommended to update your SDK tools to revision 12 or newer.") + endif() + MARK_AS_ADVANCED(ANDROID_TOOLS_Pkg_Desc) + endif() + + #get installed targets + execute_process(COMMAND ${ANDROID_EXECUTABLE} list target + RESULT_VARIABLE ANDROID_PROCESS + OUTPUT_VARIABLE ANDROID_SDK_TARGETS_FULL + ERROR_VARIABLE ANDROID_PROCESS_ERRORS + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCHALL "(^|\n)id: [0-9]+ or \"([^\n]+[0-9+])\"(\n|$)" ANDROID_SDK_TARGETS_FULL "${ANDROID_SDK_TARGETS_FULL}") + + SET(ANDROID_SDK_TARGETS) + if (ANDROID_PROCESS EQUAL 0) + foreach(line ${ANDROID_SDK_TARGETS_FULL}) + string(REGEX REPLACE "(^|\n)id: [0-9]+ or \"([^\n]+[0-9+])\"(\n|$)" "\\2" line "${line}") + list(APPEND ANDROID_SDK_TARGETS "${line}") + endforeach() + endif() + + # detect ANDROID_SDK_TARGET if no target is provided by user + if (NOT ANDROID_SDK_TARGET) + set(desired_android_target_level ${ANDROID_API_LEVEL}) + if (desired_android_target_level LESS 8) + set(desired_android_target_level 8) + endif() + if (ANDROID_PROCESS EQUAL 0) + math(EXPR desired_android_target_level_1 "${desired_android_target_level}-1") + + foreach(target ${ANDROID_SDK_TARGETS}) + string(REGEX MATCH "[0-9]+$" target_level "${target}") + if (target_level GREATER desired_android_target_level_1) + set(ANDROID_SDK_TARGET "${target}") + break() + endif() + endforeach() + else() + set(ANDROID_SDK_TARGET android-${desired_android_target_level}) + message(WARNING "Could not retrieve list of installed Android targets. Will try to use \"${ANDROID_SDK_TARGET}\" target") + endif() + endif() + + SET(ANDROID_SDK_TARGET ${ANDROID_SDK_TARGET} CACHE STRING "SDK target for Android tests and samples") + if (ANDROID_PROCESS EQUAL 0) + set_property( CACHE ANDROID_SDK_TARGET PROPERTY STRINGS ${ANDROID_SDK_TARGETS} ) + endif() + string(REGEX MATCH "[0-9]+$" ANDROID_SDK_TARGET_LEVEL "${ANDROID_SDK_TARGET}") + endif() + endif() + + #find apache ant + find_host_program(ANT_EXECUTABLE NAMES ant.bat ant + PATHS "${ANT_DIR_ENV_PATH}/bin" + "${ProgramFiles_ENV_PATH}/apache-ant/bin" + ) + if(ANT_EXECUTABLE) + execute_process(COMMAND ${ANT_EXECUTABLE} -version + OUTPUT_VARIABLE ANT_VERSION_FULL + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" ANT_VERSION "${ANT_VERSION_FULL}") + + message(STATUS " Found apache ant ${ANT_VERSION}: ${ANT_EXECUTABLE}") + endif() + + if (ANDROID_EXECUTABLE AND ANT_EXECUTABLE AND (ANT_VERSION VERSION_GREATER 1.7) AND (ANDROID_SDK_TARGET_LEVEL GREATER 7)) + SET(CAN_BUILD_ANDROID_PROJECTS TRUE) + else() + SET(CAN_BUILD_ANDROID_PROJECTS FALSE) + endif() +endif() + +if(CAN_BUILD_ANDROID_PROJECTS) + SET(BUILD_ANDROID_EXAMPLES TRUE CACHE BOOL "Build examples for Android platform") +endif() #YV ############################### QT ################################ @@ -675,22 +846,19 @@ if (WITH_QT) find_package(Qt4) if (QT4_FOUND) set(HAVE_QT 1) - add_definitions(-DHAVE_QT)#We need to define te macro this way, using cvconfig.h.cmake does not work - + add_definitions(-DHAVE_QT)#We need to define te macro this way, using cvconfig.h.cmake does not work find_package (OpenGL QUIET) - - #if (NOT WIN32) - if (WITH_QT_OPENGL) - if (QT_QTOPENGL_FOUND AND OPENGL_FOUND) - set(HAVE_QT_OPENGL 1) - add_definitions(-DHAVE_QT_OPENGL) - #link_directories("${OPENGL_LIBRARIES}") - set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${OPENGL_LIBRARIES}) + #if (NOT WIN32) + if (WITH_QT_OPENGL) + if (QT_QTOPENGL_FOUND AND OPENGL_FOUND) + set(HAVE_QT_OPENGL 1) + add_definitions(-DHAVE_QT_OPENGL) + #link_directories("${OPENGL_LIBRARIES}") + set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${OPENGL_LIBRARIES}) + endif() endif() - endif() - #endif() - + #endif() endif() endif() @@ -699,7 +867,6 @@ endif() if (WITH_TBB) if (UNIX AND NOT APPLE AND NOT ANDROID) PKG_CHECK_MODULES(TBB tbb) - message(STATUS "TBB detected: ${TBBLIB_FOUND}") if (TBB_FOUND) set(HAVE_TBB 1) @@ -859,10 +1026,21 @@ if(WITH_OPENNI) include(OpenCVFindOpenNI.cmake) endif() +############################### XIMEA ################################ +set(HAVE_XIMEA FALSE) + +if(WITH_XIMEA) + include(OpenCVFindXimea.cmake) +endif() + +if(XIMEA_FOUND) + set(HAVE_XIMEA TRUE) +endif() + ############################## Eigen ############################## if(WITH_EIGEN) - find_path(EIGEN_INCLUDE_PATH "Eigen/Core" + find_path(EIGEN_INCLUDE_PATH "Eigen/Core" PATHS "/usr/local/include/eigen2" "/opt/include/eigen2" "/usr/include/eigen2" "/usr/local/include/eigen3" "/opt/include/eigen3" "/usr/include/eigen3" DOC "The path to Eigen2/Eigen3 headers") @@ -877,7 +1055,6 @@ endif() if(WIN32) set(WITH_VIDEOINPUT ON CACHE BOOL "Build HighGUI with DirectShow support") - set(HIGHGUI_LIBRARIES ${HIGHGUI_LIBRARIES} comctl32 gdi32 ole32) if(WITH_VIDEOINPUT) @@ -897,9 +1074,10 @@ if(WIN32) endif() endif() - ############## Android source tree for native camera ############### -if(ANDROID) +if(ANDROID AND ANDROID_API_LEVEL GREATER 7) + option(WITH_ANDROID_CAMERA "Build with native Android camera support" TRUE) + SET (ANDROID_SOURCE_TREE "ANDROID_SOURCE_TREE-NOTFOUND" CACHE PATH "Path to Android source tree. Set this variable to path to your Android sources to compile @@ -912,27 +1090,18 @@ libnative_camera_rx.x.x.so for your Android") SET(BUILD_ANDROID_CAMERA_WRAPPER ON) endif() endif() + MARK_AS_ADVANCED(ANDROID_SOURCE_TREE) endif() - -################### DOXYGEN ############### - -#find_package(Doxygen) -# -#if(DOXYGEN_FOUND) -# set(BUILD_DOXYGEN_DOCS ON CACHE BOOL "Generate HTML docs using Doxygen") -#endif() - - # ---------------------------------------------------------------------------- # UPDATE CONFIG FILES & SCRIPTS: # # CONFIGURE_FILE(InputFile OutputFile [COPYONLY] [ESCAPE_QUOTES] [@ONLY]) -# If @ONLY is specified, only variables of the form @VAR@ will be +# If @ONLY is specified, only variables of the form @VAR@ will be # replaces and ${VAR} will be ignored. # # A directory will be created for each platform so the "cvconfig.h" file is -# not overwritten if cmake generates code in the same path. +# not overwritten if cmake generates code in the same path. # ---------------------------------------------------------------------------- add_definitions(-DHAVE_CVCONFIG_H) @@ -941,7 +1110,6 @@ set(OPENCV_CONFIG_FILE_INCLUDE_DIR "${CMAKE_BINARY_DIR}/" CACHE PATH "Where to c message(STATUS "Parsing 'cvconfig.h.cmake'") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cvconfig.h.cmake" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/cvconfig.h") - # --------------------------------------------------------------------------- # The C+//0 include & link directories: # --------------------------------------------------------------------------- @@ -951,12 +1119,14 @@ include_directories("." "${CMAKE_CURRENT_SOURCE_DIR}/include/opencv" ) - # ---------------------------------------------------------------------------- # Set the maximum level of warnings: # ---------------------------------------------------------------------------- # Should be set to true for development set(OPENCV_WARNINGS_ARE_ERRORS OFF CACHE BOOL "Treat warnings as errors") +if (WIN32 AND ${CMAKE_GENERATOR} MATCHES "(MinGW)|(MSYS)") + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG" CACHE STRING "") +endif() set(EXTRA_C_FLAGS "") set(EXTRA_C_FLAGS_RELEASE "") @@ -970,7 +1140,6 @@ if(MSVC) # 64-bit portability warnings, in MSVC8 if(MSVC80) set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} /Wp64") - endif() #if(MSVC90) # set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} /D _BIND_TO_CURRENT_CRT_VERSION=1 /D _BIND_TO_CURRENT_VCLIBS_VERSION=1") @@ -980,10 +1149,6 @@ if(MSVC) set(EXTRA_EXE_LINKER_FLAGS_RELEASE "${EXTRA_EXE_LINKER_FLAGS_RELEASE} /debug") endif() - #if(ENABLE_OPENMP) - # set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} /openmp") - #endif() - # Remove unreferenced functions: function level linking set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} /Gy") if(BUILD_WITH_DEBUG_INFO) @@ -992,41 +1157,25 @@ if(MSVC) endif() if(CMAKE_COMPILER_IS_GNUCXX) - # High level of warnings. set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Wall") - if(BUILD_WITH_STATIC_CRT) - set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -static-libstdc++") - endif() - # The -Wno-long-long is required in 64bit systems when including sytem headers. - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64*) - set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Wno-long-long") - endif() - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES amd64*) - set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Wno-long-long") + if(X86_64) + set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Wno-long-long") endif() # We need pthread's - if(UNIX) - if(NOT ANDROID) + if(UNIX AND NOT ANDROID) set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -pthread") - endif() endif() if(OPENCV_WARNINGS_ARE_ERRORS) set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Werror") endif() - if(X86) - if(NOT MINGW64) - if(NOT X86_64) - if(NOT APPLE) - set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -march=i686") - endif() - endif() - endif() + if(X86 AND NOT MINGW64 AND NOT X86_64 AND NOT APPLE) + set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -march=i686") endif() # Other optimizations @@ -1058,11 +1207,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(HAVE_GCC42_OR_NEWER 1) endif() - if(HAVE_GCC43_OR_NEWER OR APPLE) + if(HAVE_GCC42_OR_NEWER OR APPLE) if(ENABLE_SSSE3) set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -mssse3") endif() - if(HAVE_GCC42_OR_NEWER) + if(HAVE_GCC43_OR_NEWER) if(ENABLE_SSE41) set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -msse4.1") endif() @@ -1074,32 +1223,21 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() if(X86 OR X86_64) - if(NOT APPLE) - if(${CMAKE_SIZEOF_VOID_P} EQUAL 4) - set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -mfpmath=387") - endif() + if(NOT APPLE AND ${CMAKE_SIZEOF_VOID_P} EQUAL 4) + set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -mfpmath=387") endif() endif() # Profiling? if(ENABLE_PROFILING) set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -pg -g") - else() + elseif(NOT APPLE) # Remove unreferenced functions: function level linking - if(NOT APPLE) - set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -ffunction-sections") - endif() + set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -ffunction-sections") endif() - # Parallel mode - #if(ENABLE_OPENMP) - # set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -D_GLIBCXX_PARALLEL -fopenmp") - # set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} gomp) - #endif() - set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -DNDEBUG") set(EXTRA_C_FLAGS_DEBUG "${EXTRA_C_FLAGS_DEBUG} -O0 -DDEBUG -D_DEBUG") - if(BUILD_WITH_DEBUG_INFO) set(EXTRA_C_FLAGS_DEBUG "${EXTRA_C_FLAGS_DEBUG} -ggdb3") endif() @@ -1127,23 +1265,22 @@ if(MSVC) endif() # Extra link libs if the user selects building static libs: -if(NOT BUILD_SHARED_LIBS) - if(CMAKE_COMPILER_IS_GNUCXX) - set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} stdc++) - set(OPENCV_EXTRA_C_FLAGS "${OPENCV_EXTRA_C_FLAGS} -fPIC") - endif() +if(NOT BUILD_SHARED_LIBS AND CMAKE_COMPILER_IS_GNUCXX AND NOT ANDROID) + # Android does not need these settings because they are already set by toolchain file + set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} stdc++) + set(OPENCV_EXTRA_C_FLAGS "-fPIC ${OPENCV_EXTRA_C_FLAGS}") endif() - # Add user supplied extra options (optimization, etc...) # ========================================================== -set(OPENCV_EXTRA_C_FLAGS "" CACHE STRING "Extra compiler options") -set(OPENCV_EXTRA_C_FLAGS_RELEASE "" CACHE STRING "Extra compiler options for Release build") -set(OPENCV_EXTRA_C_FLAGS_DEBUG "" CACHE STRING "Extra compiler options for Debug build") -set(OPENCV_EXTRA_EXE_LINKER_FLAGS "" CACHE STRING "Extra linker flags" FORCE) -set(OPENCV_EXTRA_EXE_LINKER_FLAGS_RELEASE "" CACHE STRING "Extra linker flags for Release build" FORCE) -set(OPENCV_EXTRA_EXE_LINKER_FLAGS_DEBUG "" CACHE STRING "Extra linker flags for Debug build" FORCE) +set(OPENCV_EXTRA_C_FLAGS "${OPENCV_EXTRA_C_FLAGS}" CACHE STRING "Extra compiler options") +set(OPENCV_EXTRA_C_FLAGS_RELEASE "${OPENCV_EXTRA_C_FLAGS_RELEASE}" CACHE STRING "Extra compiler options for Release build") +set(OPENCV_EXTRA_C_FLAGS_DEBUG "${OPENCV_EXTRA_C_FLAGS_DEBUG}" CACHE STRING "Extra compiler options for Debug build") +set(OPENCV_EXTRA_EXE_LINKER_FLAGS "${OPENCV_EXTRA_EXE_LINKER_FLAGS}" CACHE STRING "Extra linker flags" FORCE) +set(OPENCV_EXTRA_EXE_LINKER_FLAGS_RELEASE "${OPENCV_EXTRA_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING "Extra linker flags for Release build" FORCE) +set(OPENCV_EXTRA_EXE_LINKER_FLAGS_DEBUG "${OPENCV_EXTRA_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING "Extra linker flags for Debug build" FORCE) +#combine all "extra" options set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_C_FLAGS} ${OPENCV_EXTRA_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_FLAGS} ${OPENCV_EXTRA_C_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${EXTRA_C_FLAGS_RELEASE} ${OPENCV_EXTRA_C_FLAGS_RELEASE}") @@ -1155,10 +1292,8 @@ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${EXTRA_EX set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${EXTRA_EXE_LINKER_FLAGS_DEBUG} ${OPENCV_EXTRA_EXE_LINKER_FLAGS_DEBUG}") # In case of Makefiles if the user does not setup CMAKE_BUILD_TYPE, assume it's Release: -if (${CMAKE_GENERATOR} MATCHES ".*Makefiles") - if("${CMAKE_BUILD_TYPE}" STREQUAL "") - set(CMAKE_BUILD_TYPE Release) - endif() +if (${CMAKE_GENERATOR} MATCHES ".*Makefiles" AND "${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE Release) endif() if (WIN32 AND MSVC) @@ -1178,31 +1313,16 @@ if (WIN32 AND MSVC) string(REPLACE "/EHsc" "/EHsc-" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "/EHsc" "/EHsc-" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - string(REPLACE "/Zm1000" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "/Zm1000" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") endif() if("${CMAKE_CONFIGURE_LDFLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_CONFIGURE_LDFLAGS}") endif("${CMAKE_CONFIGURE_LDFLAGS}") - -# ---------------------------------------------------------------------------- -# PROCESS SUBDIRECTORIES: -# ---------------------------------------------------------------------------- -# Save libs and executables in the same place -set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib CACHE PATH "Output directory for libraries" ) -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin CACHE PATH "Output directory for applications" ) - -if(WIN32) -set(OPENCV_DOC_INSTALL_PATH doc) -else() -set(OPENCV_DOC_INSTALL_PATH share/opencv/doc) -endif() - - # -------------------------------------------------------------------------------------------- -# Installation for CMake Module: OpenCVConfig.cmake +# Installation for CMake Module: OpenCVConfig.cmake # Part 1/3: ${BIN_DIR}/OpenCVConfig.cmake -> For use *without* "make install" # Part 2/3: ${BIN_DIR}/unix-install/OpenCVConfig.cmake -> For use with "make install" # Part 3/3: ${BIN_DIR}/win-install/OpenCVConfig.cmake -> For use within binary installers/packages @@ -1211,65 +1331,68 @@ endif() # ------------------------------------------------------------------------------------------- # Part 1/3: ${BIN_DIR}/OpenCVConfig.cmake -> For use *without* "make install" # ------------------------------------------------------------------------------------------- - -# Name of libraries is: libcv.so.1.1.0, etc... -# OPENCV_DLLVERSION must be set to "110", etc.. -# Already done above. - -# Set CMAKE_INCLUDE_DIRS_CONFIGCMAKE to the list of include directories: set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"${OPENCV_CONFIG_FILE_INCLUDE_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}/include\" \"${CMAKE_CURRENT_SOURCE_DIR}/include/opencv\"") -set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "\"${CMAKE_CURRENT_SOURCE_DIR}\"") - +set(CMAKE_OPENCV2_INCLUDE_DIRS_CONFIGCMAKE "${CMAKE_CURRENT_SOURCE_DIR}") set(CMAKE_LIB_DIRS_CONFIGCMAKE "${LIBRARY_OUTPUT_PATH}") +set(CMAKE_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"${CMAKE_BINARY_DIR}/3rdparty/${OPENCV_LIB_INSTALL_PATH}\"") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" IMMEDIATE @ONLY) - +#support for version checking when finding opencv. find_package(OpenCV 2.3.1 EXACT) should now work. +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig-version.cmake" IMMEDIATE @ONLY) # -------------------------------------------------------------------------------------------- # Part 2/3: ${BIN_DIR}/unix-install/OpenCVConfig.cmake -> For use *with* "make install" # ------------------------------------------------------------------------------------------- -# Set CMAKE_INCLUDE_DIRS_CONFIGCMAKE to the list of include directories: +set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_PREFIX}/opencv" "\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_PREFIX}\"") -set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"\${THIS_OPENCV_CONFIG_PATH}/../../include/opencv" "\${THIS_OPENCV_CONFIG_PATH}/../../include\"") -set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "\"\"") +set(CMAKE_OPENCV2_INCLUDE_DIRS_CONFIGCMAKE "") +if(ANDROID) + set(CMAKE_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/libs/\${ARMEABI_NDK_NAME}\"") + set(CMAKE_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/share/OpenCV/3rdparty/libs/\${ARMEABI_NDK_NAME}\"") +else() + set(CMAKE_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_LIB_INSTALL_PATH}\"") + set(CMAKE_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH}\"") + if(OPENCV_MANGLED_INSTALL_PATHS) + set(CMAKE_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/share/OpenCV-${OPENCV_VERSION}/3rdparty/${OPENCV_LIB_INSTALL_PATH}\"") + endif() +endif() -set(CMAKE_LIB_DIRS_CONFIGCMAKE "\"\${THIS_OPENCV_CONFIG_PATH}/../../lib\"") - -exec_program(mkdir ARGS "-p \"${CMAKE_BINARY_DIR}/unix-install/\"" OUTPUT_VARIABLE RET_VAL) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake" IMMEDIATE @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake" IMMEDIATE @ONLY) if(UNIX) - # For a command "FIND_PACKAGE(FOO)", CMake will look at the directory /usr/share|lib/cmake/FOO/FOOConfig.cmake, so: - install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake DESTINATION share/opencv/) - install(CODE "exec_program(ln ARGS -sf \"${CMAKE_INSTALL_PREFIX}/share/opencv\" \"${CMAKE_INSTALL_PREFIX}/share/OpenCV\")") + #http://www.vtk.org/Wiki/CMake/Tutorials/Packaging reference + # For a command "find_package( [major[.minor]] [EXACT] [REQUIRED|QUIET])" + # cmake will look in the following dir on unix: + # /(share|lib)/cmake/*/ (U) + # /(share|lib)/*/ (U) + # /(share|lib)/*/(cmake|CMake)/ (U) + if(OPENCV_MANGLED_INSTALL_PATHS) + install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake DESTINATION share/OpenCV-${OPENCV_VERSION}/) + install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake DESTINATION share/OpenCV-${OPENCV_VERSION}/) + else() + install(FILES "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake" DESTINATION share/OpenCV/) + install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake DESTINATION share/OpenCV/) + endif() +endif() + +if(ANDROID) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/android/android.toolchain.cmake" DESTINATION share/OpenCV) endif() # -------------------------------------------------------------------------------------------- # Part 3/3: ${BIN_DIR}/win-install/OpenCVConfig.cmake -> For use within binary installers/packages # ------------------------------------------------------------------------------------------- if(WIN32) - # Set CMAKE_INCLUDE_DIRS_CONFIGCMAKE to the list of include directories: - # support for 3rdparty libraries. - # This will expand to, for example, /OpenCV 1.1.0/include - set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"\${THIS_OPENCV_CONFIG_PATH}/include\" - \"\${THIS_OPENCV_CONFIG_PATH}/include/opencv\" - \"\${THIS_OPENCV_CONFIG_PATH}/3rdparty/include\"") + set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_CONFIG_PATH}/include\" \"\${OpenCV_CONFIG_PATH}/include/opencv\"") + set(CMAKE_OPENCV2_INCLUDE_DIRS_CONFIGCMAKE "") + set(CMAKE_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_CONFIG_PATH}/${OPENCV_LIB_INSTALL_PATH}\"") + set(CMAKE_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_CONFIG_PATH}/share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH}\"") - set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "\"\${THIS_OPENCV_CONFIG_PATH}\"") - - # This will expand to, for example, /OpenCV 1.1.0/lib - # support for 3rdparty libraries. - set(CMAKE_LIB_DIRS_CONFIGCMAKE "\"\${THIS_OPENCV_CONFIG_PATH}/lib\" - \"\${THIS_OPENCV_CONFIG_PATH}/3rdparty/lib\"") - - #exec_program(${CMAKE_COMMAND} ARGS "-E make_directory \"${CMAKE_BINARY_DIR}/win-install/\"") exec_program(mkdir ARGS "-p \"${CMAKE_BINARY_DIR}/win-install/\"" OUTPUT_VARIABLE RET_VAL) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" IMMEDIATE @ONLY) + # Install the OpenCVConfig.cmake file which has the right paths pointing to the install directory install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/") - - # Add the OpenCV configuration header to the install path - # Useful for instance if a client application checks against the features OpenCV has been compiled with - install(FILES "${CMAKE_BINARY_DIR}/cvconfig.h" DESTINATION "${CMAKE_INSTALL_PREFIX}/include") endif() # -------------------------------------------------------------------------------------------- @@ -1283,27 +1406,27 @@ if(ANDROID) else() SET(OPENCV_LIBTYPE_CONFIGMAKE "STATIC") endif() - if(ARMEABI_V7A) - if(BUILD_ANDROID_CAMERA_WRAPPER) - set(CMAKE_CAMERA_LIBS_CONFIGCMAKE "native_camera_r${ANDROID_VERSION}") - else() - SET(CMAKE_CAMERA_LIBS_CONFIGCMAKE "") - file(GLOB CMAKE_CAMERA_LIBS "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/lib/libnative_camera_r*.so") - foreach(cam_lib ${CMAKE_CAMERA_LIBS}) - get_filename_component(cam_lib "${cam_lib}" NAME) - string(REGEX REPLACE "lib(native_camera_r[0-9]+\\.[0-9]+\\.[0-9]+)\\.so" "\\1" cam_lib "${cam_lib}") - SET(CMAKE_CAMERA_LIBS_CONFIGCMAKE "${CMAKE_CAMERA_LIBS_CONFIGCMAKE} ${cam_lib}") - endforeach() - endif() + if(BUILD_ANDROID_CAMERA_WRAPPER) + set(CMAKE_CAMERA_LIBS_CONFIGCMAKE "native_camera_r${ANDROID_VERSION}") + elseif(WITH_ANDROID_CAMERA) + SET(CMAKE_CAMERA_LIBS_CONFIGCMAKE "") + file(GLOB CMAKE_CAMERA_LIBS "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/lib/${ARMEABI_NDK_NAME}/libnative_camera_r*.so") + foreach(cam_lib ${CMAKE_CAMERA_LIBS}) + get_filename_component(cam_lib "${cam_lib}" NAME) + string(REGEX REPLACE "lib(native_camera_r[0-9]+\\.[0-9]+\\.[0-9]+)\\.so" "\\1" cam_lib "${cam_lib}") + SET(CMAKE_CAMERA_LIBS_CONFIGCMAKE "${CMAKE_CAMERA_LIBS_CONFIGCMAKE} ${cam_lib}") + endforeach() endif() endif(ANDROID) + # ------------------------------------------------------------------------------------------- # Part 1/2: ${BIN_DIR}/OpenCV.mk -> For use *without* "make install" # ------------------------------------------------------------------------------------------- if(ANDROID) - set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"\$(RELATIVE_PREFIX)${OPENCV_CONFIG_FILE_INCLUDE_DIR}\" \"\$(RELATIVE_PREFIX)${CMAKE_CURRENT_SOURCE_DIR}/include\" \"\$(RELATIVE_PREFIX)${CMAKE_CURRENT_SOURCE_DIR}/include/opencv\"") - set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "\"\$(RELATIVE_PREFIX)${CMAKE_CURRENT_SOURCE_DIR}\"") - set(CMAKE_LIB_DIRS_CONFIGCMAKE "\$(RELATIVE_PREFIX)${LIBRARY_OUTPUT_PATH}") + set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"${OPENCV_CONFIG_FILE_INCLUDE_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}/include\" \"${CMAKE_CURRENT_SOURCE_DIR}/include/opencv\"") + set(CMAKE_BASE_INCLUDE_DIR_CONFIGCMAKE "\"${CMAKE_CURRENT_SOURCE_DIR}\"") + set(CMAKE_LIBS_DIR_CONFIGCMAKE "\$(OPENCV_THIS_DIR)") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCV.mk.in" "${CMAKE_BINARY_DIR}/OpenCV.mk" IMMEDIATE @ONLY) endif(ANDROID) @@ -1311,14 +1434,21 @@ endif(ANDROID) # Part 2/2: ${BIN_DIR}/unix-install/OpenCV.mk -> For use with "make install" # ------------------------------------------------------------------------------------------- if(ANDROID) - set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/../../include/opencv \$(OPENCV_THIS_DIR)/../../include") - set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "") - set(CMAKE_LIB_DIRS_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/../../lib") + set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"\$(LOCAL_PATH)/\$(OPENCV_THIS_DIR)/../../include/opencv\" \"\$(LOCAL_PATH)/\$(OPENCV_THIS_DIR)/../../include\"") + set(CMAKE_BASE_INCLUDE_DIR_CONFIGCMAKE "") + set(CMAKE_LIBS_DIR_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/../..") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCV.mk.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCV.mk" IMMEDIATE @ONLY) - install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCV.mk DESTINATION share/opencv/) + install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCV.mk DESTINATION share/OpenCV/) endif(ANDROID) # -------------------------------------------------------------------------------------------- +#according to man pkg-config +# The package name specified on the pkg-config command line is defined to +# be the name of the metadata file, minus the .pc extension. If a library +# can install multiple versions simultaneously, it must give each version +# its own name (for example, GTK 1.2 might have the package name "gtk+" +# while GTK 2.0 has "gtk+-2.0"). # Part 2/2: ${BIN_DIR}/unix-install/opencv.pc -> For use *with* "make install" # prefix=/usr # exec_prefix=${prefix} @@ -1326,17 +1456,30 @@ endif(ANDROID) # includedir=${prefix}/include/opencv # ------------------------------------------------------------------------------------------- set(prefix ${CMAKE_INSTALL_PREFIX}) -set(exec_prefix "\${prefix}") -set(libdir "\${exec_prefix}/lib") -set(includedir "\${prefix}/include") -set(VERSION ${OPENCV_VERSION}) +set(exec_prefix "\${prefix}") +set(libdir "\${exec_prefix}/lib${LIB_SUFFIX}") +set(includedir "\${prefix}/${OPENCV_INCLUDE_PREFIX}") +set(VERSION ${OPENCV_VERSION}) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/opencv.pc.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/opencv.pc" @ONLY IMMEDIATE) - -if(UNIX) - install(FILES ${CMAKE_BINARY_DIR}/unix-install/opencv.pc DESTINATION lib/pkgconfig) +set(OPENCV_PC_FILE_NAME opencv.pc) +#need to be explicit with naming the pc file and version number for side by side installs to work. +if(OPENCV_MANGLED_INSTALL_PATHS) + SET(OpenCV_LIB_COMPONENTS opencv_contrib opencv_legacy opencv_objdetect opencv_calib3d opencv_features2d opencv_video opencv_highgui opencv_ml opencv_imgproc opencv_flann opencv_core ) + #be explicit about the library names. + set(OpenCV_LIB_COMPONENTS_ ) + foreach( CVLib ${OpenCV_LIB_COMPONENTS}) + set(OpenCV_LIB_COMPONENTS_ "${OpenCV_LIB_COMPONENTS_} ${libdir}/lib${CVLib}.so.${OPENCV_VERSION}" ) + endforeach() + set(OpenCV_LIB_COMPONENTS ${OpenCV_LIB_COMPONENTS_}) + set(OPENCV_PC_FILE_NAME "opencv-${OPENCV_VERSION}.pc") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/opencv-XXX.pc.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/${OPENCV_PC_FILE_NAME}" @ONLY IMMEDIATE) +else() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/opencv.pc.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/${OPENCV_PC_FILE_NAME}" @ONLY IMMEDIATE) endif() +if(UNIX AND NOT ANDROID) + install(FILES ${CMAKE_BINARY_DIR}/unix-install/${OPENCV_PC_FILE_NAME} DESTINATION ${OPENCV_LIB_INSTALL_PATH}/pkgconfig) +endif() # ---------------------------------------------------------------------------- # Uninstall target, for "make uninstall" @@ -1346,62 +1489,24 @@ CONFIGURE_FILE( "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) -ADD_CUSTOM_TARGET(uninstall - "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") - - -# ---------------------------------------------------------------------------- -# CPack target -# ---------------------------------------------------------------------------- +ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") +#----------------------------------- +# Source package: +#----------------------------------- set(BUILD_PACKAGE ON CACHE BOOL "Enables 'make package_source' command") if(BUILD_PACKAGE) - - configure_file( - Package.cmake.in - ${CMAKE_BINARY_DIR}/.cpack/Package.cmake - @ONLY - ) - - include(${CMAKE_BINARY_DIR}/.cpack/Package.cmake) - - set(root_files README) - - file(GLOB root_src_files *.in *.cmake CMakeLists.txt) - + set(TARBALL_NAME "${CMAKE_PROJECT_NAME}-${OPENCV_VERSION_MAJOR}.${OPENCV_VERSION_MINOR}.${OPENCV_VERSION_PATCH}") if (NOT WIN32) - install(FILES ${root_files} - DESTINATION ${OPENCV_DOC_INSTALL_PATH} - COMPONENT main) + add_custom_target(package_source + #TODO: maybe we should not remove dll's + COMMAND tar --transform 's,^,${TARBALL_NAME}/,S' -cjpf ${CMAKE_CURRENT_BINARY_DIR}/${TARBALL_NAME}.tar.bz2 --exclude-vcs --exclude="*.pyc" --exclude="*.vcproj" --exclude="*/lib/*" --exclude="*.dll" ./ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) else() - install(FILES ${root_files} - DESTINATION "." - COMPONENT main) - install(FILES ${root_src_files} - DESTINATION "." - COMPONENT src) - # Add the "win-install/OpenCVConfig.cmake" file to the "main" install component - install(FILES - "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" - DESTINATION "." - COMPONENT main - ) - install(FILES - "include/CMakeLists.txt" - DESTINATION "include/" - COMPONENT src - ) - - install(DIRECTORY data samples DESTINATION "." COMPONENT main PATTERN ".svn" EXCLUDE) - install(DIRECTORY 3rdparty android modules doc DESTINATION "." COMPONENT src PATTERN ".svn" EXCLUDE) - - # install TBB dlls - if(WIN32 AND HAVE_TBB) - string(REGEX REPLACE "/lib" "/bin" TBB_DLL_DIR "${TBB_LIB_DIR}") - install(PROGRAMS "${TBB_DLL_DIR}/tbb.dll" DESTINATION bin COMPONENT main) - install(PROGRAMS "${TBB_DLL_DIR}/tbb_debug.dll" DESTINATION bin COMPONENT main) - endif() + add_custom_target(package_source + COMMAND zip -9 -r ${CMAKE_CURRENT_BINARY_DIR}/${TARBALL_NAME}.zip . -x '*/.svn/*' '*.vcproj' '*.pyc' + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif() endif() @@ -1426,217 +1531,220 @@ add_subdirectory(include) add_subdirectory(modules) add_subdirectory(doc) add_subdirectory(data) - -if(BUILD_EXAMPLES OR INSTALL_PYTHON_EXAMPLES) - add_subdirectory(samples) -endif() - add_subdirectory(3rdparty) +if(BUILD_EXAMPLES OR BUILD_ANDROID_EXAMPLES OR INSTALL_PYTHON_EXAMPLES) + add_subdirectory(samples) +endif() # ---------------------------------------------------------------------------- # Summary: # ---------------------------------------------------------------------------- -message(STATUS "") -message(STATUS "General configuration for opencv ${OPENCV_VERSION} =====================================") -message(STATUS "") -message(STATUS " Built as dynamic libs?: ${BUILD_SHARED_LIBS}") -message(STATUS " Compiler: ${CMAKE_COMPILER}") -message(STATUS " C++ flags (Release): ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}") -message(STATUS " C++ flags (Debug): ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}") +macro(status text) + SET(status_cond) + SET(status_then) + SET(status_else) + + SET(status_current_name "cond") + foreach(arg ${ARGN}) + if(arg STREQUAL "THEN") + SET(status_current_name "then") + elseif(arg STREQUAL "ELSE") + SET(status_current_name "else") + else() + LIST(APPEND status_${status_current_name} ${arg}) + endif() + endforeach() + + if(DEFINED status_cond) + SET(status_placeholder_length 32) + string(RANDOM LENGTH ${status_placeholder_length} ALPHABET " " status_placeholder) + string(LENGTH "${text}" status_text_length) + if (status_text_length LESS status_placeholder_length) + string(SUBSTRING "${text}${status_placeholder}" 0 ${status_placeholder_length} status_text) + elseif (DEFINED status_then OR DEFINED status_else) + message(STATUS "${text}") + SET(status_text "${status_placeholder}") + else() + SET(status_text "${text}") + endif() + + if (DEFINED status_then OR DEFINED status_else) + if(${status_cond}) + string(REPLACE ";" " " status_then "${status_then}") + message(STATUS "${status_text}" "${status_then}") + else() + string(REPLACE ";" " " status_else "${status_else}") + message(STATUS "${status_text}" "${status_else}") + endif() + else() + string(REPLACE ";" " " status_cond "${status_cond}") + message(STATUS "${status_text}" "${status_cond}") + endif() + else() + message(STATUS "${text}") + endif() +endmacro() + +status("") +status("General configuration for opencv ${OPENCV_VERSION} =====================================") +status("") +status(" Built as dynamic libs?:" BUILD_SHARED_LIBS THEN YES ELSE NO) +status(" Compiler:" CMAKE_COMPILER THEN "${CMAKE_COMPILER}" ELSE "${CMAKE_CXX_COMPILER}") +status(" C++ flags (Release):" ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}) +status(" C++ flags (Debug):" ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}) if(WIN32) -message(STATUS " Linker flags (Release): ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -message(STATUS " Linker flags (Debug): ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") + status(" Linker flags (Release):" ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_RELEASE}) + status(" Linker flags (Debug):" ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_DEBUG}) else() -message(STATUS " Linker flags (Release): ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -message(STATUS " Linker flags (Debug): ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") + status(" Linker flags (Release):" ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}) + status(" Linker flags (Debug):" ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}) +endif() + +if(ANDROID) + status(" Floating point type:" ${ARM_TARGET}) + status(" Native API level:" android-${ANDROID_API_LEVEL}) + status(" SDK target:" "${ANDROID_SDK_TARGET}") endif() #YV -message(STATUS "") -message(STATUS " GUI: ") +status("") +status(" GUI: ") if (HAVE_QT) - message(STATUS " QT 4.x: ${HAVE_QT}") - message(STATUS " QT OpenGL support: ${HAVE_QT_OPENGL}") + status(" QT 4.x:" HAVE_QT THEN YES ELSE NO) + status(" QT OpenGL support:" HAVE_QT_OPENGL THEN YES ELSE NO) else() if(WIN32) - message(STATUS " Win32 UI: YES") + status(" Win32 UI:" YES) else() if(APPLE) if(WITH_CARBON) - message(STATUS " Carbon: YES") + status(" Carbon:" YES) else() - message(STATUS " Cocoa: YES") + status(" Cocoa:" YES) endif() else() - message(STATUS " GTK+ 2.x: ${HAVE_GTK}") - message(STATUS " GThread: ${HAVE_GTHREAD}") + status(" GTK+ 2.x:" HAVE_GTK THEN YES ELSE NO) + status(" GThread:" HAVE_GTHREAD THEN YES ELSE NO) endif() endif() endif() -message(STATUS "") -message(STATUS " Media I/O: ") -if(ZLIB_FOUND) -message(STATUS " ZLib: ${ZLIB_FOUND}") -else() -message(STATUS " ZLib: build") -endif() +# media +status("") +status(" Media I/O: ") +status(" ZLib:" ZLIB_FOUND THEN YES ELSE build) +status(" JPEG:" NOT WITH_JPEG OR JPEG_FOUND THEN ${JPEG_FOUND} ELSE build) +status(" PNG:" NOT WITH_PNG OR PNG_FOUND THEN ${PNG_FOUND} ELSE build) +status(" TIFF:" NOT WITH_TIFF OR TIFF_FOUND THEN ${TIFF_FOUND} ELSE build) +status(" JPEG 2000:" NOT WITH_JASPER OR JASPER_FOUND THEN ${JASPER_FOUND} ELSE build) +status(" OpenEXR:" WITH_OPENEXR AND OPENEXR_FOUND THEN YES ELSE NO) -if(NOT WITH_JPEG OR JPEG_FOUND) -message(STATUS " JPEG: ${JPEG_FOUND}") -else() -message(STATUS " JPEG: build") -endif() - -if(NOT WITH_PNG OR PNG_FOUND) -message(STATUS " PNG: ${PNG_FOUND}") -else() -message(STATUS " PNG: build") -endif() - -if(NOT WITH_TIFF OR TIFF_FOUND) -message(STATUS " TIFF: ${TIFF_FOUND}") -else() -message(STATUS " TIFF: build") -endif() - -if(NOT WITH_JASPER OR JASPER_FOUND) -message(STATUS " JPEG 2000: ${JASPER_FOUND}") -else() -message(STATUS " JPEG 2000: build") -endif() - -if(WITH_OPENEXR AND OPENEXR_FOUND) -message(STATUS " OpenEXR: YES") -else() -message(STATUS " OpenEXR: NO") -endif() - -if(NOT HAVE_OPENNI OR HAVE_OPENNI_PRIME_SENSOR_MODULE) -message(STATUS " OpenNI: ${HAVE_OPENNI}") -else() -message(STATUS " OpenNI: ${HAVE_OPENNI} (WARNING: PrimeSensor Modules for OpenNI are not installed (not found in OPENNI_PRIME_SENSOR_MODULE_BIN_DIR).)") -endif() +status(" OpenNI:" HAVE_OPENNI THEN YES ELSE NO) +status(" OpenNI PrimeSensor Modules:" + HAVE_OPENNI_PRIME_SENSOR_MODULE THEN YES ELSE NO) +status(" XIMEA:" HAVE_XIMEA THEN YES ELSE NO) +# video +status("") if(UNIX AND NOT APPLE) -message(STATUS "") -message(STATUS " Video I/O: ") -message(STATUS " DC1394 1.x: ${HAVE_DC1394}") -message(STATUS " DC1394 2.x: ${HAVE_DC1394_2}") -message(STATUS " FFMPEG: ${HAVE_FFMPEG}") -message(STATUS " codec: ${HAVE_FFMPEG_CODEC}") -message(STATUS " format: ${HAVE_FFMPEG_FORMAT}") -message(STATUS " util: ${HAVE_FFMPEG_UTIL}") -message(STATUS " swscale: ${HAVE_FFMPEG_SWSCALE}") -message(STATUS " gentoo-style: ${HAVE_GENTOO_FFMPEG}") -message(STATUS " GStreamer: ${HAVE_GSTREAMER}") -message(STATUS " UniCap: ${HAVE_UNICAP}") -message(STATUS " PvAPI: ${HAVE_PVAPI}") -if(HAVE_LIBV4L) -message(STATUS " V4L/V4L2: Using libv4l") -else() -message(STATUS " V4L/V4L2: ${HAVE_CAMV4L}/${HAVE_CAMV4L2}") -endif() -message(STATUS " Xine: ${HAVE_XINE}") -if(ANDROID) -if (ARMEABI_V7A) -if(BUILD_ANDROID_CAMERA_WRAPPER) -message(STATUS " AndroidNativeCamera: build for Android ${ANDROID_VERSION}") -else() -message(STATUS " AndroidNativeCamera: use prebuilt libraries") -endif(BUILD_ANDROID_CAMERA_WRAPPER) -else(ARMEABI_V7A) -message(STATUS " AndroidNativeCamera: NO") -endif(ARMEABI_V7A) -endif() -endif() #if(UNIX AND NOT APPLE) + status(" Video I/O:") + status(" DC1394 1.x:" HAVE_DC1394 THEN YES ELSE NO) + status(" DC1394 2.x:" HAVE_DC1394_2 THEN YES ELSE NO) + status(" FFMPEG:" HAVE_FFMPEG THEN YES ELSE NO) + status(" codec:" HAVE_FFMPEG_CODEC THEN YES ELSE NO) + status(" format:" HAVE_FFMPEG_FORMAT THEN YES ELSE NO) + status(" util:" HAVE_FFMPEG_UTIL THEN YES ELSE NO) + status(" swscale:" HAVE_FFMPEG_SWSCALE THEN YES ELSE NO) + status(" gentoo-style:" HAVE_GENTOO_FFMPEG THEN YES ELSE NO) + status(" GStreamer:" HAVE_GSTREAMER THEN YES ELSE NO) + status(" UniCap:" HAVE_UNICAP THEN YES ELSE NO) + status(" PvAPI:" HAVE_PVAPI THEN YES ELSE NO) + status(" V4L/V4L2:" HAVE_LIBV4L THEN Using libv4l ELSE ${HAVE_CAMV4L}/${HAVE_CAMV4L2}) + status(" Xine:" HAVE_XINE THEN YES ELSE NO) -if(APPLE) -message(STATUS "") -if(WITH_QUICKTIME) -message(STATUS " Video I/O: QuickTime") -else() -message(STATUS " Video I/O: QTKit") -endif() + if(ANDROID) + if(WITH_ANDROID_CAMERA) + status(" AndroidNativeCamera:" BUILD_ANDROID_CAMERA_WRAPPER THEN "build for Android ${ANDROID_VERSION}" ELSE "use prebuilt libraries") + else() + status(" AndroidNativeCamera:" "NO (native camera requires Android API level 8 or higher)") + endif() + endif() +elseif(APPLE) + status(" Video I/O:" WITH_QUICKTIME THEN QuickTime ELSE QTKit) +elseif(WIN32) + status(" Video I/O:" HAVE_VIDEOINPUT THEN DirectShow ELSE NO) endif() -if(WIN32 AND HAVE_VIDEOINPUT) -message(STATUS "") -message(STATUS " Video I/O: DirectShow") -endif() - -message(STATUS "") -message(STATUS " Interfaces: ") -message(STATUS " Python: ${BUILD_NEW_PYTHON_SUPPORT}") -message(STATUS " Python interpreter: ${PYTHON_EXECUTABLE}") -if (PYTHON_USE_NUMPY) -message(STATUS " Python numpy: YES") -else() -message(STATUS " Python numpy: NO (Python interface will not cover OpenCV 2.x API)") -endif() +# Other third-party libraries +status("") +status(" Other third-party libraries:") if(WITH_IPP AND IPP_FOUND) -message(STATUS " Use IPP: ${IPP_LATEST_VERSION_STR} [${IPP_LATEST_VERSION_MAJOR}.${IPP_LATEST_VERSION_MINOR}.${IPP_LATEST_VERSION_BUILD}]") -message(STATUS " at: ${IPP_ROOT_DIR}") -elseif(WITH_IPP AND NOT IPP_FOUND) -message(STATUS " Use IPP: IPP not found") + status(" Use IPP:" "${IPP_LATEST_VERSION_STR} [${IPP_LATEST_VERSION_MAJOR}.${IPP_LATEST_VERSION_MINOR}.${IPP_LATEST_VERSION_BUILD}]") + status(" at:" "${IPP_ROOT_DIR}") else() -message(STATUS " Use IPP: NO") + status(" Use IPP:" WITH_IPP AND NOT IPP_FOUND THEN IPP not found ELSE NO) endif() -if(HAVE_TBB) -message(STATUS " Use TBB: YES") -else() -message(STATUS " Use TBB: NO") -if(HAVE_THREADING_FRAMEWORK) -message(STATUS " Use ThreadingFramework: YES") -else() -message(STATUS " Use ThreadingFramework: NO") -endif() +status(" Use TBB:" HAVE_TBB THEN YES ELSE NO) + +if(UNIX) + status(" Use ThreadingFramework:" HAVE_THREADING_FRAMEWORK THEN YES ELSE NO) endif() -if (HAVE_CUDA) -message(STATUS " Use Cuda: YES") +status(" Use Cuda:" HAVE_CUDA THEN YES ELSE NO) +status(" Use Eigen:" HAVE_EIGEN THEN YES ELSE NO) + +# interfaces to other languages +status("") +status(" Interfaces:") +status(" Python:" BUILD_NEW_PYTHON_SUPPORT THEN YES ELSE NO) +status(" Python interpreter:" PYTHON_EXECUTABLE THEN "${PYTHON_EXECUTABLE} (ver ${PYTHON_VERSION_MAJOR_MINOR})" ELSE NO) +status(" Python numpy:" PYTHON_USE_NUMPY THEN YES ELSE "NO (Python wrappers will not be generated)") +if(ANDROID AND ANDROID_API_LEVEL LESS 8) + status(" Java:" "NO (Java API requires Android API level 8 or higher)") else() -message(STATUS " Use Cuda: NO") + status(" Java:" BUILD_JAVA_SUPPORT THEN YES ELSE NO) endif() -if(HAVE_EIGEN) -message(STATUS " Use Eigen: YES") -else() -message(STATUS " Use Eigen: NO") +if(ANDROID) + status(" android tool:" ANDROID_EXECUTABLE THEN "${ANDROID_EXECUTABLE} (${ANDROID_TOOLS_Pkg_Desc})" ELSE NO) + status(" ant:" ANT_EXECUTABLE THEN "${ANT_EXECUTABLE} (ver ${ANT_VERSION})" ELSE NO) endif() -message(STATUS "") -message(STATUS " Documentation: ") - -if(BUILD_DOCS AND PDFLATEX_COMPILER AND HAVE_SPHINX) -message(STATUS " Build Documentation: YES") +# documentation +status("") +status(" Documentation:") +status(" Sphinx:" HAVE_SPHINX THEN "${SPHINX_BUILD} (ver ${SPHINX_VERSION})" ELSE NO) +status(" PdfLaTeX compiler:" PDFLATEX_COMPILER THEN "${PDFLATEX_COMPILER}" ELSE NO) +if (BUILD_DOCS AND HAVE_SPHINX) + status(" Build Documentation:" PDFLATEX_COMPILER THEN YES ELSE "YES (only HTML without math formulas)") else() -message(STATUS " Build Documentation: NO") + status(" Build Documentation:" NO) endif() -#if(BUILD_DOXYGEN_DOCS AND DOXYGEN_FOUND) -#message(STATUS " Doxygen HTMLs YES") -#else() -#message(STATUS " Doxygen HTMLs NO") -#endif() +# samples and tests +status("") +status(" Tests and samples:") +status(" Tests:" BUILD_TESTS THEN YES ELSE NO) +status(" Examples:" BUILD_EXAMPLES THEN YES ELSE NO) -message(STATUS "") -message(STATUS " Install path: ${CMAKE_INSTALL_PREFIX}") -message(STATUS "") -message(STATUS " cvconfig.h is in: ${OPENCV_CONFIG_FILE_INCLUDE_DIR}") -message(STATUS "-----------------------------------------------------------------") -message(STATUS "") +if(ANDROID) + status(" Android tests:" BUILD_TESTS AND CAN_BUILD_ANDROID_PROJECTS THEN YES ELSE NO) + status(" Android examples:" BUILD_ANDROID_EXAMPLES THEN YES ELSE NO) +endif() + +# auxiliary +status("") +status(" Install path:" "${CMAKE_INSTALL_PREFIX}") +status("") +status(" cvconfig.h is in:" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}") +status("-----------------------------------------------------------------") +status("") # warn in the case of in-source build if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") message(WARNING "The source directory is the same as binary directory. \"make clean\" may damage the source tree") endif() - -#---------------------------------------------------------------------------- -# Generate the OpenCVConfig.cmake file for unix -# installation in CMAKE_INSTALL_PREFIX -#---------------------------------------------------------------------------- diff --git a/OpenCV.mk.in b/OpenCV.mk.in index f3ce25c163..95fd93c62b 100644 --- a/OpenCV.mk.in +++ b/OpenCV.mk.in @@ -1,41 +1,53 @@ -RELATIVE_PREFIX:=.$(shell echo $(abspath $(LOCAL_PATH))| sed -e "s/\/[^\/]*/\/../g" ) -OPENCV_THIS_DIR:=$(RELATIVE_PREFIX)$(abspath $(dir $(lastword $(MAKEFILE_LIST)))) -OPENCV_LIBS_DIR:=@CMAKE_LIB_DIRS_CONFIGCMAKE@ -OPENCV_BASEDIR:=@CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE@ +# In order to compile your application under cygwin +# you need to define NDK_USE_CYGPATH=1 before calling ndk-build + +USER_LOCAL_PATH:=$(LOCAL_PATH) +LOCAL_PATH:=$(subst ?,,$(firstword ?$(subst \, ,$(subst /, ,$(call my-dir))))) + +OPENCV_THIS_DIR:=$(patsubst $(LOCAL_PATH)\\%,%,$(patsubst $(LOCAL_PATH)/%,%,$(call my-dir))) +OPENCV_LIBS_DIR:=@CMAKE_LIBS_DIR_CONFIGCMAKE@ +OPENCV_BASEDIR:=@CMAKE_BASE_INCLUDE_DIR_CONFIGCMAKE@ OPENCV_LOCAL_C_INCLUDES:=@CMAKE_INCLUDE_DIRS_CONFIGCMAKE@ -OPENCV_MODULES := contrib calib3d objdetect features2d imgproc video highgui ml legacy flann core +OPENCV_MODULES := contrib calib3d objdetect features2d video imgproc highgui ml legacy flann core + +ifeq (${OPENCV_CAMERA_MODULES},off) + OPENCV_CAMERA_MODULES:= +else + OPENCV_CAMERA_MODULES:=@CMAKE_CAMERA_LIBS_CONFIGCMAKE@ +endif OPENCV_LIB_TYPE:=@OPENCV_LIBTYPE_CONFIGMAKE@ + ifeq ($(OPENCV_LIB_TYPE),SHARED) OPENCV_LIB_SUFFIX:=so OPENCV_EXTRA_COMPONENTS:= else OPENCV_LIB_SUFFIX:=a - OPENCV_MODULES+= androidcamera - OPENCV_EXTRA_COMPONENTS:=@JPEG_LIBRARIES@ @PNG_LIBRARIES@ @TIFF_LIBRARIES@ @JASPER_LIBRARIES@ zlib + ifeq (@WITH_ANDROID_CAMERA@,ON) + OPENCV_MODULES+= androidcamera + endif + OPENCV_EXTRA_COMPONENTS:=@JPEG_LIBRARIES@ @PNG_LIBRARIES@ @TIFF_LIBRARIES@ @JASPER_LIBRARIES@ @ZLIB_LIBRARY@ endif -OPENCV_CAMERA_MODULES := @CMAKE_CAMERA_LIBS_CONFIGCMAKE@ - define add_opencv_module include $(CLEAR_VARS) LOCAL_MODULE:=opencv_$1 - LOCAL_SRC_FILES:=$(OPENCV_LIBS_DIR)/libopencv_$1.$(OPENCV_LIB_SUFFIX) + LOCAL_SRC_FILES:=$(OPENCV_LIBS_DIR)/libs/$(TARGET_ARCH_ABI)/libopencv_$1.$(OPENCV_LIB_SUFFIX) include $(PREBUILT_@OPENCV_LIBTYPE_CONFIGMAKE@_LIBRARY) endef define add_opencv_extra_component include $(CLEAR_VARS) LOCAL_MODULE:=$1 - LOCAL_SRC_FILES:=$(OPENCV_THIS_DIR)/3rdparty/lib/lib$1.a + LOCAL_SRC_FILES:=$(OPENCV_THIS_DIR)/3rdparty/libs/$(TARGET_ARCH_ABI)/lib$1.a include $(PREBUILT_STATIC_LIBRARY) endef define add_opencv_camera_module include $(CLEAR_VARS) LOCAL_MODULE:=$1 - LOCAL_SRC_FILES:=$(OPENCV_LIBS_DIR)/lib$1.so + LOCAL_SRC_FILES:=$(OPENCV_LIBS_DIR)/libs/$(TARGET_ARCH_ABI)/lib$1.so include $(PREBUILT_SHARED_LIBRARY) endef @@ -47,11 +59,16 @@ ifneq ($(OPENCV_BASEDIR),) OPENCV_LOCAL_C_INCLUDES += $(foreach mod, $(OPENCV_MODULES), $(OPENCV_BASEDIR)/modules/$(mod)/include) endif -OPENCV_LOCAL_LIBRARIES += $(foreach mod, $(OPENCV_MODULES), opencv_$(mod)) +ifeq ($(OPENCV_LIB_TYPE),STATIC) + OPENCV_LOCAL_LIBRARIES += $(foreach mod, $(OPENCV_MODULES), opencv_$(mod)) +endif + OPENCV_LOCAL_LIBRARIES += $(OPENCV_EXTRA_COMPONENTS) -OPENCV_LOCAL_CFLAGS := -fsigned-char -fPIC -DANDROID +OPENCV_LOCAL_CFLAGS := -fPIC -DANDROID -fsigned-char include $(CLEAR_VARS) LOCAL_C_INCLUDES += $(OPENCV_LOCAL_C_INCLUDES) LOCAL_STATIC_LIBRARIES += $(OPENCV_LOCAL_LIBRARIES) LOCAL_CFLAGS += $(OPENCV_LOCAL_CFLAGS) + +LOCAL_PATH:=$(USER_LOCAL_PATH) diff --git a/OpenCVAndroidProject.cmake b/OpenCVAndroidProject.cmake new file mode 100644 index 0000000000..d3f3b6c17a --- /dev/null +++ b/OpenCVAndroidProject.cmake @@ -0,0 +1,143 @@ +# creates target "${_target}_android_project" for building standard Android project +macro(add_android_project _target _path) + SET (android_dependencies opencv_contrib opencv_legacy opencv_objdetect opencv_calib3d opencv_features2d opencv_video opencv_highgui opencv_ml opencv_imgproc opencv_flann opencv_core) + if(NOT BUILD_SHARED_LIBS) + LIST(APPEND android_dependencies opencv_androidcamera) + endif() + + if (ANDROID AND CAN_BUILD_ANDROID_PROJECTS) + file(GLOB_RECURSE res_files_all RELATIVE "${_path}" "${_path}/res/*") + file(GLOB_RECURSE jni_files_all RELATIVE "${_path}" "${_path}/jni/*.c*" "${_path}/jni/*.h*") + file(GLOB_RECURSE src_files_all RELATIVE "${_path}" "${_path}/src/*.java") + + #remove .svn + set(res_files) + foreach(f ${res_files_all}) + if(NOT f MATCHES "\\.svn") + list(APPEND res_files "${f}") + endif() + endforeach() + set(jni_files) + foreach(f ${jni_files_all}) + if(NOT f MATCHES "\\.svn") + list(APPEND jni_files "${f}") + endif() + endforeach() + set(src_files) + foreach(f ${src_files_all}) + if(NOT f MATCHES "\\.svn") + list(APPEND src_files "${f}") + endif() + endforeach() + + # get temporary location for the project + file(RELATIVE_PATH build_path "${OpenCV_SOURCE_DIR}" "${_path}") + SET(build_path "${CMAKE_BINARY_DIR}/${build_path}") + + # copy project to temporary location + SET(${_target}_project_files) + foreach(f ${res_files} ${src_files} "AndroidManifest.xml") + if(NOT "${build_path}" STREQUAL "${_path}") + #this is not needed in case of in-source build + add_custom_command( + OUTPUT "${build_path}/${f}" + COMMAND ${CMAKE_COMMAND} -E copy "${_path}/${f}" "${build_path}/${f}" + DEPENDS "${_path}/${f}" + COMMENT "" + ) + endif() + list(APPEND ${_target}_project_files "${build_path}/${f}") + endforeach() + + # process default.properties + file(STRINGS "${_path}/default.properties" default_properties REGEX "^android\\.library\\.reference\\.1=.+$") + if (default_properties) + # has opencv dependency + file(RELATIVE_PATH OPENCV_REFERENCE_PATH "${build_path}" "${CMAKE_BINARY_DIR}") + add_custom_command( + OUTPUT "${build_path}/default.properties" + OUTPUT "${build_path}/build.xml" + OUTPUT "${build_path}/local.properties" + OUTPUT "${build_path}/proguard.cfg" + COMMAND ${CMAKE_COMMAND} -E echo "" > "default.properties" + COMMAND ${ANDROID_EXECUTABLE} update project --name "${_target}" --target "${ANDROID_SDK_TARGET}" --library "${OPENCV_REFERENCE_PATH}" --path . + WORKING_DIRECTORY ${build_path} + DEPENDS ${${_target}_project_files} + DEPENDS "${CMAKE_BINARY_DIR}/default.properties" + DEPENDS "${CMAKE_BINARY_DIR}/AndroidManifest.xml" + COMMENT "Updating android project - ${_target}" + ) + else() + # has no opencv dependency + add_custom_command( + OUTPUT "${build_path}/default.properties" + OUTPUT "${build_path}/build.xml" + OUTPUT "${build_path}/local.properties" + OUTPUT "${build_path}/proguard.cfg" + COMMAND ${CMAKE_COMMAND} -E echo "" > "default.properties" + COMMAND ${ANDROID_EXECUTABLE} update project --name "${_target}" --target "${ANDROID_SDK_TARGET}" --path . + WORKING_DIRECTORY ${build_path} + DEPENDS ${${_target}_project_files} + COMMENT "Updating android project - ${_target}" + ) + endif() + + if("${build_path}" STREQUAL "${_path}") + #in case of in-source build default.properties file is not generated (it is just overwritten :) + SET_SOURCE_FILES_PROPERTIES("${build_path}/default.properties" PROPERTIES GENERATED FALSE) + endif() + + list(APPEND ${_target}_project_files "${build_path}/default.properties" "${build_path}/build.xml" "${build_path}/local.properties" "${build_path}/proguard.cfg") + + # build native part of android project + if(jni_files) + INCLUDE_DIRECTORIES("${_path}/jni") + + FILE(STRINGS "${_path}/jni/Android.mk" JNI_LIB_NAME REGEX "LOCAL_MODULE[ ]*:=[ ]*.*" ) + string(REGEX REPLACE "LOCAL_MODULE[ ]*:=[ ]*([a-zA-Z_][a-zA-Z_0-9]*)[ ]*" "\\1" JNI_LIB_NAME "${JNI_LIB_NAME}") + + SET(jni_sources) + foreach(src ${jni_files}) + list(APPEND jni_sources "${_path}/${src}") + endforeach() + + ADD_LIBRARY(${JNI_LIB_NAME} MODULE ${jni_sources}) + TARGET_LINK_LIBRARIES(${JNI_LIB_NAME} ${OPENCV_LINKER_LIBS} ${android_dependencies}) + + set_target_properties(${JNI_LIB_NAME} PROPERTIES + OUTPUT_NAME "${JNI_LIB_NAME}" + LIBRARY_OUTPUT_DIRECTORY "${build_path}/libs/${ARMEABI_NDK_NAME}" + ) + + ADD_CUSTOM_COMMAND( + TARGET ${JNI_LIB_NAME} + POST_BUILD + COMMAND ${CMAKE_STRIP} "${build_path}/libs/${ARMEABI_NDK_NAME}/*.so" + ) + else() + SET(JNI_LIB_NAME) + endif() + + add_custom_command( + OUTPUT "${build_path}/bin/${_target}-debug.apk" + OUTPUT "${CMAKE_BINARY_DIR}/bin/${_target}.apk" + COMMAND ${ANT_EXECUTABLE} -q -noinput -k debug + COMMAND ${CMAKE_COMMAND} -E copy "${build_path}/bin/${_target}-debug.apk" "${CMAKE_BINARY_DIR}/bin/${_target}.apk" + WORKING_DIRECTORY ${build_path} + DEPENDS ${${_target}_project_files} + DEPENDS "${LIBRARY_OUTPUT_PATH}/libopencv_java.so" + COMMENT "Generating bin/${_target}.apk" + ) + + ADD_CUSTOM_TARGET(${_target}_android_project ALL + DEPENDS "${build_path}/bin/${_target}-debug.apk" + DEPENDS "${CMAKE_BINARY_DIR}/bin/${_target}.apk" + ) + + add_dependencies(${_target}_android_project opencv_java ${JNI_LIB_NAME}) + + if("${ARGN}" STREQUAL "INSTALL" AND INSTALL_ANDROID_EXAMPLES) + install(FILES "${CMAKE_BINARY_DIR}/bin/${_target}.apk" DESTINATION "bin" COMPONENT main) + endif() + endif() +endmacro() diff --git a/OpenCVConfig-version.cmake.in b/OpenCVConfig-version.cmake.in new file mode 100644 index 0000000000..ab11e3927c --- /dev/null +++ b/OpenCVConfig-version.cmake.in @@ -0,0 +1,14 @@ +set(OpenCV_VERSION @OPENCV_VERSION@) +set(PACKAGE_VERSION ${OpenCV_VERSION}) + +set(PACKAGE_VERSION_EXACT False) +set(PACKAGE_VERSION_COMPATIBLE False) + +if(PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT True) + set(PACKAGE_VERSION_COMPATIBLE True) +endif() + +if(PACKAGE_FIND_VERSION VERSION_LESS PACKAGE_VERSION) + set(PACKAGE_VERSION_COMPATIBLE True) +endif() diff --git a/OpenCVConfig.cmake.in b/OpenCVConfig.cmake.in index 7234be2f2b..ff6016adbb 100644 --- a/OpenCVConfig.cmake.in +++ b/OpenCVConfig.cmake.in @@ -15,10 +15,19 @@ # with this path is NOT needed. # - OpenCV_INCLUDE_DIRS : The OpenCV include directories. # - OpenCV_COMPUTE_CAPABILITIES : The version of compute capability -# - OpenCV_VERSION : The version of this OpenCV build. Example: "1.2.0" -# - OpenCV_VERSION_MAJOR : Major version part of OpenCV_VERSION. Example: "1" -# - OpenCV_VERSION_MINOR : Minor version part of OpenCV_VERSION. Example: "2" -# - OpenCV_VERSION_PATCH : Patch version part of OpenCV_VERSION. Example: "0" +# - OpenCV_VERSION : The version of this OpenCV build. Example: "@OPENCV_VERSION@" +# - OpenCV_VERSION_MAJOR : Major version part of OpenCV_VERSION. Example: "@OPENCV_VERSION_MAJOR@" +# - OpenCV_VERSION_MINOR : Minor version part of OpenCV_VERSION. Example: "@OPENCV_VERSION_MINOR@" +# - OpenCV_VERSION_PATCH : Patch version part of OpenCV_VERSION. Example: "@OPENCV_VERSION_PATCH@" +# +# Advanced variables: +# - OpenCV_SHARED +# - OpenCV_CONFIG_PATH +# - OpenCV_INSTALL_PATH +# - OpenCV_LIB_COMPONENTS +# - OpenCV_EXTRA_COMPONENTS +# - OpenCV_USE_MANGLED_PATHS +# - OpenCV_HAVE_ANDROID_CAMERA # # ================================================================================================= @@ -28,9 +37,20 @@ # ====================================================== SET(OpenCV_COMPUTE_CAPABILITIES @OpenCV_CUDA_CC@) +# Some additional settings are required if OpenCV is built as static libs +set(OpenCV_SHARED @BUILD_SHARED_LIBS@) + +# Enables mangled install paths, that help with side by side installs +set(OpenCV_USE_MANGLED_PATHS @OPENCV_MANGLED_INSTALL_PATHS@) + # Extract the directory where *this* file has been installed (determined at cmake run-time) -# This variable may or may not be used below, depending on the parsing of OpenCVConfig.cmake -get_filename_component(THIS_OPENCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH) + +# Get the absolute path with no ../.. relative marks, to eliminate implicit linker warnings +get_filename_component(OpenCV_INSTALL_PATH "${OpenCV_CONFIG_PATH}/../.." REALPATH) + +# Presence of Android native camera support +set (OpenCV_HAVE_ANDROID_CAMERA @WITH_ANDROID_CAMERA@) # ====================================================== # Include directories to add to the user project: @@ -38,7 +58,6 @@ get_filename_component(THIS_OPENCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH # Provide the include directories to the caller SET(OpenCV_INCLUDE_DIRS @CMAKE_INCLUDE_DIRS_CONFIGCMAKE@) - INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS}) # ====================================================== @@ -47,93 +66,100 @@ INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS}) # Provide the libs directory anyway, it may be needed in some cases. SET(OpenCV_LIB_DIR @CMAKE_LIB_DIRS_CONFIGCMAKE@) - LINK_DIRECTORIES(${OpenCV_LIB_DIR}) # ==================================================================== -# Link libraries: e.g. opencv_core220.so, opencv_imgproc220d.lib, etc... +# Link libraries: e.g. libopencv_core.so, opencv_imgproc220d.lib, etc... # ==================================================================== +SET(OpenCV_LIB_COMPONENTS opencv_contrib opencv_legacy opencv_objdetect opencv_calib3d opencv_features2d opencv_video opencv_highgui opencv_ml opencv_imgproc opencv_flann opencv_core ) +#libraries order is very important because linker from Android NDK is one-pass linker if(NOT ANDROID) - set(OPENCV_LIB_COMPONENTS opencv_core opencv_imgproc opencv_features2d opencv_gpu opencv_calib3d opencv_objdetect opencv_video opencv_highgui opencv_ml opencv_legacy opencv_contrib opencv_flann) -else() - #libraries order is very important because linker from Android NDK is one-pass linker - set(OPENCV_LIB_COMPONENTS opencv_contrib opencv_calib3d opencv_objdetect opencv_features2d opencv_imgproc opencv_video opencv_highgui opencv_ml opencv_legacy opencv_flann opencv_core ) - IF (NOT @BUILD_SHARED_LIBS@) - set(OPENCV_LIB_COMPONENTS ${OPENCV_LIB_COMPONENTS} opencv_androidcamera) - ENDIF() + LIST(INSERT OpenCV_LIB_COMPONENTS 0 opencv_gpu) +ELSEIF(NOT OpenCV_SHARED AND OpenCV_HAVE_ANDROID_CAMERA) + LIST(APPEND OpenCV_LIB_COMPONENTS opencv_androidcamera) +endif() + +if(OpenCV_USE_MANGLED_PATHS) + #be explicit about the library names. + set(OpenCV_LIB_COMPONENTS_ ) + foreach( CVLib ${OpenCV_LIB_COMPONENTS}) + list(APPEND OpenCV_LIB_COMPONENTS_ ${OpenCV_LIB_DIR}/lib${CVLib}.so.@OPENCV_VERSION@ ) + endforeach() + set(OpenCV_LIB_COMPONENTS ${OpenCV_LIB_COMPONENTS_}) endif() SET(OpenCV_LIBS "") -foreach(__CVLIB ${OPENCV_LIB_COMPONENTS}) - # CMake>=2.6 supports the notation "debug XXd optimized XX" - if (CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 4) - # Modern CMake: - SET(OpenCV_LIBS ${OpenCV_LIBS} debug ${__CVLIB}@OPENCV_DLLVERSION@@OPENCV_DEBUG_POSTFIX@ optimized ${__CVLIB}@OPENCV_DLLVERSION@) - else(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 4) - # Old CMake: - SET(OpenCV_LIBS ${OpenCV_LIBS} ${__CVLIB}@OPENCV_DLLVERSION@) - endif(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 4) -endforeach(__CVLIB) +if(WIN32) + foreach(__CVLIB ${OpenCV_LIB_COMPONENTS}) + # CMake>=2.6 supports the notation "debug XXd optimized XX" + if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_GREATER 2.4) + # Modern CMake: + SET(OpenCV_LIBS ${OpenCV_LIBS} debug ${__CVLIB}@OPENCV_DLLVERSION@@OPENCV_DEBUG_POSTFIX@ optimized ${__CVLIB}@OPENCV_DLLVERSION@) + else() + # Old CMake: + SET(OpenCV_LIBS ${OpenCV_LIBS} ${__CVLIB}@OPENCV_DLLVERSION@) + endif() + endforeach() +else() + foreach(__CVLIB ${OpenCV_LIB_COMPONENTS}) + SET(OpenCV_LIBS ${OpenCV_LIBS} ${__CVLIB}) + endforeach() +endif() # ============================================================== # Extra include directories, needed by OpenCV 2 new structure # ============================================================== -if(NOT @CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE@ STREQUAL "") - SET(BASEDIR @CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE@) - foreach(__CVLIB ${OPENCV_LIB_COMPONENTS}) +if(NOT "@CMAKE_OPENCV2_INCLUDE_DIRS_CONFIGCMAKE@" STREQUAL "") + foreach(__CVLIB ${OpenCV_LIB_COMPONENTS}) # We only need the "core",... part here: "opencv_core" -> "core" - STRING(REGEX REPLACE "opencv_(.*)" "\\1" MODNAME ${__CVLIB}) - INCLUDE_DIRECTORIES("${BASEDIR}/modules/${MODNAME}/include") - endforeach(__CVLIB) -endif(NOT @CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE@ STREQUAL "") + STRING(REGEX REPLACE "opencv_(.*)" "\\1" __MODNAME ${__CVLIB}) + INCLUDE_DIRECTORIES("@CMAKE_OPENCV2_INCLUDE_DIRS_CONFIGCMAKE@/modules/${__MODNAME}/include") + endforeach() +endif() # For OpenCV built as static libs, we need the user to link against # many more dependencies: -set(OpenCV_SHARED @BUILD_SHARED_LIBS@) - IF (NOT OpenCV_SHARED) # Under static libs, the user of OpenCV needs access to the 3rdparty libs as well: - if(WIN32 AND NOT ANDROID) - LINK_DIRECTORIES(@CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE@/3rdparty/lib) - else() - LINK_DIRECTORIES("${THIS_OPENCV_CONFIG_PATH}/3rdparty/lib") - endif() + LINK_DIRECTORIES(@CMAKE_3RDPARTY_LIB_DIRS_CONFIGCMAKE@) set(OpenCV_LIBS @OPENCV_LINKER_LIBS@ @IPP_LIBS@ @HIGHGUI_LIBRARIES@ ${OpenCV_LIBS}) + set(OpenCV_EXTRA_COMPONENTS @JPEG_LIBRARIES@ @PNG_LIBRARIES@ @TIFF_LIBRARIES@ @JASPER_LIBRARIES@ @ZLIB_LIBRARY@) - set(OPENCV_EXTRA_COMPONENTS @JPEG_LIBRARIES@ @PNG_LIBRARIES@ @TIFF_LIBRARIES@ @JASPER_LIBRARIES@ zlib) - - if (CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 4) - foreach(__EXTRA_LIB ${OPENCV_EXTRA_COMPONENTS}) + if (WIN32 AND ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_GREATER 2.4) + # Modern CMake: + foreach(__EXTRA_LIB ${OpenCV_EXTRA_COMPONENTS}) set(OpenCV_LIBS ${OpenCV_LIBS} debug ${__EXTRA_LIB}@OPENCV_DEBUG_POSTFIX@ optimized ${__EXTRA_LIB}) - endforeach(__EXTRA_LIB) - else(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 4) - set(OpenCV_LIBS ${OpenCV_LIBS} ${OPENCV_EXTRA_COMPONENTS}) - endif(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 4) - + endforeach() + else() + # Old CMake: + set(OpenCV_LIBS ${OpenCV_LIBS} ${OpenCV_EXTRA_COMPONENTS}) + endif() + + if (APPLE) + set(OpenCV_LIBS ${OpenCV_LIBS} "-lbz2" "-framework Cocoa" "-framework QuartzCore" "-framework QTKit") + endif() ENDIF() # ====================================================== # Android camera helper macro # ====================================================== -IF (ANDROID) +IF (OpenCV_HAVE_ANDROID_CAMERA) macro( COPY_NATIVE_CAMERA_LIBS target ) - IF( ARMEABI_V7A) - get_target_property(target_location ${target} LOCATION) - get_filename_component(target_location "${target_location}" PATH) - file(GLOB camera_wrappers "${OpenCV_LIB_DIR}/libnative_camera_r*.so") - foreach(wrapper ${camera_wrappers}) - ADD_CUSTOM_COMMAND( - TARGET ${target} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy "${wrapper}" "${target_location}" - ) - endforeach() - ENDIF( ARMEABI_V7A ) + get_target_property(target_location ${target} LOCATION) + get_filename_component(target_location "${target_location}" PATH) + file(GLOB camera_wrappers "${OpenCV_LIB_DIR}/libnative_camera_r*.so") + foreach(wrapper ${camera_wrappers}) + ADD_CUSTOM_COMMAND( + TARGET ${target} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${wrapper}" "${target_location}" + ) + endforeach() endmacro() -ENDIF(ANDROID) +ENDIF() # ====================================================== # Version variables: diff --git a/OpenCVFindIPP.cmake b/OpenCVFindIPP.cmake index 1927454c8b..69f7f2e256 100644 --- a/OpenCVFindIPP.cmake +++ b/OpenCVFindIPP.cmake @@ -43,6 +43,14 @@ set(IPPCV "cv") # computer vision set(IPPVM "vm") # vector math +set(IPP_X64 0) +if (CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + set(IPP_X64 1) +endif() +if (CMAKE_CL_64) + set(IPP_X64 1) +endif() + # ------------------------------------------------------------------------ # This function detect IPP version by analyzing ippversion.h file # Note, ippversion.h file was inroduced since IPP 5.3 @@ -96,7 +104,7 @@ function(set_ipp_old_libraries) set(IPPCV "cv") # computer vision set(IPPVM "vm") # vector math - if (CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + if (IPP_X64) set(IPP_ARCH "em64t") endif() @@ -167,7 +175,7 @@ function(set_ipp_variables _LATEST_VERSION) set(IPP_INCLUDE_DIRS ${IPP_ROOT_DIR}/include PARENT_SCOPE) set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib PARENT_SCOPE) - if (CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + if (IPP_X64) if(NOT EXISTS ${IPP_ROOT_DIR}/../em64t) message(SEND_ERROR "IPP EM64T libraries not found") endif() @@ -188,7 +196,7 @@ function(set_ipp_variables _LATEST_VERSION) # set INCLUDE and LIB folders set(IPP_INCLUDE_DIRS ${IPP_ROOT_DIR}/include PARENT_SCOPE) - if (CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + if (IPP_X64) if(NOT EXISTS ${IPP_ROOT_DIR}/lib/intel64) message(SEND_ERROR "IPP EM64T libraries not found") endif() diff --git a/OpenCVFindLATEX.cmake b/OpenCVFindLATEX.cmake index 392d2a8bf2..081f47853d 100644 --- a/OpenCVFindLATEX.cmake +++ b/OpenCVFindLATEX.cmake @@ -47,55 +47,55 @@ IF (WIN32) ENDIF (WIN32) -FIND_PROGRAM(LATEX_COMPILER +FIND_HOST_PROGRAM(LATEX_COMPILER NAMES latex PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin ) -FIND_PROGRAM(PDFLATEX_COMPILER +FIND_HOST_PROGRAM(PDFLATEX_COMPILER NAMES pdflatex PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin ) -FIND_PROGRAM(BIBTEX_COMPILER +FIND_HOST_PROGRAM(BIBTEX_COMPILER NAMES bibtex PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin ) -FIND_PROGRAM(MAKEINDEX_COMPILER +FIND_HOST_PROGRAM(MAKEINDEX_COMPILER NAMES makeindex PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin ) -FIND_PROGRAM(DVIPS_CONVERTER +FIND_HOST_PROGRAM(DVIPS_CONVERTER NAMES dvips PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin ) -FIND_PROGRAM(DVIPDF_CONVERTER +FIND_HOST_PROGRAM(DVIPDF_CONVERTER NAMES dvipdfm dvipdft dvipdf PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin ) IF (WIN32) - FIND_PROGRAM(PS2PDF_CONVERTER + FIND_HOST_PROGRAM(PS2PDF_CONVERTER NAMES ps2pdf14.bat PATHS ${GHOSTSCRIPT_LIBRARY_PATH} ) ELSE (WIN32) - FIND_PROGRAM(PS2PDF_CONVERTER + FIND_HOST_PROGRAM(PS2PDF_CONVERTER NAMES ps2pdf14 ps2pdf PATHS /usr/bin /usr/texbin ) ENDIF (WIN32) -FIND_PROGRAM(LATEX2HTML_CONVERTER +FIND_HOST_PROGRAM(LATEX2HTML_CONVERTER NAMES latex2html PATHS ${MIKTEX_BINARY_PATH} /usr/bin /usr/texbin diff --git a/OpenCVFindOpenNI.cmake b/OpenCVFindOpenNI.cmake index 17ad9cca15..2bfd074daa 100644 --- a/OpenCVFindOpenNI.cmake +++ b/OpenCVFindOpenNI.cmake @@ -2,81 +2,57 @@ # OPENNI_LIBRARY and OPENNI_INCLUDES to link OpenCV modules with OpenNI # HAVE_OPENNI for conditional compilation OpenCV with/without OpenNI -set(OPENNI_LIB_DESCR "Path to the directory of OpenNI libraries" CACHE INTERNAL "Description" ) -set(OPENNI_INCLUDE_DESCR "Path to the directory of OpenNI includes" CACHE INTERNAL "Description" ) -set(OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR "Path to the directory of PrimeSensor Module binaries" CACHE INTERNAL "Description" ) - if(NOT "${OPENNI_LIB_DIR}" STREQUAL "${OPENNI_LIB_DIR_INTERNAL}") unset(OPENNI_LIBRARY CACHE) -endif() - -if(NOT "${OPENNI_INCLUDE_DIR}" STREQUAL "${OPENNI_INCLUDE_DIR_INTERNAL}") - unset(OPENNI_INCLUDES CACHE) -endif() - -if(NOT "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}" STREQUAL "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}") - unset(OPENNI_PRIME_SENSOR_MODULE CACHE) -endif() - -if(NOT OPENNI_LIB_DIR OR OPENNI_LIB_DIR STREQUAL "") - if(WIN32) - set(OPENNI_LIB_DIR "c:/Program Files/OpenNI/Lib" CACHE PATH ${OPENNI_LIB_DESCR}) - elseif(UNIX OR APPLE) - set(OPENNI_LIB_DIR "/usr/lib" CACHE PATH ${OPENNI_LIB_DESCR}) - endif() -endif() - -if(NOT OPENNI_INCLUDE_DIR OR OPENNI_INCLUDE_DIR STREQUAL "") - if(WIN32) - set(OPENNI_INCLUDE_DIR "c:/Program Files/OpenNI/Include" CACHE PATH ${OPENNI_INCLUDE_DESCR}) - elseif(UNIX OR APPLE) - set(OPENNI_INCLUDE_DIR "/usr/include/ni" CACHE PATH ${OPENNI_INCLUDE_DESCR}) - endif() -endif() - -if(NOT OPENNI_PRIME_SENSOR_MODULE_BIN_DIR OR OPENNI_PRIME_SENSOR_MODULE_BIN_DIR STREQUAL "") - if(WIN32) - set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "c:/Program Files/Prime Sense/Sensor/Bin" CACHE PATH ${OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR}) - elseif(UNIX OR APPLE) - set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "/usr/lib" CACHE PATH ${OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR}) - endif() + unset(OPENNI_LIB_DIR CACHE) endif() -find_library(OPENNI_LIBRARY "OpenNI" PATHS ${OPENNI_LIB_DIR} DOC "OpenNI library" NO_DEFAULT_PATH) -find_path(OPENNI_INCLUDES "XnCppWrapper.h" PATHS ${OPENNI_INCLUDE_DIR} DOC "OpenNI c++ interface header" NO_DEFAULT_PATH) +if(NOT "${OPENNI_INCLUDE_DIR}" STREQUAL "${OPENNI_INCLUDE_DIR_INTERNAL}") + unset(OPENNI_INCLUDES CACHE) + unset(OPENNI_INCLUDE_DIR CACHE) +endif() + +if(NOT "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}" STREQUAL "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR_INTERNAL}") + unset(OPENNI_PRIME_SENSOR_MODULE CACHE) + unset(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR CACHE) +endif() + +find_file(OPENNI_INCLUDES "XnCppWrapper.h" PATHS $ENV{OPEN_NI_INCLUDE} "/usr/include/ni" "/usr/include/openni" "c:/Program Files/OpenNI/Include" DOC "OpenNI c++ interface header") +find_library(OPENNI_LIBRARY "OpenNI" PATHS $ENV{OPEN_NI_LIB} "/usr/lib" "c:/Program Files/OpenNI/Lib" DOC "OpenNI library") if(OPENNI_LIBRARY AND OPENNI_INCLUDES) set(HAVE_OPENNI TRUE) - # the check: are PrimeSensor Modules for OpenNI installed? + # the check: are PrimeSensor Modules for OpenNI installed if(WIN32) - find_file(OPENNI_PRIME_SENSOR_MODULE "XnCore.dll" PATHS ${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR} DOC "Core library of PrimeSensor Modules for OpenNI" NO_DEFAULT_PATH) + find_file(OPENNI_PRIME_SENSOR_MODULE "XnCore.dll" PATHS "c:/Program Files/Prime Sense/Sensor/Bin" DOC "Core library of PrimeSensor Modules for OpenNI") elseif(UNIX OR APPLE) - find_library(OPENNI_PRIME_SENSOR_MODULE "XnCore" PATHS ${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR} DOC "Core library of PrimeSensor Modules for OpenNI" NO_DEFAULT_PATH) + find_library(OPENNI_PRIME_SENSOR_MODULE "XnCore" PATHS "/usr/lib" DOC "Core library of PrimeSensor Modules for OpenNI") endif() if(OPENNI_PRIME_SENSOR_MODULE) set(HAVE_OPENNI_PRIME_SENSOR_MODULE TRUE) - endif() + endif() endif() #if(OPENNI_LIBRARY AND OPENNI_INCLUDES) +get_filename_component(OPENNI_LIB_DIR "${OPENNI_LIBRARY}" PATH CACHE) +get_filename_component(OPENNI_INCLUDE_DIR ${OPENNI_INCLUDES} PATH CACHE) +get_filename_component(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "${OPENNI_PRIME_SENSOR_MODULE}" PATH CACHE) + if(OPENNI_LIBRARY) set(OPENNI_LIB_DIR_INTERNAL "${OPENNI_LIB_DIR}" CACHE INTERNAL "This is the value of the last time OPENNI_LIB_DIR was set successfully." FORCE) else() - set(OPENNI_LIB_DIR "${OPENNI_LIB_DIR}-NOTFOUND or does not have OpenNI libraries" CACHE PATH ${OPENNI_LIB_DESCR} FORCE) message( WARNING, " OpenNI library directory (set by OPENNI_LIB_DIR variable) is not found or does not have OpenNI libraries." ) endif() if(OPENNI_INCLUDES) set(OPENNI_INCLUDE_DIR_INTERNAL "${OPENNI_INCLUDE_DIR}" CACHE INTERNAL "This is the value of the last time OPENNI_INCLUDE_DIR was set successfully." FORCE) else() - set(OPENNI_INCLUDE_DIR "${OPENNI_INCLUDE_DIR}-NOTFOUND or does not have OpenNI includes" CACHE PATH ${OPENNI_INCLUDE_DESCR} FORCE) - message( WARNING, " OpenNI include directory (set by OPENNI_INCLUDE_DIR variable) is not found or does not have OpenNI includes." ) + message( WARNING, " OpenNI include directory (set by OPENNI_INCLUDE_DIR variable) is not found or does not have OpenNI include files." ) endif() if(OPENNI_PRIME_SENSOR_MODULE) set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR_INTERNAL "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}" CACHE INTERNAL "This is the value of the last time OPENNI_PRIME_SENSOR_MODULE_BIN_DIR was set successfully." FORCE) else() - set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}-NOTFOUND or does not have PrimeSensor Module binaries" CACHE PATH ${OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR} FORCE) message( WARNING, " PrimeSensor Module binaries directory (set by OPENNI_PRIME_SENSOR_MODULE_BIN_DIR variable) is not found or does not have PrimeSensor Module binaries." ) endif() diff --git a/OpenCVFindXimea.cmake b/OpenCVFindXimea.cmake new file mode 100755 index 0000000000..afc73e09f7 --- /dev/null +++ b/OpenCVFindXimea.cmake @@ -0,0 +1,35 @@ +# - Find XIMEA +# This module finds if XIMEA Software package is installed +# and determines where the binaries and header files are. +# This code sets the following variables: +# +# XIMEA_FOUND - True if XIMEA API found +# XIMEA_PATH: - Path to the XIMEA API folder +# XIMEA_LIBRARY_DIRS - XIMEA libraries folder +# +# Created: 5 Aug 2011 by Marian Zajko (marian.zajko@ximea.com) +# + +set(XIMEA_FOUND) +set(XIMEA_PATH) +set(XIMEA_LIBRARY_DIR) + +# Try to find the XIMEA API path in registry. +GET_FILENAME_COMPONENT(XIMEA_PATH "[HKEY_CURRENT_USER\\Software\\XIMEA\\CamSupport\\API;Path]" ABSOLUTE) + +if(XIMEA_PATH) + set(XIMEA_FOUND 1) + + # set LIB folders + set(XIMEA_LIBRARY_DIR "${XIMEA_PATH}\\x86") + +else() + set(XIMEA_FOUND 0) +endif() + +mark_as_advanced(FORCE XIMEA_FOUND) +mark_as_advanced(FORCE XIMEA_PATH) +mark_as_advanced(FORCE XIMEA_LIBRARY_DIR) + + + \ No newline at end of file diff --git a/OpenCVModule.cmake b/OpenCVModule.cmake index f7620b6cb9..53a24bdfdc 100644 --- a/OpenCVModule.cmake +++ b/OpenCVModule.cmake @@ -1,3 +1,24 @@ +#opencv precompiled headers macro (can add pch to modules and tests) +#this macro must be called after any "add_definitions" commands, otherwise precompiled headers will not work +macro(add_opencv_precompiled_headers the_target) + if("${the_target}" MATCHES "opencv_test_.*") + SET(pch_name "test/test_precomp") + else() + SET(pch_name "src/precomp") + endif() + set(pch_header "${CMAKE_CURRENT_SOURCE_DIR}/${pch_name}.hpp") + if(PCHSupport_FOUND AND USE_PRECOMPILED_HEADERS AND EXISTS "${pch_header}") + if(CMAKE_GENERATOR MATCHES Visual) + set(${the_target}_pch "${CMAKE_CURRENT_SOURCE_DIR}/${pch_name}.cpp") + add_native_precompiled_header(${the_target} ${pch_header}) + elseif(CMAKE_GENERATOR MATCHES Xcode) + add_native_precompiled_header(${the_target} ${pch_header}) + elseif(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_GENERATOR MATCHES Makefiles) + add_precompiled_header(${the_target} ${pch_header}) + endif() + endif() +endmacro() + # this is template for a OpenCV module macro(define_opencv_module name) @@ -8,20 +29,19 @@ macro(define_opencv_module name) "${CMAKE_CURRENT_BINARY_DIR}") foreach(d ${ARGN}) - if(${d} MATCHES "opencv_") - if(${d} MATCHES "opencv_lapack") - else() - string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d}) - include_directories("${d_dir}/include") - endif() + if(d MATCHES "opencv_") + string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d}) + include_directories("${d_dir}/include") endif() endforeach() file(GLOB lib_srcs "src/*.cpp") file(GLOB lib_int_hdrs "src/*.h*") + if(COMMAND get_module_external_sources) get_module_external_sources(${name}) endif() + source_group("Src" FILES ${lib_srcs} ${lib_int_hdrs}) file(GLOB lib_hdrs "include/opencv2/${name}/*.h*") @@ -66,17 +86,7 @@ macro(define_opencv_module name) INSTALL_NAME_DIR lib ) - if(PCHSupport_FOUND AND USE_PRECOMPILED_HEADERS) - set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/src/precomp.hpp) - if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*") - if(${CMAKE_GENERATOR} MATCHES "Visual*") - set(${the_target}_pch "src/precomp.cpp") - endif() - add_native_precompiled_header(${the_target} ${pch_header}) - elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles") - add_precompiled_header(${the_target} ${pch_header}) - endif() - endif() + add_opencv_precompiled_headers(${the_target}) # Add the required libraries for linking: target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${IPP_LIBS} ${ARGN}) @@ -97,11 +107,11 @@ macro(define_opencv_module name) install(TARGETS ${the_target} RUNTIME DESTINATION bin COMPONENT main - LIBRARY DESTINATION lib COMPONENT main - ARCHIVE DESTINATION lib COMPONENT main) + LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main + ARCHIVE DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main) install(FILES ${lib_hdrs} - DESTINATION include/opencv2/${name} + DESTINATION ${OPENCV_INCLUDE_PREFIX}/opencv2/${name} COMPONENT main) if(BUILD_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test) @@ -111,12 +121,9 @@ macro(define_opencv_module name) set(test_deps opencv_${name} ${ARGN} opencv_ts opencv_highgui ${EXTRA_${the_target}_DEPS}) foreach(d ${test_deps}) - if(${d} MATCHES "opencv_") - if(${d} MATCHES "opencv_lapack") - else() - string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d}) - include_directories("${d_dir}/include") - endif() + if(d MATCHES "opencv_") + string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d}) + include_directories("${d_dir}/include") endif() endforeach() @@ -130,24 +137,14 @@ macro(define_opencv_module name) add_executable(${the_target} ${test_srcs} ${test_hdrs}) - if(PCHSupport_FOUND AND USE_PRECOMPILED_HEADERS) - set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/test/test_precomp.hpp) - if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*") - if(${CMAKE_GENERATOR} MATCHES "Visual*") - set(${the_target}_pch "test/test_precomp.cpp") - endif() - add_native_precompiled_header(${the_target} ${pch_header}) - elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles") - add_precompiled_header(${the_target} ${pch_header}) - endif() - endif() + add_opencv_precompiled_headers(${the_target}) # Additional target properties set_target_properties(${the_target} PROPERTIES DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" ) - + if(ENABLE_SOLUTION_FOLDERS) set_target_properties(${the_target} PROPERTIES FOLDER "tests") endif() @@ -165,5 +162,5 @@ macro(define_opencv_module name) # install(TARGETS ${the_target} RUNTIME DESTINATION bin COMPONENT main) #endif() endif() - + endmacro() diff --git a/OpenCVPCHSupport.cmake b/OpenCVPCHSupport.cmake index b72783fa80..0955255dad 100644 --- a/OpenCVPCHSupport.cmake +++ b/OpenCVPCHSupport.cmake @@ -15,234 +15,234 @@ IF(CMAKE_COMPILER_IS_GNUCXX) EXEC_PROGRAM( - ${CMAKE_CXX_COMPILER} - ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion + ${CMAKE_CXX_COMPILER} + ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion OUTPUT_VARIABLE gcc_compiler_version) #MESSAGE("GCC Version: ${gcc_compiler_version}") IF(gcc_compiler_version MATCHES "4\\.[0,2-9]\\.[0-9]") SET(PCHSupport_FOUND TRUE) ENDIF() - SET(_PCH_include_prefix "-I") + SET(_PCH_include_prefix "-I") +ELSEIF(WIN32) + SET(PCHSupport_FOUND TRUE) # for experimental msvc support + SET(_PCH_include_prefix "/I") ELSE() - IF(WIN32) - SET(PCHSupport_FOUND TRUE) # for experimental msvc support - SET(_PCH_include_prefix "/I") - ELSE() - SET(PCHSupport_FOUND FALSE) - ENDIF() -ENDIF(CMAKE_COMPILER_IS_GNUCXX) + SET(PCHSupport_FOUND FALSE) +ENDIF() MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags) + STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name) + SET(${_out_compile_flags} ${${_flags_var_name}} ) - STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name) - SET(${_out_compile_flags} ${${_flags_var_name}} ) + IF(CMAKE_COMPILER_IS_GNUCXX) - IF(CMAKE_COMPILER_IS_GNUCXX) + GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) + IF(${_targetType} STREQUAL SHARED_LIBRARY AND NOT WIN32) + LIST(APPEND ${_out_compile_flags} "-fPIC") + ENDIF() - GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) - IF(${_targetType} STREQUAL SHARED_LIBRARY AND NOT WIN32) - LIST(APPEND ${_out_compile_flags} "${${_out_compile_flags}} -fPIC") + ELSE() + ## TODO ... ? or does it work out of the box ENDIF() - ELSE() - ## TODO ... ? or does it work out of the box - ENDIF() + GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES ) + FOREACH(item ${DIRINC}) + LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}\"${item}\"") + ENDFOREACH(item) - GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES ) - FOREACH(item ${DIRINC}) - LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}${item}") - ENDFOREACH(item) + GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS) + GET_DIRECTORY_PROPERTY(_global_definitions DIRECTORY ${OpenCV_SOURCE_DIR} DEFINITIONS) + #MESSAGE("_directory_flags ${_directory_flags} ${_global_definitions}" ) + LIST(APPEND ${_out_compile_flags} ${_directory_flags}) + LIST(APPEND ${_out_compile_flags} ${_global_definitions}) + LIST(APPEND ${_out_compile_flags} ${CMAKE_CXX_FLAGS}) - GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS) - GET_DIRECTORY_PROPERTY(_global_definitions DIRECTORY ${OpenCV_SOURCE_DIR} DEFINITIONS) - #MESSAGE("_directory_flags ${_directory_flags} ${_global_definitions}" ) - LIST(APPEND ${_out_compile_flags} ${_directory_flags}) - LIST(APPEND ${_out_compile_flags} ${_global_definitions}) - LIST(APPEND ${_out_compile_flags} ${CMAKE_CXX_FLAGS} ) - - SEPARATE_ARGUMENTS(${_out_compile_flags}) + SEPARATE_ARGUMENTS(${_out_compile_flags}) ENDMACRO(_PCH_GET_COMPILE_FLAGS) MACRO(_PCH_WRITE_PCHDEP_CXX _targetName _include_file _dephelp) - SET(${_dephelp} ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch_dephelp.cxx) - FILE(WRITE ${${_dephelp}} -"#include \"${_include_file}\" -int testfunction() -{ - return 0; -} -" - ) + SET(${_dephelp} ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch_dephelp.cxx) + IF(CMAKE_HOST_WIN32) + ADD_CUSTOM_COMMAND( + OUTPUT "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "#include \\\"${_include_file}\\\"" > "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "int testfunction()" >> "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "{" >> "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo " return 0;" >> "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "}" >> "${${_dephelp}}" + DEPENDS "${_include_file}" + ) + else() + ADD_CUSTOM_COMMAND( + OUTPUT "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "\\#include \\\"${_include_file}\\\"" > "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "int testfunction\\(\\)" >> "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "{" >> "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo " \\return 0\\;" >> "${${_dephelp}}" + COMMAND ${CMAKE_COMMAND} -E echo "}" >> "${${_dephelp}}" + DEPENDS "${_include_file}" + ) + endif() ENDMACRO(_PCH_WRITE_PCHDEP_CXX ) MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _output) - FILE(TO_NATIVE_PATH ${_input} _native_input) - FILE(TO_NATIVE_PATH ${_output} _native_output) + FILE(TO_NATIVE_PATH ${_input} _native_input) + FILE(TO_NATIVE_PATH ${_output} _native_output) - - IF(CMAKE_COMPILER_IS_GNUCXX) - IF(CMAKE_CXX_COMPILER_ARG1) - # remove leading space in compiler argument + IF(CMAKE_COMPILER_IS_GNUCXX) + IF(CMAKE_CXX_COMPILER_ARG1) + # remove leading space in compiler argument STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1}) - SET(${out_command} - ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input} - ) - ELSE(CMAKE_CXX_COMPILER_ARG1) - SET(${out_command} - ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input} - ) - ENDIF(CMAKE_CXX_COMPILER_ARG1) - ELSE(CMAKE_COMPILER_IS_GNUCXX) + SET(${out_command} + ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input} + ) + ELSE(CMAKE_CXX_COMPILER_ARG1) + SET(${out_command} + ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input} + ) + ENDIF(CMAKE_CXX_COMPILER_ARG1) + ELSE(CMAKE_COMPILER_IS_GNUCXX) - SET(_dummy_str "#include <${_input}>") - FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pch_dummy.cpp ${_dummy_str}) + SET(_dummy_str "#include <${_input}>") + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pch_dummy.cpp ${_dummy_str}) - SET(${out_command} - ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} /c /Fp${_native_output} /Yc${_native_input} pch_dummy.cpp - ) - #/out:${_output} + SET(${out_command} + ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} /c /Fp${_native_output} /Yc${_native_input} pch_dummy.cpp + ) + #/out:${_output} - ENDIF(CMAKE_COMPILER_IS_GNUCXX) + ENDIF(CMAKE_COMPILER_IS_GNUCXX) ENDMACRO(_PCH_GET_COMPILE_COMMAND ) - MACRO(_PCH_GET_TARGET_COMPILE_FLAGS _cflags _header_name _pch_path _dowarn ) - FILE(TO_NATIVE_PATH ${_pch_path} _native_pch_path) + FILE(TO_NATIVE_PATH ${_pch_path} _native_pch_path) - IF(CMAKE_COMPILER_IS_GNUCXX) - # for use with distcc and gcc >4.0.1 if preprocessed files are accessible - # on all remote machines set - # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess - # if you want warnings for invalid header files (which is very inconvenient - # if you have different versions of the headers for different build types - # you may set _pch_dowarn - IF (_dowarn) - SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include ${CMAKE_CURRENT_BINARY_DIR}/${_header_name} -Winvalid-pch " ) - ELSE (_dowarn) - SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include ${CMAKE_CURRENT_BINARY_DIR}/${_header_name} " ) - ENDIF (_dowarn) - ELSE(CMAKE_COMPILER_IS_GNUCXX) + IF(CMAKE_COMPILER_IS_GNUCXX) + # for use with distcc and gcc >4.0.1 if preprocessed files are accessible + # on all remote machines set + # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess + # if you want warnings for invalid header files (which is very inconvenient + # if you have different versions of the headers for different build types + # you may set _pch_dowarn + IF (_dowarn) + SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_header_name}\" -Winvalid-pch " ) + ELSE (_dowarn) + SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_header_name}\" " ) + ENDIF (_dowarn) - set(${_cflags} "/Fp${_native_pch_path} /Yu${_header_name}" ) + ELSE(CMAKE_COMPILER_IS_GNUCXX) - ENDIF(CMAKE_COMPILER_IS_GNUCXX) + set(${_cflags} "/Fp${_native_pch_path} /Yu${_header_name}" ) + + ENDIF(CMAKE_COMPILER_IS_GNUCXX) ENDMACRO(_PCH_GET_TARGET_COMPILE_FLAGS ) + MACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input _output) - GET_FILENAME_COMPONENT(_name ${_input} NAME) - GET_FILENAME_COMPONENT(_path ${_input} PATH) - SET(_output "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch/${_targetName}_${CMAKE_BUILD_TYPE}.gch") + + GET_FILENAME_COMPONENT(_name ${_input} NAME) + GET_FILENAME_COMPONENT(_path ${_input} PATH) + SET(${_output} "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch/${_targetName}_${CMAKE_BUILD_TYPE}.gch") + ENDMACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input) MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use ) - # to do: test whether compiler flags match between target _targetName - # and _pch_output_to_use - GET_FILENAME_COMPONENT(_name ${_input} NAME) + # to do: test whether compiler flags match between target _targetName + # and _pch_output_to_use + GET_FILENAME_COMPONENT(_name ${_input} NAME) - IF( "${ARGN}" STREQUAL "0") - SET(_dowarn 0) - ELSE( "${ARGN}" STREQUAL "0") - SET(_dowarn 1) - ENDIF("${ARGN}" STREQUAL "0") + IF(ARGN STREQUAL "0") + SET(_dowarn 0) + ELSE() + SET(_dowarn 1) + ENDIF() + _PCH_GET_TARGET_COMPILE_FLAGS(_target_cflags ${_name} ${_pch_output_to_use} ${_dowarn}) + #MESSAGE("Add flags ${_target_cflags} to ${_targetName} " ) + SET_TARGET_PROPERTIES(${_targetName} + PROPERTIES + COMPILE_FLAGS ${_target_cflags} + ) - _PCH_GET_TARGET_COMPILE_FLAGS(_target_cflags ${_name} ${_pch_output_to_use} ${_dowarn}) - # MESSAGE("Add flags ${_target_cflags} to ${_targetName} " ) - SET_TARGET_PROPERTIES(${_targetName} - PROPERTIES - COMPILE_FLAGS ${_target_cflags} - ) + ADD_CUSTOM_TARGET(pch_Generate_${_targetName} + DEPENDS ${_pch_output_to_use} + ) - ADD_CUSTOM_TARGET(pch_Generate_${_targetName} - DEPENDS ${_pch_output_to_use} - ) - - ADD_DEPENDENCIES(${_targetName} pch_Generate_${_targetName} ) + ADD_DEPENDENCIES(${_targetName} pch_Generate_${_targetName} ) ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET) MACRO(ADD_PRECOMPILED_HEADER _targetName _input) - SET(_PCH_current_target ${_targetName}) + SET(_PCH_current_target ${_targetName}) - IF(NOT CMAKE_BUILD_TYPE) - MESSAGE(FATAL_ERROR - "This is the ADD_PRECOMPILED_HEADER macro. " - "You must set CMAKE_BUILD_TYPE!" - ) - ENDIF(NOT CMAKE_BUILD_TYPE) + IF(NOT CMAKE_BUILD_TYPE) + MESSAGE(FATAL_ERROR + "This is the ADD_PRECOMPILED_HEADER macro. " + "You must set CMAKE_BUILD_TYPE!" + ) + ENDIF() - IF( "${ARGN}" STREQUAL "0") - SET(_dowarn 0) - ELSE( "${ARGN}" STREQUAL "0") - SET(_dowarn 1) - ENDIF("${ARGN}" STREQUAL "0") + IF(ARGN STREQUAL "0") + SET(_dowarn 0) + ELSE() + SET(_dowarn 1) + ENDIF() + GET_FILENAME_COMPONENT(_name ${_input} NAME) + GET_FILENAME_COMPONENT(_path ${_input} PATH) + GET_PRECOMPILED_HEADER_OUTPUT( ${_targetName} ${_input} _output) - GET_FILENAME_COMPONENT(_name ${_input} NAME) - GET_FILENAME_COMPONENT(_path ${_input} PATH) - GET_PRECOMPILED_HEADER_OUTPUT( ${_targetName} ${_input} _output) + _PCH_WRITE_PCHDEP_CXX(${_targetName} "${_input}" _pch_dephelp_cxx) - GET_FILENAME_COMPONENT(_outdir ${_output} PATH ) - - GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) - _PCH_WRITE_PCHDEP_CXX(${_targetName} ${_input} _pch_dephelp_cxx) - - IF(${_targetType} STREQUAL SHARED_LIBRARY) - ADD_LIBRARY(${_targetName}_pch_dephelp STATIC ${_pch_dephelp_cxx} ) - ELSE(${_targetType} STREQUAL SHARED_LIBRARY) - ADD_LIBRARY(${_targetName}_pch_dephelp STATIC ${_pch_dephelp_cxx}) - ENDIF(${_targetType} STREQUAL SHARED_LIBRARY) + ADD_LIBRARY(${_targetName}_pch_dephelp STATIC "${_pch_dephelp_cxx}" "${_input}" ) - set_target_properties(${_targetName}_pch_dephelp PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/" - ) + set_target_properties(${_targetName}_pch_dephelp PROPERTIES + DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" + ARCHIVE_OUTPUT_DIRECTORY "${LIBRARY_OUTPUT_PATH}" + ) + _PCH_GET_COMPILE_FLAGS(_compile_FLAGS) - FILE(MAKE_DIRECTORY ${_outdir}) + #MESSAGE("_compile_FLAGS: ${_compile_FLAGS}") + #message("COMMAND ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}") + + ADD_CUSTOM_COMMAND( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}" + COMMAND ${CMAKE_COMMAND} -E copy "${_input}" "${CMAKE_CURRENT_BINARY_DIR}/${_name}" # ensure same directory! Required by gcc + DEPENDS "${_input}" + ) + #message("_command ${_input} ${_output}") + _PCH_GET_COMPILE_COMMAND(_command ${CMAKE_CURRENT_BINARY_DIR}/${_name} ${_output} ) - _PCH_GET_COMPILE_FLAGS(_compile_FLAGS) + GET_FILENAME_COMPONENT(_outdir ${_output} PATH) + ADD_CUSTOM_COMMAND( + OUTPUT "${_output}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${_outdir}" + COMMAND ${_command} + DEPENDS "${_input}" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_name}" + DEPENDS ${_targetName}_pch_dephelp + ) - #MESSAGE("_compile_FLAGS: ${_compile_FLAGS}") - #message("COMMAND ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}") - SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${_name} PROPERTIES GENERATED 1) - ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_name} - COMMAND ${CMAKE_COMMAND} -E copy ${_input} ${CMAKE_CURRENT_BINARY_DIR}/${_name} # ensure same directory! Required by gcc - DEPENDS ${_input} - ) - - #message("_command ${_input} ${_output}") - _PCH_GET_COMPILE_COMMAND(_command ${CMAKE_CURRENT_BINARY_DIR}/${_name} ${_output} ) - - #message(${_input} ) - #message("_output ${_output}") - - ADD_CUSTOM_COMMAND( - OUTPUT ${_output} - COMMAND ${_command} - DEPENDS ${_input} ${CMAKE_CURRENT_BINARY_DIR}/${_name} ${_targetName}_pch_dephelp - ) - - - ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_input} ${_output} ${_dowarn}) + ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_input} ${_output} ${_dowarn}) + ENDMACRO(ADD_PRECOMPILED_HEADER) @@ -253,72 +253,66 @@ ENDMACRO(ADD_PRECOMPILED_HEADER) MACRO(GET_NATIVE_PRECOMPILED_HEADER _targetName _input) - if(CMAKE_GENERATOR MATCHES Visual*) + if(CMAKE_GENERATOR MATCHES "^Visual.*$") + SET(_dummy_str "#include \"${_input}\"\n" +"// This is required to suppress LNK4221. Very annoying.\n" +"void *g_${_targetName}Dummy = 0\;\n") - SET(_dummy_str "#include \"${_input}\"\n" - "// This is required to suppress LNK4221. Very annoying.\n" - "void *g_${_targetName}Dummy = 0\;\n") - - # Use of cxx extension for generated files (as Qt does) - SET(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cxx) - if(EXISTS ${${_targetName}_pch}) - # Check if contents is the same, if not rewrite - # todo - else(EXISTS ${${_targetName}_pch}) - FILE(WRITE ${${_targetName}_pch} ${_dummy_str}) - endif(EXISTS ${${_targetName}_pch}) - endif(CMAKE_GENERATOR MATCHES Visual*) + # Use of cxx extension for generated files (as Qt does) + SET(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cxx) + if(EXISTS ${${_targetName}_pch}) + # Check if contents is the same, if not rewrite + # todo + else() + FILE(WRITE ${${_targetName}_pch} ${_dummy_str}) + endif() + endif() ENDMACRO(GET_NATIVE_PRECOMPILED_HEADER) MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input) - IF( "${ARGN}" STREQUAL "0") - SET(_dowarn 0) - ELSE( "${ARGN}" STREQUAL "0") - SET(_dowarn 1) - ENDIF("${ARGN}" STREQUAL "0") + IF(ARGN STREQUAL "0") + SET(_dowarn 0) + ELSE() + SET(_dowarn 1) + ENDIF() - if(CMAKE_GENERATOR MATCHES Visual*) - # Auto include the precompile (useful for moc processing, since the use of - # precompiled is specified at the target level - # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt) + if(CMAKE_GENERATOR MATCHES "^Visual.*$") + + # Auto include the precompile (useful for moc processing, since the use of + # precompiled is specified at the target level + # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt) - GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) - if (${oldProps} MATCHES NOTFOUND) - SET(oldProps "") - endif(${oldProps} MATCHES NOTFOUND) + GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) + if (oldProps MATCHES NOTFOUND) + SET(oldProps "") + endif() - SET(newProperties "${oldProps} /Yu\"${_input}\" /FI\"${_input}\"") - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}") + SET(newProperties "${oldProps} /Yu\"${_input}\" /FI\"${_input}\"") + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}") - #also inlude ${oldProps} to have the same compile options - SET_SOURCE_FILES_PROPERTIES(${${_targetName}_pch} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_input}\"") + #also inlude ${oldProps} to have the same compile options + SET_SOURCE_FILES_PROPERTIES(${${_targetName}_pch} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_input}\"") - else(CMAKE_GENERATOR MATCHES Visual*) + elseif (CMAKE_GENERATOR MATCHES Xcode) + + # For Xcode, cmake needs my patch to process + # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties - if (CMAKE_GENERATOR MATCHES Xcode) - # For Xcode, cmake needs my patch to process - # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties + # When buiding out of the tree, precompiled may not be located + # Use full path instead. + GET_FILENAME_COMPONENT(fullPath ${_input} ABSOLUTE) - GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) - if (${oldProps} MATCHES NOTFOUND) - SET(oldProps "") - endif(${oldProps} MATCHES NOTFOUND) + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}") + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") - # When buiding out of the tree, precompiled may not be located - # Use full path instead. - GET_FILENAME_COMPONENT(fullPath ${_input} ABSOLUTE) + else() - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}") - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") + #Fallback to the "old" precompiled suppport + #ADD_PRECOMPILED_HEADER(${_targetName} ${_input} ${_dowarn}) - else (CMAKE_GENERATOR MATCHES Xcode) - - #Fallback to the "old" precompiled suppport - #ADD_PRECOMPILED_HEADER(${_targetName} ${_input} ${_dowarn}) - endif(CMAKE_GENERATOR MATCHES Xcode) - endif(CMAKE_GENERATOR MATCHES Visual*) + endif() ENDMACRO(ADD_NATIVE_PRECOMPILED_HEADER) diff --git a/Package.cmake.in b/Package.cmake.in deleted file mode 100644 index f97868d241..0000000000 --- a/Package.cmake.in +++ /dev/null @@ -1,111 +0,0 @@ -# -# CPack template for OpenCV -# -# (c) Copyrights 2008 Hartmut Seichter, HIT Lab NZ -# - -if(MSVC) - set(CMAKE_INSTALL_DEBUG_LIBRARIES 1) -endif() -#if(ENABLE_OPENMP) -# set(CMAKE_INSTALL_OPENMP_LIBRARIES 1) -#endif() -include(InstallRequiredSystemLibraries) - -set(CPACK_PACKAGE_NAME "OpenCV") -set(CPACK_PACKAGE_VENDOR "OpenCV project opencvlibrary.sourceforge.net") - -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenCV SDK for ${CMAKE_GENERATOR} is an All-In-One package for developing computer vision applications") - -#set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README") -set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/doc/license.txt") - -set(CPACK_PACKAGE_VERSION_MAJOR "${OPENCV_VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${OPENCV_VERSION_MINOR}") -set(CPACK_PACKAGE_VERSION_PATCH "${OPENCV_VERSION_PATCH}") - -set(CPACK_PACKAGE_INSTALL_DIRECTORY "OpenCV${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}") - -set(CPACK_PACKAGE_EXECUTABLES "") - -set(CPACK_COMPONENTS_ALL main src Unspecified) - -set(CPACK_COMPONENT_main_DISPLAY_NAME "Binaries and the Documentation") -set(CPACK_COMPONENT_src_DISPLAY_NAME "The source code") -#set(CPACK_COMPONENT_py_DISPLAY_NAME "Python Bindings") - -set(CPACK_ALL_INSTALL_TYPES Full) - -set(CPACK_COMPONENT_MAIN_INSTALL_TYPES Full) -set(CPACK_COMPONENT_SRC_INSTALL_TYPES Full) -#set(CPACK_COMPONENT_py_INSTALL_TYPES Full) - -set(CPACK_SOURCE_IGNORE_FILES - "/\\\\.svn/" - "/autom4te.cache/" - "/build/" - "/interfaces/" - "/swig_python/" - "/octave/" - "/gtest/" - "~$" - "\\\\.aux$" - "\\\\.bbl$" - "\\\\.blg$" - "\\\\.idx$" - "\\\\.ilg$" - "\\\\.ind$" - "\\\\.log$" - "\\\\.toc$" - "\\\\.out$" - "\\\\.pyc$" - "\\\\.pyo$" - "\\\\.vcproj$" - "/1$" - "${CPACK_SOURCE_IGNORE_FILES}") - -if(NOT WIN32) - set(CPACK_SOURCE_IGNORE_FILES - "/lib/" - "\\\\.dll$" - "${CPACK_SOURCE_IGNORE_FILES}") -endif() - -set(CPACK_SOURCE_PACKAGE_FILE_NAME - "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") - -if(WIN32) - set(CPACK_GENERATOR "NSIS") - set(CPACK_SOURCE_GENERATOR "ZIP") - set(CPACK_NSIS_PACKAGE_NAME "OpenCV ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}rc") - set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}\\\\doc\\\\opencv.ico") - set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}\\\\doc\\\\opencv.ico") - #set(CPACK_PACKAGE_ICON "utils/opencv.ico") - - set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_SOURCE_DIR}\\\\doc\\\\opencv.ico") - set(CPACK_NSIS_HELP_LINK "http:\\\\\\\\opencv.willowgarage.com") - set(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\opencv.willowgarage.com") - set(CPACK_NSIS_CONTACT "") - set(CPACK_NSIS_DISPLAY_NAME "Open Source Computer Vision Library") - - set(CPACK_NSIS_MENU_LINKS - "http://opencv.willowgarage.com" "Start Page" - "doc\\\\opencv2refman.pdf" "The OpenCV Reference Manual" - "doc\\\\opencv_tutorials.pdf" "The OpenCV Tutorials for Beginners" - "CMakeLists.txt" "The Build Script (open with CMake)" - "samples\\\\c" "C Samples" - "samples\\\\cpp" "C++ Samples" - "samples\\\\python" "Python Samples") - - # Add "/bin" to the system PATH - set(CPACK_NSIS_MODIFY_PATH ON) -else() - set(CPACK_GENERATOR "TBZ2") - set(CPACK_SOURCE_GENERATOR "TBZ2") - - if(APPLE) - set(CPACK_GENERATOR "PackageMaker;TBZ2") - endif() -endif() - -include(CPack) diff --git a/android/CMakeCache.android.initial.cmake b/android/CMakeCache.android.initial.cmake index e6b86d3484..b934915056 100644 --- a/android/CMakeCache.android.initial.cmake +++ b/android/CMakeCache.android.initial.cmake @@ -3,20 +3,6 @@ # run cmake with: # cmake -C ######################## -#Build all examples -set(BUILD_EXAMPLES OFF CACHE BOOL "" ) - -#Build Reference Manual -set(BUILD_REFMAN OFF CACHE BOOL "" ) - -#Build LaTeX OpenCV Documentation -#set(BUILD_LATEX_DOCS OFF CACHE BOOL "" ) - -#Build with Python support -set(BUILD_NEW_PYTHON_SUPPORT OFF CACHE BOOL "" ) - -#Build a installer with the SDK -set(BUILD_PACKAGE OFF CACHE BOOL "" ) #Build shared libraries (.dll/.so CACHE BOOL "" ) instead of static ones (.lib/.a CACHE BOOL "" ) set(BUILD_SHARED_LIBS OFF CACHE BOOL "" ) @@ -24,8 +10,7 @@ set(BUILD_SHARED_LIBS OFF CACHE BOOL "" ) #Build 3rd party libraries set(OPENCV_BUILD_3RDPARTY_LIBS ON CACHE BOOL "" ) -#Choose the type of build, options are: None Debug Release RelWithDebInfo -# MinSizeRel. +#Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel. set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" ) #Include IEEE1394 support @@ -88,6 +73,9 @@ set(WITH_V4L OFF CACHE BOOL "" ) #Include Xine support (GPL CACHE BOOL "" ) set(WITH_XINE OFF CACHE BOOL "" ) +#no python available on Android +set(BUILD_NEW_PYTHON_SUPPORT OFF CACHE INTERNAL "" FORCE) + #Enable SSE instructions SET( ENABLE_SSE OFF CACHE INTERNAL "" FORCE ) @@ -106,5 +94,5 @@ SET( ENABLE_SSE42 OFF CACHE INTERNAL "" FORCE ) #Enable SSSE3 instructions SET( ENABLE_SSSE3 OFF CACHE INTERNAL "" FORCE ) -#Set output folder to "libs" instead of "lib" for better compatibility with java projects -SET( LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/libs CACHE PATH "path for android libs" ) +#Set output folder to ${CMAKE_BINARY_DIR} +set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_BINARY_DIR} CACHE PATH "root for library output, set this to change where android libs are compiled to" ) diff --git a/android/README.android b/android/README.android index 401a10a143..b9c688096d 100644 --- a/android/README.android +++ b/android/README.android @@ -1 +1 @@ -See http://opencv.willowgarage.com/wiki/Android2.3 +See http://opencv.willowgarage.com/wiki/Android diff --git a/android/android-opencv/AndroidManifest.xml b/android/android-opencv/AndroidManifest.xml deleted file mode 100644 index 8d3efb0fd7..0000000000 --- a/android/android-opencv/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/android-opencv/AndroidOpenCVConfig.cmake.in b/android/android-opencv/AndroidOpenCVConfig.cmake.in deleted file mode 100644 index 53cdfc2cc3..0000000000 --- a/android/android-opencv/AndroidOpenCVConfig.cmake.in +++ /dev/null @@ -1,44 +0,0 @@ -# ============================================================================ -# The AndroidOpenCV CMake configuration file -# -# ** File generated automatically, do not modify ** -# -# Usage from an external project: -# In your CMakeLists.txt, add these lines: -# -# FIND_PACKAGE(AndroidOpenCV REQUIRED ) -# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${AndroidOpenCV_LIBS}) -# -# This file will define the following variables: -# - AndroidOpenCV_LIBS : The list of libraries to links against. -# - AndroidOpenCV_LIB_DIR : The directory where lib files are. -# Calling LINK_DIRECTORIES with this path -# is NOT needed. -# - AndroidOpenCV_INCLUDE_DIRS : The AndroidOpenCV include directories. -# - AndroidOpenCV_SWIG_DIR : The swig path -# -# =========================================================================== - - -# ====================================================== -# Include directories to add to the user project: -# ====================================================== - -# Provide the include directories to the caller -SET(AndroidOpenCV_INCLUDE_DIRS @CMAKE_INCLUDE_DIRS_CONFIGCMAKE@) -INCLUDE_DIRECTORIES(${AndroidOpenCV_INCLUDE_DIRS}) - -# ====================================================== -# Link directories to add to the user project: -# ====================================================== - -# Provide the libs directory anyway, it may be needed in some cases. -SET(AndroidOpenCV_LIB_DIR @CMAKE_LIB_DIRS_CONFIGCMAKE@) -LINK_DIRECTORIES(${AndroidOpenCV_LIB_DIR}) - -# ====================================================== -# Libraries to add to the user project: -# ====================================================== -SET(AndroidOpenCV_LIBS @CMAKE_LIBS_CONFIGCMAKE@) - -SET(AndroidOpenCV_SWIG_DIR @CMAKE_SWIG_DIR_CONFIGCMAKE@) diff --git a/android/android-opencv/CMakeLists.txt b/android/android-opencv/CMakeLists.txt deleted file mode 100644 index 27377666e2..0000000000 --- a/android/android-opencv/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(android-jni) - -add_subdirectory(jni) diff --git a/android/android-opencv/README.txt b/android/android-opencv/README.txt deleted file mode 100644 index 8082add891..0000000000 --- a/android/android-opencv/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -========================================= -CMake Build -========================================= -#path to the android build of opencv -opencv_dir=`pwd`/../build -mkdir build -cd build -cmake -DOpenCV_DIR=$opencv_dir -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN .. - -========================================= -Android Build -========================================= -sh project_create.sh -ant compile - diff --git a/android/android-opencv/cmake_android.cmd b/android/android-opencv/cmake_android.cmd deleted file mode 100644 index fdb8e45969..0000000000 --- a/android/android-opencv/cmake_android.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@ECHO OFF -SETLOCAL -PUSHD %~dp0 -SET PROJECT_NAME=android-opencv -CALL ..\scripts\build.cmd %* -POPD -ENDLOCAL \ No newline at end of file diff --git a/android/android-opencv/cmake_android.sh b/android/android-opencv/cmake_android.sh deleted file mode 100644 index 3e90e33076..0000000000 --- a/android/android-opencv/cmake_android.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -cd `dirname $0` - -opencv_build_dir=`pwd`/../build -mkdir -p build -cd build - -cmake -DOpenCVDIR=$opencv_build_dir -DCMAKE_TOOLCHAIN_FILE=../../android.toolchain.cmake .. - diff --git a/android/android-opencv/cmake_android_neon.sh b/android/android-opencv/cmake_android_neon.sh deleted file mode 100644 index 56c14923c6..0000000000 --- a/android/android-opencv/cmake_android_neon.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -cd `dirname $0` - -opencv_build_dir=`pwd`/../build_neon -mkdir -p build_neon -cd build_neon - -cmake -DOpenCVDIR=$opencv_build_dir -DARM_TARGET="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=../../android.toolchain.cmake .. diff --git a/android/android-opencv/jni/CMakeLists.txt b/android/android-opencv/jni/CMakeLists.txt deleted file mode 100644 index 1f26f0de1a..0000000000 --- a/android/android-opencv/jni/CMakeLists.txt +++ /dev/null @@ -1,70 +0,0 @@ -######################################################### -# Find opencv and android-opencv -######################################################### - -set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../build - CACHE PATH "The path where you built opencv for android") -find_package(OpenCV REQUIRED) - -######################################################### -#c flags, included, and lib dependencies -######################################################### -#notice the "recycling" of CMAKE_C_FLAGS -#this is necessary to pick up android flags -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" ) - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/include) - -set( LIBRARY_DEPS ${OpenCV_LIBS} ) -if(ANDROID) - set( LIBRARY_DEPS ${LIBRARY_DEPS} log dl GLESv2) -endif(ANDROID) - -######################################################### -#SWIG STUFF -######################################################### -#the java package to place swig generated java files in -set(MY_PACKAGE com.opencv.jni) - -if(NOT ANDROID) - #non android swig and jni - #jni is available by default on android - find_package(JNI REQUIRED) - include_directories(${JNI_INCLUDE_DIRS}) - FIND_PACKAGE(SWIG) -endif() - -INCLUDE(${SWIG_USE_FILE}) #on android this is found by the cmake toolchain - -if(ANDROID) - #this will set the output path for the java package - #and properly create the package declarations in generated java sources - SET_SWIG_JAVA_PACKAGE( ${MY_PACKAGE} ) #defined in the android toolchain -endif(ANDROID) - -SET_SOURCE_FILES_PROPERTIES(android-cv.i PROPERTIES CPLUSPLUS ON) - -SWIG_ADD_MODULE(android-opencv java - android-cv.i - Calibration.cpp - gl_code.cpp - image_pool.cpp - yuv420sp2rgb.c - #yuv420rgb888c.c - #yuv420rgb888.s - yuv2rgb16tab.c - ) - -target_link_libraries(android-opencv ${LIBRARY_DEPS} ) - -################################################################### -# Setup the configure file for other's to link against. -################################################################### -set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE ${CMAKE_CURRENT_SOURCE_DIR}/include) -set(CMAKE_LIB_DIRS_CONFIGCMAKE ${LIBRARY_OUTPUT_PATH}) -set(CMAKE_LIBS_CONFIGCMAKE android-opencv) -set(CMAKE_SWIG_DIR_CONFIGCMAKE ${CMAKE_CURRENT_SOURCE_DIR}) -configure_file( "${CMAKE_SOURCE_DIR}/AndroidOpenCVConfig.cmake.in" - "${CMAKE_BINARY_DIR}/AndroidOpenCVConfig.cmake" - IMMEDIATE @ONLY) diff --git a/android/android-opencv/jni/Calibration.cpp b/android/android-opencv/jni/Calibration.cpp deleted file mode 100644 index 9ba8fa8ac0..0000000000 --- a/android/android-opencv/jni/Calibration.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Processor.cpp - * - * Created on: Jun 13, 2010 - * Author: ethan - */ - -#include "Calibration.h" - -#include - -using namespace cv; - -Calibration::Calibration() : - patternsize(6, 8) -{ - -} - -Calibration::~Calibration() -{ - -} - -namespace -{ -double computeReprojectionErrors(const vector >& objectPoints, - const vector >& imagePoints, const vector& rvecs, const vector< - Mat>& tvecs, const Mat& cameraMatrix, const Mat& distCoeffs, - vector& perViewErrors) -{ - vector imagePoints2; - int i, totalPoints = 0; - double totalErr = 0, err; - perViewErrors.resize(objectPoints.size()); - - for (i = 0; i < (int)objectPoints.size(); i++) - { - projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, distCoeffs, imagePoints2); - err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L1); - int n = (int)objectPoints[i].size(); - perViewErrors[i] = err / n; - totalErr += err; - totalPoints += n; - } - - return totalErr / totalPoints; -} - -void calcChessboardCorners(Size boardSize, float squareSize, vector& corners) -{ - corners.resize(0); - - for (int i = 0; i < boardSize.height; i++) - for (int j = 0; j < boardSize.width; j++) - corners.push_back(Point3f(float(j * squareSize), float(i * squareSize), 0)); -} - -/**from opencv/samples/cpp/calibration.cpp - * - */ -bool runCalibration(vector > imagePoints, Size imageSize, Size boardSize, float squareSize, - float aspectRatio, int flags, Mat& cameraMatrix, Mat& distCoeffs, vector& rvecs, - vector& tvecs, vector& reprojErrs, double& totalAvgErr) -{ - cameraMatrix = Mat::eye(3, 3, CV_64F); - if (flags & CV_CALIB_FIX_ASPECT_RATIO) - cameraMatrix.at (0, 0) = aspectRatio; - - distCoeffs = Mat::zeros(4, 1, CV_64F); - - vector > objectPoints(1); - calcChessboardCorners(boardSize, squareSize, objectPoints[0]); - for (size_t i = 1; i < imagePoints.size(); i++) - objectPoints.push_back(objectPoints[0]); - - calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags); - - bool ok = checkRange(cameraMatrix, CV_CHECK_QUIET) && checkRange(distCoeffs, CV_CHECK_QUIET); - - totalAvgErr - = computeReprojectionErrors(objectPoints, imagePoints, rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs); - - return ok; -} -void saveCameraParams(const string& filename, Size imageSize, Size boardSize, float squareSize, float aspectRatio, - int flags, const Mat& cameraMatrix, const Mat& distCoeffs, const vector& rvecs, - const vector& tvecs, const vector& reprojErrs, - const vector >& imagePoints, double totalAvgErr) -{ - FileStorage fs(filename, FileStorage::WRITE); - - time_t t; - time(&t); - struct tm *t2 = localtime(&t); - char buf[1024]; - strftime(buf, sizeof(buf) - 1, "%c", t2); - - fs << "calibration_time" << buf; - - if (!rvecs.empty() || !reprojErrs.empty()) - fs << "nframes" << (int)std::max(rvecs.size(), reprojErrs.size()); - fs << "image_width" << imageSize.width; - fs << "image_height" << imageSize.height; - fs << "board_width" << boardSize.width; - fs << "board_height" << boardSize.height; - fs << "squareSize" << squareSize; - - if (flags & CV_CALIB_FIX_ASPECT_RATIO) - fs << "aspectRatio" << aspectRatio; - - if (flags != 0) - { - sprintf(buf, "flags: %s%s%s%s", flags & CV_CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "", flags - & CV_CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "", flags & CV_CALIB_FIX_PRINCIPAL_POINT - ? "+fix_principal_point" : "", flags & CV_CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : ""); - cvWriteComment(*fs, buf, 0); - } - - fs << "flags" << flags; - - fs << "camera_matrix" << cameraMatrix; - fs << "distortion_coefficients" << distCoeffs; - - fs << "avg_reprojection_error" << totalAvgErr; - if (!reprojErrs.empty()) - fs << "per_view_reprojection_errors" << Mat(reprojErrs); - - if (!rvecs.empty() && !tvecs.empty()) - { - Mat bigmat(rvecs.size(), 6, CV_32F); - for (size_t i = 0; i < rvecs.size(); i++) - { - Mat r = bigmat(Range(i, i + 1), Range(0, 3)); - Mat t = bigmat(Range(i, i + 1), Range(3, 6)); - rvecs[i].copyTo(r); - tvecs[i].copyTo(t); - } - cvWriteComment(*fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0); - fs << "extrinsic_parameters" << bigmat; - } - - if (!imagePoints.empty()) - { - Mat imagePtMat(imagePoints.size(), imagePoints[0].size(), CV_32FC2); - for (size_t i = 0; i < imagePoints.size(); i++) - { - Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols); - Mat(imagePoints[i]).copyTo(r); - } - fs << "image_points" << imagePtMat; - } -} -}//anon namespace -bool Calibration::detectAndDrawChessboard(int idx, image_pool* pool) -{ - - bool patternfound = false; - Mat grey = pool->getGrey(idx); - if (grey.empty()) - return false; - vector corners; - - patternfound = findChessboardCorners(grey, patternsize, corners,CALIB_CB_FILTER_QUADS + CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE - + CALIB_CB_FAST_CHECK); - Mat img = pool->getImage(idx); - - if (corners.size() < 1) - return false; - - if (patternfound) - { - cornerSubPix(grey, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); - imagepoints.push_back(corners); - } - - drawChessboardCorners(img, patternsize, Mat(corners), patternfound); - - imgsize = grey.size(); - - return patternfound; - -} - -void Calibration::drawText(int i, image_pool* pool, const char* ctext) -{ - // Use "y" to show that the baseLine is about - string text = ctext; - int fontFace = FONT_HERSHEY_COMPLEX_SMALL; - double fontScale = .8; - int thickness = .5; - - Mat img = pool->getImage(i); - - int baseline = 0; - Size textSize = getTextSize(text, fontFace, fontScale, thickness, &baseline); - baseline += thickness; - - // center the text - Point textOrg((img.cols - textSize.width) / 2, (img.rows - textSize.height * 2)); - - // draw the box - rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0, 0, 255), - CV_FILLED); - // ... and the baseline first - line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255)); - - // then put the text itself - putText(img, text, textOrg, fontFace, fontScale, Scalar::all(255), thickness, 8); -} - -void Calibration::resetChess() -{ - - imagepoints.clear(); -} - -void Calibration::calibrate(const char* filename) -{ - - vector rvecs, tvecs; - vector reprojErrs; - double totalAvgErr = 0; - int flags = 0; - flags |= CV_CALIB_FIX_PRINCIPAL_POINT | CV_CALIB_FIX_ASPECT_RATIO; - bool writeExtrinsics = true; - bool writePoints = true; - - bool ok = runCalibration(imagepoints, imgsize, patternsize, 1.f, 1.f, flags, K, distortion, rvecs, tvecs, reprojErrs, - totalAvgErr); - - if (ok) - { - - saveCameraParams(filename, imgsize, patternsize, 1.f, 1.f, flags, K, distortion, writeExtrinsics ? rvecs : vector< - Mat> (), writeExtrinsics ? tvecs : vector (), writeExtrinsics ? reprojErrs : vector (), writePoints - ? imagepoints : vector > (), totalAvgErr); - } - -} - -int Calibration::getNumberDetectedChessboards() -{ - return imagepoints.size(); -} diff --git a/android/android-opencv/jni/Calibration.i b/android/android-opencv/jni/Calibration.i deleted file mode 100644 index ba6154b3c7..0000000000 --- a/android/android-opencv/jni/Calibration.i +++ /dev/null @@ -1,28 +0,0 @@ -/* - * include the headers required by the generated cpp code - */ -%{ -#include "Calibration.h" -#include "image_pool.h" -using namespace cv; -%} - - -class Calibration { -public: - - Size patternsize; - - Calibration(); - virtual ~Calibration(); - - bool detectAndDrawChessboard(int idx, image_pool* pool); - - void resetChess(); - - int getNumberDetectedChessboards(); - - void calibrate(const char* filename); - - void drawText(int idx, image_pool* pool, const char* text); -}; diff --git a/android/android-opencv/jni/android-cv-typemaps.i b/android/android-opencv/jni/android-cv-typemaps.i deleted file mode 100644 index cae2d6b63b..0000000000 --- a/android/android-opencv/jni/android-cv-typemaps.i +++ /dev/null @@ -1,6 +0,0 @@ -%feature("director") Mat; -%feature("director") glcamera; -%feature("director") image_pool; -%typemap("javapackage") Mat, Mat *, Mat & "com.opencv.jni"; -%typemap("javapackage") glcamera, glcamera *, glcamera & "com.opencv.jni"; -%typemap("javapackage") image_pool, image_pool *, image_pool & "com.opencv.jni"; \ No newline at end of file diff --git a/android/android-opencv/jni/android-cv.i b/android/android-opencv/jni/android-cv.i deleted file mode 100644 index f6661aa698..0000000000 --- a/android/android-opencv/jni/android-cv.i +++ /dev/null @@ -1,58 +0,0 @@ -/* File : android-cv.i - -import this file, and make sure to add the System.loadlibrary("android-opencv") -before loading any lib that depends on this. - */ - -%module opencv -%{ -#include "image_pool.h" -#include "glcamera.h" -using namespace cv; -%} -#ifndef SWIGIMPORTED -%include "various.i" -%include "typemaps.i" -%include "arrays_java.i" -#endif - -/** - * Make all the swig pointers public, so that - * external libraries can refer to these, otherwise they default to - * protected... - */ -%typemap(javabody) SWIGTYPE %{ - private long swigCPtr; - protected boolean swigCMemOwn; - public $javaclassname(long cPtr, boolean cMemoryOwn) { - swigCMemOwn = cMemoryOwn; - swigCPtr = cPtr; - } - public static long getCPtr($javaclassname obj) { - return (obj == null) ? 0 : obj.swigCPtr; - } -%} - - -%pragma(java) jniclasscode=%{ - static { - try { - //load the library, make sure that libandroid-opencv.so is in your /libs/armeabi directory - //so that android sdk automatically installs it along with the app. - System.loadLibrary("android-opencv"); - } catch (UnsatisfiedLinkError e) { - //badness - throw e; - - } - } -%} - - -%include "cv.i" - -%include "glcamera.i" - -%include "image_pool.i" - -%include "Calibration.i" diff --git a/android/android-opencv/jni/buffers.i b/android/android-opencv/jni/buffers.i deleted file mode 100644 index 42cca9cecf..0000000000 --- a/android/android-opencv/jni/buffers.i +++ /dev/null @@ -1,165 +0,0 @@ -/* - * These typemaps provide support for sharing data between JNI and JVM code - * using NIO direct buffers. It is the responsibility of the JVM code to - * allocate a direct buffer of the appropriate size. - * - * Example use: - - * Wrapping: - * %include "buffers.i" - * %apply int* BUFF {int* buffer} - * int read_foo_int(int* buffer); - * - * Java: - * IntBuffer buffer = IntBuffer.allocateDirect(nInts*4).order(ByteOrder.nativeOrder()).asIntBuffer(); - * Example.read_foo_int(buffer); - * - - * The following typemaps are defined: - * void* BUFF <--> javax.nio.Buffer - * char* BUFF <--> javax.nio.ByteBuffer - * char* CBUFF <--> javax.nio.CharBuffer - * unsigned char* INBUFF/OUTBUFF <--> javax.nio.ShortBuffer - * short* BUFF <--> javax.nio.ShortBuffer - * unsigned short* INBUFF/OUTBUFF <--> javax.nio.IntBuffer - * int* BUFF <--> javax.nio.IntBuffer - * unsigned int* INBUFF/OUTBUFF <--> javax.nio.LongBuffer - * long* BUFF <--> javax.nio.IntBuffer - * unsigned long* INBUFF/OUTBUF <--> javax.nio.LongBuffer - * long long* BUFF <--> javax.nio.LongBuffer - * float* BUFF <--> javax.nio.FloatBuffer - * double* BUFF <--> javax.nio.DoubleBuffer - * - * Note the potential for data loss in the conversion from - * the C type 'unsigned long' to the signed Java long type. - * Hopefully, I can implement a workaround with BigNumber in the future. - * - * The use of ByteBuffer vs CharBuffer for the char* type should - * depend on the type of data. In general you'll probably - * want to use CharBuffer for actual text data. - */ -/* - * This macro is used to define the nio buffers for primitive types. - */ -%define NIO_BUFFER_TYPEMAP(CTYPE, LABEL, BUFFERTYPE) -%typemap(jni) CTYPE* LABEL "jobject" -%typemap(jtype) CTYPE* LABEL "BUFFERTYPE" -%typemap(jstype) CTYPE* LABEL "BUFFERTYPE" -%typemap(javain, - pre=" assert $javainput.isDirect() : \"Buffer must be allocated direct.\";") CTYPE* LABEL "$javainput" -%typemap(javaout) CTYPE* LABEL { - return $jnicall; -} -%typemap(in) CTYPE* LABEL { - $1 = (CTYPE*)(jenv)->GetDirectBufferAddress( $input); - if ($1 == NULL) { - SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); - } -} -%typemap(memberin) CTYPE* LABEL { - if ($input) { - $1 = $input; - } else { - $1 = 0; - } -} -%typemap(freearg) CTYPE* LABEL "" -%enddef - -NIO_BUFFER_TYPEMAP(void, BUFF, java.nio.Buffer); -NIO_BUFFER_TYPEMAP(char, BUFF, java.nio.ByteBuffer); -NIO_BUFFER_TYPEMAP(char, CBUFF, java.nio.CharBuffer); -/*NIO_BUFFER_TYPEMAP(unsigned char, BUFF, java.nio.ShortBuffer);*/ -NIO_BUFFER_TYPEMAP(short, BUFF, java.nio.ShortBuffer); -NIO_BUFFER_TYPEMAP(unsigned short, BUFF, java.nio.IntBuffer); -NIO_BUFFER_TYPEMAP(int, BUFF, java.nio.IntBuffer); -NIO_BUFFER_TYPEMAP(unsigned int, BUFF, java.nio.LongBuffer); -NIO_BUFFER_TYPEMAP(long, BUFF, java.nio.IntBuffer); -NIO_BUFFER_TYPEMAP(unsigned long, BUFF, java.nio.LongBuffer); -NIO_BUFFER_TYPEMAP(long long, BUFF, java.nio.LongBuffer); -NIO_BUFFER_TYPEMAP(float, BUFF, java.nio.FloatBuffer); -NIO_BUFFER_TYPEMAP(double, BUFF, java.nio.DoubleBuffer); -#undef NIO_BUFFER_TYPEMAP - - -%define UNSIGNED_NIO_BUFFER_TYPEMAP(CTYPE, BSIZE, BUFFERTYPE, PACKFCN, UNPACKFCN) -%typemap(jni) CTYPE* INBUFF "jobject" -%typemap(jtype) CTYPE* INBUFF "java.nio.ByteBuffer" -%typemap(jstype) CTYPE* INBUFF "BUFFERTYPE" -%typemap(javain, - pre=" java.nio.ByteBuffer tmp$javainput = PACKFCN($javainput, true);") CTYPE* INBUFF "tmp$javainput" -%typemap(javaout) CTYPE* INBUFF { - return $jnicall; -} -%typemap(in) CTYPE* INBUFF { - $1 = (jenv)->GetDirectBufferAddress($input); - if ($1 == NULL) { - SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); - } -} -%typemap(memberin) CTYPE* INBUFF { - if ($input) { - $1 = $input; - } else { - $1 = 0; - } -} -%typemap(freearg) CTYPE* INBUFF "" - -%typemap(jni) CTYPE* OUTBUFF "jobject" -%typemap(jtype) CTYPE* OUTBUFF "java.nio.ByteBuffer" -%typemap(jstype) CTYPE* OUTBUFF "BUFFERTYPE" -%typemap(javain, - pre=" java.nio.ByteBuffer tmp$javainput = java.nio.ByteBuffer.allocateDirect($javainput.capacity()*BSIZE).order($javainput.order());", - post=" UNPACKFCN(tmp$javainput, $javainput);") CTYPE* OUTBUFF "tmp$javainput" -%typemap(javaout) CTYPE* OUTBUFF { - return $jnicall; -} -%typemap(in) CTYPE* OUTBUFF { - $1 = (jenv)->GetDirectBufferAddress( $input); - if ($1 == NULL) { - SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); - } -} -%typemap(memberin) CTYPE* OUTBUFF { - if ($input) { - $1 = $input; - } else { - $1 = 0; - } -} -%typemap(freearg) CTYPE* OUTBUFF "" -%enddef - -UNSIGNED_NIO_BUFFER_TYPEMAP(unsigned char, 1, java.nio.ShortBuffer, permafrost.hdf.libhdf.BufferUtils.packUChar, permafrost.hdf.libhdf.BufferUtils.unpackUChar); -UNSIGNED_NIO_BUFFER_TYPEMAP(unsigned short, 2, java.nio.IntBuffer, permafrost.hdf.libhdf.BufferUtils.packUShort, permafrost.hdf.libhdf.BufferUtils.unpackUShort); -UNSIGNED_NIO_BUFFER_TYPEMAP(unsigned int, 4, java.nio.LongBuffer, permafrost.hdf.libhdf.BufferUtils.packUInt, permafrost.hdf.libhdf.BufferUtils.unpackUInt); -UNSIGNED_NIO_BUFFER_TYPEMAP(unsigned long, 4, java.nio.LongBuffer, permafrost.hdf.libhdf.BufferUtils.packUInt, permafrost.hdf.libhdf.BufferUtils.unpackUInt); - -/* -%typemap(jni) unsigned char* BUFF "jobject" -%typemap(jtype) unsigned char* BUFF "java.nio.ByteBuffer" -%typemap(jstype) unsigned char* BUFF "java.nio.ShortBuffer" -%typemap(javain, - pre=" java.nio.ByteBuffer tmp$javainput = permafrost.hdf.libhdf.BufferUtils.packUChar($javainput, true);", - post=" permafrost.hdf.libhdf.BufferUtils.unpackUChar(tmp$javainput, $javainput);") unsigned char* BUFF "tmp$javainput" -%typemap(javaout) unsigned char* BUFF { - return $jnicall; -} -%typemap(in) unsigned char* BUFF { - $1 = (const char*)(jenv)->GetDirectBufferAddress( $input); - if ($1 == NULL) { - SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); - } -} -%typemap(memberin) unsigned char* BUFF { - if ($input) { - $1 = $input; - } else { - $1 = 0; - } -} -%typemap(freearg) unsigned char* BUFF "" -*/ - -#undef UNSIGNED_NIO_BUFFER_TYPEMAP \ No newline at end of file diff --git a/android/android-opencv/jni/cv.i b/android/android-opencv/jni/cv.i deleted file mode 100644 index 167d55d137..0000000000 --- a/android/android-opencv/jni/cv.i +++ /dev/null @@ -1,156 +0,0 @@ -%typemap(javaimports) Mat " -/** Wrapper for the OpenCV Mat object. Good for passing around as a pointer to a Mat. -*/" - -%typemap(javaimports) Size " -/** Wrapper for the OpenCV Size object. Good for setting dimensions of cv::Mat... -*/" - - -class Size{ -public: - Size(); - Size(int width,int height); - ~Size(); - int width; - int height; -}; - -#define CV_CN_MAX 512 -#define CV_CN_SHIFT 3 -#define CV_DEPTH_MAX (1 << CV_CN_SHIFT) - -#define CV_8U 0 -#define CV_8S 1 -#define CV_16U 2 -#define CV_16S 3 -#define CV_32S 4 -#define CV_32F 5 -#define CV_64F 6 -#define CV_USRTYPE1 7 - -#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) -#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) - -#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) -#define CV_MAKE_TYPE CV_MAKETYPE - -#define CV_8UC1 CV_MAKETYPE(CV_8U,1) -#define CV_8UC2 CV_MAKETYPE(CV_8U,2) -#define CV_8UC3 CV_MAKETYPE(CV_8U,3) -#define CV_8UC4 CV_MAKETYPE(CV_8U,4) -#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) - -#define CV_8SC1 CV_MAKETYPE(CV_8S,1) -#define CV_8SC2 CV_MAKETYPE(CV_8S,2) -#define CV_8SC3 CV_MAKETYPE(CV_8S,3) -#define CV_8SC4 CV_MAKETYPE(CV_8S,4) -#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) - -#define CV_16UC1 CV_MAKETYPE(CV_16U,1) -#define CV_16UC2 CV_MAKETYPE(CV_16U,2) -#define CV_16UC3 CV_MAKETYPE(CV_16U,3) -#define CV_16UC4 CV_MAKETYPE(CV_16U,4) -#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) - -#define CV_16SC1 CV_MAKETYPE(CV_16S,1) -#define CV_16SC2 CV_MAKETYPE(CV_16S,2) -#define CV_16SC3 CV_MAKETYPE(CV_16S,3) -#define CV_16SC4 CV_MAKETYPE(CV_16S,4) -#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) - -#define CV_32SC1 CV_MAKETYPE(CV_32S,1) -#define CV_32SC2 CV_MAKETYPE(CV_32S,2) -#define CV_32SC3 CV_MAKETYPE(CV_32S,3) -#define CV_32SC4 CV_MAKETYPE(CV_32S,4) -#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) - -#define CV_32FC1 CV_MAKETYPE(CV_32F,1) -#define CV_32FC2 CV_MAKETYPE(CV_32F,2) -#define CV_32FC3 CV_MAKETYPE(CV_32F,3) -#define CV_32FC4 CV_MAKETYPE(CV_32F,4) -#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) - -#define CV_64FC1 CV_MAKETYPE(CV_64F,1) -#define CV_64FC2 CV_MAKETYPE(CV_64F,2) -#define CV_64FC3 CV_MAKETYPE(CV_64F,3) -#define CV_64FC4 CV_MAKETYPE(CV_64F,4) -#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) - -#define CV_AUTO_STEP 0x7fffffff -#define CV_WHOLE_ARR cvSlice( 0, 0x3fffffff ) - -#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) -#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) -#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) -#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) -#define CV_MAT_CONT_FLAG_SHIFT 14 -#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT) -#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG) -#define CV_IS_CONT_MAT CV_IS_MAT_CONT -#define CV_SUBMAT_FLAG_SHIFT 15 -#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) -#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) - -#define CV_MAGIC_MASK 0xFFFF0000 -#define CV_MAT_MAGIC_VAL 0x42420000 -#define CV_TYPE_NAME_MAT "opencv-matrix" - -class Mat { -public: - Mat(); - ~Mat(); - void create(Size size, int type); - int channels() const; - %immutable; - int rows; - int cols; -}; - -template class Ptr -{ -public: - //! empty constructor - Ptr(); - //! take ownership of the pointer. The associated reference counter is allocated and set to 1 - Ptr(_Tp* _obj); - //! calls release() - ~Ptr(); - //! copy constructor. Copies the members and calls addref() - Ptr(const Ptr& ptr); - //! copy operator. Calls ptr.addref() and release() before copying the members - // Ptr& operator = (const Ptr& ptr); - //! increments the reference counter - void addref(); - //! decrements the reference counter. If it reaches 0, delete_obj() is called - void release(); - //! deletes the object. Override if needed - void delete_obj(); - //! returns true iff obj==NULL - bool empty() const; - - - //! helper operators making "Ptr ptr" use very similar to "T* ptr". - _Tp* operator -> (); - // const _Tp* operator -> () const; - - // operator _Tp* (); - // operator const _Tp*() const; - -protected: - _Tp* obj; //< the object pointer. - int* refcount; //< the associated reference counter -}; - - - -%template(PtrMat) Ptr; - -void imwrite(const char* image_name, const Mat& image); -Mat imread(const char* image_name); - - %include "buffers.i" - %apply char* BUFF {const char* buffer} - %apply char* BUFF {char* buffer} -void copyMatToBuffer(char* buffer, const Mat& mat); -void copyBufferToMat(Mat& mat, const char* buffer); \ No newline at end of file diff --git a/android/android-opencv/jni/gl_code.cpp b/android/android-opencv/jni/gl_code.cpp deleted file mode 100644 index 358b4483cb..0000000000 --- a/android/android-opencv/jni/gl_code.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// OpenGL ES 2.0 code - -#include -#if __ANDROID__ -#include -#include -#else -#include -#endif - -#include "android_logger.h" - -#include -#include - -#include -#include -#include -#include - -#include "glcamera.h" -#include "image_pool.h" -using namespace cv; - -static void printGLString(const char *name, GLenum s) -{ - const char *v = (const char *)glGetString(s); - LOGI("GL %s = %s\n", name, v); -} - -static void checkGlError(const char* op) -{ - for (GLint error = glGetError(); error; error = glGetError()) - { - LOGI("after %s() glError (0x%x)\n", op, error); - } -} - -static const char gVertexShader[] = "attribute vec4 a_position; \n" - "attribute vec2 a_texCoord; \n" - "varying vec2 v_texCoord; \n" - "void main() \n" - "{ \n" - " gl_Position = a_position; \n" - " v_texCoord = a_texCoord; \n" - "} \n"; - -static const char gFragmentShader[] = "precision mediump float; \n" - "varying vec2 v_texCoord; \n" - "uniform sampler2D s_texture; \n" - "void main() \n" - "{ \n" - " gl_FragColor = texture2D( s_texture, v_texCoord );\n" - "} \n"; - - -GLuint glcamera::createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int width, int height, int channels) -{ - - // Bind the texture - glActiveTexture(GL_TEXTURE0); - checkGlError("glActiveTexture"); - // Bind the texture object - glBindTexture(GL_TEXTURE_2D, _textureid); - checkGlError("glBindTexture"); - - GLenum format; - switch (channels) - { - case 3: -#if ANDROID - format = GL_RGB; -#else - format = GL_BGR; -#endif - break; - case 1: - format = GL_LUMINANCE; - break; - case 4: - format = GL_RGBA; - break; - } - // Load the texture - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, pixels); - - checkGlError("glTexImage2D"); -#if ANDROID - // Set the filtering mode - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -#else - /* Linear Filtering */ - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#endif - - return _textureid; - -} - -GLuint glcamera::loadShader(GLenum shaderType, const char* pSource) -{ - GLuint shader = 0; -#if __ANDROID__ - shader = glCreateShader(shaderType); - if (shader) - { - glShaderSource(shader, 1, &pSource, NULL); - glCompileShader(shader); - GLint compiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) - { - GLint infoLen = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen) - { - char* buf = (char*)malloc(infoLen); - if (buf) - { - glGetShaderInfoLog(shader, infoLen, NULL, buf); - LOGE("Could not compile shader %d:\n%s\n", - shaderType, buf); - free(buf); - } - glDeleteShader(shader); - shader = 0; - } - } - } -#endif - return shader; -} - -GLuint glcamera::createProgram(const char* pVertexSource, const char* pFragmentSource) -{ -#if __ANDROID__ - GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); - if (!vertexShader) - { - return 0; - } - - GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); - if (!pixelShader) - { - return 0; - } - - GLuint program = glCreateProgram(); - if (program) - { - glAttachShader(program, vertexShader); - checkGlError("glAttachShader"); - glAttachShader(program, pixelShader); - checkGlError("glAttachShader"); - glLinkProgram(program); - GLint linkStatus = GL_FALSE; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - if (linkStatus != GL_TRUE) - { - GLint bufLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); - if (bufLength) - { - char* buf = (char*)malloc(bufLength); - if (buf) - { - glGetProgramInfoLog(program, bufLength, NULL, buf); - LOGE("Could not link program:\n%s\n", buf); - free(buf); - } - } - glDeleteProgram(program); - program = 0; - } - } - return program; -#else - return 0; -#endif -} -void glcamera::clear(){ - nimg = Mat(); -} -//GLuint textureID; - -bool glcamera::setupGraphics(int w, int h) -{ -// printGLString("Version", GL_VERSION); -// printGLString("Vendor", GL_VENDOR); -// printGLString("Renderer", GL_RENDERER); -// printGLString("Extensions", GL_EXTENSIONS); - -#if __ANDROID__ - gProgram = createProgram(gVertexShader, gFragmentShader); - if (!gProgram) - { - LOGE("Could not create program."); - return false; - } - - gvPositionHandle = glGetAttribLocation(gProgram, "a_position"); - gvTexCoordHandle = glGetAttribLocation(gProgram, "a_texCoord"); - gvSamplerHandle = glGetAttribLocation(gProgram, "s_texture"); - - // Use tightly packed data - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - // Generate a texture object - glGenTextures(1, &textureID); - - glViewport(0, 0, w, h); -#endif - return true; -} - -void glcamera::renderFrame() -{ - -#if __ANDROID__ - GLfloat vVertices[] = {-1.0f, 1.0f, 0.0f, // Position 0 - 0.0f, 0.0f, // TexCoord 0 - -1.0f, -1.0f, 0.0f, // Position 1 - 0.0f, img_h, // TexCoord 1 - 1.0f, -1.0f, 0.0f, // Position 2 - img_w, img_h, // TexCoord 2 - 1.0f, 1.0f, 0.0f, // Position 3 - img_w, 0.0f // TexCoord 3 - }; - GLushort indices[] = {0, 1, 2, 0, 2, 3}; - GLsizei stride = 5 * sizeof(GLfloat); // 3 for position, 2 for texture - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - checkGlError("glClearColor"); - - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - checkGlError("glClear"); - - if(nimg.empty())return; - - glUseProgram(gProgram); - checkGlError("glUseProgram"); - - // Load the vertex position - glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, stride, vVertices); - // Load the texture coordinate - glVertexAttribPointer(gvTexCoordHandle, 2, GL_FLOAT, GL_FALSE, stride, &vVertices[3]); - - glEnableVertexAttribArray(gvPositionHandle); - glEnableVertexAttribArray(gvTexCoordHandle); - - // Bind the texture - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textureID); - - // Set the sampler texture unit to 0 - glUniform1i(gvSamplerHandle, 0); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); -#endif - //checkGlError("glVertexAttribPointer"); - //glEnableVertexAttribArray(gvPositionHandle); - //checkGlError("glEnableVertexAttribArray"); - //glDrawArrays(GL_TRIANGLES, 0, 3); - //checkGlError("glDrawArrays"); -} - -void glcamera::init(int width, int height) -{ - newimage = false; - nimg = Mat(); - setupGraphics(width, height); - -} - -void glcamera::step() -{ - if (newimage && !nimg.empty()) - { - - textureID = createSimpleTexture2D(textureID, nimg.ptr (0), nimg.cols, nimg.rows, nimg.channels()); - newimage = false; - } - renderFrame(); - -} -#define NEAREST_POW2(x)( std::ceil(std::log(x)/0.69315) ) -void glcamera::setTextureImage(const Mat& img) -{ - int p = NEAREST_POW2(img.cols/2); //subsample by 2 - //int sz = std::pow(2, p); - - // Size size(sz, sz); - Size size(256, 256); - img_w = 1; - img_h = 1; - if (nimg.cols != size.width) - LOGI_STREAM( "using texture of size: (" << size.width << " , " << size.height << ") image size is: (" << img.cols << " , " << img.rows << ")"); - nimg.create(size, img.type()); -#if SUBREGION_NPO2 - cv::Rect roi(0, 0, img.cols/2, img.rows/2); - cv::Mat nimg_sub = nimg(roi); - //img.copyTo(nimg_sub); - img_w = (img.cols/2)/float(sz); - img_h = (img.rows/2)/float(sz); - cv::resize(img,nimg_sub,nimg_sub.size(),0,0,CV_INTER_NN); -#else - cv::resize(img, nimg, nimg.size(), 0, 0, CV_INTER_NN); -#endif - newimage = true; -} - -void glcamera::drawMatToGL(int idx, image_pool* pool) -{ - - Mat img = pool->getImage(idx); - - if (img.empty()) - return; //no image at input_idx! - - setTextureImage(img); - -} - -glcamera::glcamera() : - newimage(false) -{ - LOGI("glcamera constructor"); -} -glcamera::~glcamera() -{ - LOGI("glcamera destructor"); -} - diff --git a/android/android-opencv/jni/glcamera.i b/android/android-opencv/jni/glcamera.i deleted file mode 100644 index 2fd2a53ff6..0000000000 --- a/android/android-opencv/jni/glcamera.i +++ /dev/null @@ -1,44 +0,0 @@ - -%typemap(javaimports) glcamera " -/** a class for doing the native rendering of images -this class renders using GL2 es, the native ndk version -This class is used by the GL2CameraViewer to do the rendering, -and is inspired by the gl2 example in the ndk samples -*/" - - - -%javamethodmodifiers glcamera::init" - /** should be called onSurfaceChanged by the GLSurfaceView that is using this - * as the drawing engine - * @param width the width of the surface view that this will be drawing to - * @param width the height of the surface view that this will be drawing to - * - */ - public"; - -%javamethodmodifiers glcamera::step" - /** should be called by GLSurfaceView.Renderer in the onDrawFrame method, as it - handles the rendering of the opengl scene, and requires that the opengl context be - valid. - - * - */ - public"; -%javamethodmodifiers glcamera::drawMatToGL" - /** copies an image from a pool and queues it for drawing in opengl. - * this does transformation into power of two texture sizes - * @param idx the image index to copy - * @param pool the image_pool to look up the image from - * - */ - public"; - -class glcamera { -public: - void init(int width, int height); - void step(); - void drawMatToGL(int idx, image_pool* pool); - void clear(); -}; - diff --git a/android/android-opencv/jni/image_pool.cpp b/android/android-opencv/jni/image_pool.cpp deleted file mode 100644 index c7a6720905..0000000000 --- a/android/android-opencv/jni/image_pool.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "image_pool.h" - -#include "yuv420sp2rgb.h" - -#include "android_logger.h" - -#include - -#include -#include -#ifdef __cplusplus -extern "C" -{ -#endif - -JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved); -// -//JNIEXPORT jobject JNICALL Java_com_opencv_jni_opencvJNI_getBitmapBuffer( -// JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_); - - -JNIEXPORT void JNICALL Java_com_opencv_jni_opencvJNI_addYUVtoPool(JNIEnv *, jclass, jlong, jobject, jbyteArray, jint, - jint, jint, jboolean); - -#ifdef __cplusplus -} -#endif - -using namespace cv; - -JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ - JNIEnv *env; - LOGI("JNI_OnLoad called for opencv"); - return JNI_VERSION_1_4; -} - -JNIEXPORT void JNICALL Java_com_opencv_jni_opencvJNI_addYUVtoPool(JNIEnv * env, jclass thiz, jlong ppool, - jobject _jpool, jbyteArray jbuffer, jint jidx, - jint jwidth, jint jheight, jboolean jgrey) -{ - int buff_height = jheight + (jheight / 2); - Size buff_size(jwidth, buff_height); - image_pool *pool = (image_pool *)ppool; - - Mat mat = pool->getYUV(jidx); - //create is smart and only copies if the buffer size is different - mat.create(buff_size, CV_8UC1); - { - uchar* buff = mat.ptr (0); - jsize sz = env->GetArrayLength(jbuffer); - //http://elliotth.blogspot.com/2007/03/optimizing-jni-array-access.html - env->GetByteArrayRegion(jbuffer, 0, sz, (jbyte*)buff); - } - pool->addYUVMat(jidx, mat); - - Mat color; - if (jgrey) - { - Mat grey = pool->getGrey(jidx); - color = grey; - } - else - { - color = pool->getImage(jidx); - pool->convertYUVtoColor(jidx, color); - } - pool->addImage(jidx, color); -} - -image_pool::image_pool() -{ - -} - -image_pool::~image_pool() -{ - -} - -Mat image_pool::getImage(int i) -{ - return imagesmap[i]; -} -Mat image_pool::getGrey(int i) -{ - Mat tm = yuvImagesMap[i]; - if (tm.empty()) - return tm; - return tm(Range(0, tm.rows * (2.0f / 3)), Range::all()); -} -Mat image_pool::getYUV(int i) -{ - return yuvImagesMap[i]; -} -void image_pool::addYUVMat(int i, Mat mat) -{ - yuvImagesMap[i] = mat; -} -void image_pool::addImage(int i, Mat mat) -{ - imagesmap[i] = mat; -} - -void image_pool::convertYUVtoColor(int i, cv::Mat& out) -{ - Mat yuv = getYUV(i); - if (yuv.empty()) - return; - int width = yuv.cols; - int height = yuv.rows * (2.0f / 3); - out.create(height, width, CV_8UC3); - const unsigned char* buff = yuv.ptr (0); - unsigned char* out_buff = out.ptr (0); - color_convert_common(buff, buff + width * height, width, height, out_buff, false); -} - -void copyMatToBuffer(char* buffer, const cv::Mat& mat) -{ - memcpy(buffer, mat.data, mat.rows * mat.cols * mat.step1()); -} -void copyBufferToMat(cv::Mat& mat, const char* buffer) -{ - memcpy(mat.data, buffer, mat.rows * mat.cols * mat.step1()); -} - -void RGB2BGR(const Mat& in, Mat& out) -{ - cvtColor(in, out, CV_RGB2BGR); -} diff --git a/android/android-opencv/jni/image_pool.i b/android/android-opencv/jni/image_pool.i deleted file mode 100644 index b81e64a958..0000000000 --- a/android/android-opencv/jni/image_pool.i +++ /dev/null @@ -1,51 +0,0 @@ - - -%typemap(javaimports) image_pool " -/** image_pool is used for keeping track of a pool of native images. It stores images as cv::Mat's and -references them by an index. It allows one to get a pointer to an underlying mat, and handles memory deletion.*/" - - -%javamethodmodifiers image_pool::getImage" - /** gets a pointer to a stored image, by an index. If the index is new, returns a null pointer - * @param idx the index in the pool that is associated with a cv::Mat - * @return the pointer to a cv::Mat, null pointer if the given idx is novel - */ - public"; - - -%javamethodmodifiers image_pool::deleteImage" - /** deletes the image from the pool - * @param idx the index in the pool that is associated with a cv::Mat - */ - public"; - - - -%javamethodmodifiers addYUVtoPool" - /** adds a yuv - * @param idx the index in the pool that is associated with a cv::Mat - */ - public"; - -%include "various.i" - - -%apply (char* BYTE) { (char *data)}; //byte[] to char* - - -%native (addYUVtoPool) void addYUVtoPool(image_pool* pool, char* data,int idx, int width, int height, bool grey); - - - - -%feature("director") image_pool; -class image_pool { -public: - Mat getGrey(int i); - Mat getImage(int i); - void addImage(int i, Mat mat); - void convertYUVtoColor(int i, Mat& out); -}; - -void RGB2BGR(const Mat& in, Mat& out); - diff --git a/android/android-opencv/jni/include/Calibration.h b/android/android-opencv/jni/include/Calibration.h deleted file mode 100644 index 6e0eef3bc4..0000000000 --- a/android/android-opencv/jni/include/Calibration.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Processor.h - * - * Created on: Jun 13, 2010 - * Author: ethan - */ - -#ifndef PROCESSOR_H_ -#define PROCESSOR_H_ - -#include -#include -#include -#include -#include - -#include - -#include "image_pool.h" - -#define DETECT_FAST 0 -#define DETECT_STAR 1 -#define DETECT_SURF 2 - -class Calibration -{ -public: - - Calibration(); - virtual ~Calibration(); - - bool detectAndDrawChessboard(int idx, image_pool* pool); - - void resetChess(); - - int getNumberDetectedChessboards(); - - void calibrate(const char* filename); - - void drawText(int idx, image_pool* pool, const char* text); - - cv::Size patternsize; -private: - std::vector keypoints; - - std::vector > imagepoints; - - cv::Mat K; - cv::Mat distortion; - cv::Size imgsize; - -}; - -#endif /* PROCESSOR_H_ */ diff --git a/android/android-opencv/jni/include/android_logger.h b/android/android-opencv/jni/include/android_logger.h deleted file mode 100644 index 09f8dc3512..0000000000 --- a/android/android-opencv/jni/include/android_logger.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include - -#define LOG_TAG "libopencv" -#if ANDROID -#include -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) -#else -#include -#define LOGI(...) printf("info:");printf("%s:",LOG_TAG); fprintf(stdout,__VA_ARGS__);printf("\n"); -#define LOGE(...) printf("error:");printf("%s:",LOG_TAG); fprintf(stderr,__VA_ARGS__);printf("\n"); -#endif - -#ifndef LOGI_STREAM -#define LOGI_STREAM(x) {std::stringstream ss; ss << x; LOGI("%s",ss.str().c_str());} -#endif -#define LOGE_STREAM(x) {std::stringstream ss; ss << x; LOGE("%s",ss.str().c_str());} diff --git a/android/android-opencv/jni/include/glcamera.h b/android/android-opencv/jni/include/glcamera.h deleted file mode 100644 index e7c021a429..0000000000 --- a/android/android-opencv/jni/include/glcamera.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef GLCAMERA_H_ -#define GLCAMERA_H_ -#include - -#ifdef __ANDROID__ -#include -#include -#else -#include -#include -#endif - -#include "image_pool.h" - -class glcamera -{ -public: - - glcamera(); - ~glcamera(); - void init(int width, int height); - void step(); - - void drawMatToGL(int idx, image_pool* pool); - void drawMatToGL(const cv::Mat& img); - void setTextureImage(const cv::Mat& img); - - void clear(); - -private: - GLuint createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int width, int height, int channels); - GLuint loadShader(GLenum shaderType, const char* pSource); - GLuint - createProgram(const char* pVertexSource, const char* pFragmentSource); - bool setupGraphics(int w, int h); - void renderFrame(); - cv::Mat nimg; - bool newimage; - GLuint textureID; - - GLuint gProgram; - GLuint gvPositionHandle; - - GLuint gvTexCoordHandle; - GLuint gvSamplerHandle; - float img_w, img_h; -}; -#endif diff --git a/android/android-opencv/jni/include/image_pool.h b/android/android-opencv/jni/include/image_pool.h deleted file mode 100644 index d32eb479c9..0000000000 --- a/android/android-opencv/jni/include/image_pool.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef IMAGE_POOL_H_ANDROID_KDJFKJ -#define IMAGE_POOL_H_ANDROID_KDJFKJ -#include -#include - - - -class image_pool -{ - -public: - image_pool(); - ~image_pool(); - cv::Mat getImage(int i); - cv::Mat getGrey(int i); - cv::Mat getYUV(int i); - - int getCount() - { - return imagesmap.size(); - } - - /** Adds a mat at the given index - will not do a deep copy, just images[i] = mat - * - */ - void addImage(int i, cv::Mat mat); - - /** this function stores the given matrix in the the yuvImagesMap. Also, - * after this call getGrey will work, as the grey image is just the top - * half of the YUV mat. - * - * \param i index to store yuv image at - * \param mat the yuv matrix to store - */ - void addYUVMat(int i, cv::Mat mat); - - void convertYUVtoColor(int i, cv::Mat& out); - - // int addYUV(uchar* buffer, int size, int width, int height, bool grey,int idx); - // - // void getBitmap(int * outintarray, int size, int idx); -private: - std::map imagesmap; - std::map yuvImagesMap; - -}; - -void copyMatToBuffer(char* buffer, const cv::Mat& mat); -void copyBufferToMat(cv::Mat& mat, const char* buffer); -void RGB2BGR(const cv::Mat& in, cv::Mat& out); -#endif diff --git a/android/android-opencv/jni/include/yuv2rgb.h b/android/android-opencv/jni/include/yuv2rgb.h deleted file mode 100644 index 9b7535c661..0000000000 --- a/android/android-opencv/jni/include/yuv2rgb.h +++ /dev/null @@ -1,147 +0,0 @@ -/* YUV-> RGB conversion code. - * - * Copyright (C) 2008-9 Robin Watts (robin@wss.co.uk) for Pinknoise - * Productions Ltd. - * - * Licensed under the GNU GPL. If you need it under another license, contact - * me and ask. - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation ; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY ; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program ; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef YUV2RGB_H - -#define YUV2RGB_H - -/* Define these to something appropriate in your build */ -typedef unsigned int uint32_t; -typedef signed int int32_t; -typedef unsigned short uint16_t; -typedef unsigned char uint8_t; - -extern const uint32_t yuv2rgb565_table[]; -extern const uint32_t yuv2bgr565_table[]; - -void yuv420_2_rgb565(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv422_2_rgb565(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv444_2_rgb565(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv420_2_rgb888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv422_2_rgb888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv444_2_rgb888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv420_2_rgb8888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv422_2_rgb8888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - -void yuv444_2_rgb8888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither); - - -#endif /* YUV2RGB_H */ diff --git a/android/android-opencv/jni/include/yuv420sp2rgb.h b/android/android-opencv/jni/include/yuv420sp2rgb.h deleted file mode 100644 index fcfc49cc4b..0000000000 --- a/android/android-opencv/jni/include/yuv420sp2rgb.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef YUV420SP2RGB_H -#define YUV420SP2RGB_H - -#ifdef __cplusplus -extern "C" { -#endif - -void color_convert_common( - const unsigned char *pY, const unsigned char *pUV, - int width, int height, unsigned char *buffer, - int grey); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/android/android-opencv/jni/nocopy.i b/android/android-opencv/jni/nocopy.i deleted file mode 100644 index 23e685fd83..0000000000 --- a/android/android-opencv/jni/nocopy.i +++ /dev/null @@ -1,36 +0,0 @@ -/* - * int *INTARRAY typemaps. - * These are input typemaps for mapping a Java int[] array to a C int array. - * Note that as a Java array is used and thus passeed by reference, the C routine - * can return data to Java via the parameter. - * - * Example usage wrapping: - * void foo((int *INTARRAY, int INTARRAYSIZE); - * - * Java usage: - * byte b[] = new byte[20]; - * modulename.foo(b); - */ - -%typemap(in) (int *INTARRAY, int INTARRAYSIZE) { - $1 = (int *) JCALL2(GetIntArrayElements, jenv, $input, 0); - jsize sz = JCALL1(GetArrayLength, jenv, $input); - $2 = (int)sz; -} - -%typemap(argout) (int *INTARRAY, int INTARRAYSIZE) { - JCALL3(ReleaseIntArrayElements, jenv, $input, (jint *) $1, 0); -} - - -/* Prevent default freearg typemap from being used */ -%typemap(freearg) (int *INTARRAY, int INTARRAYSIZE) "" - -%typemap(jni) (int *INTARRAY, int INTARRAYSIZE) "jintArray" -%typemap(jtype) (int *INTARRAY, int INTARRAYSIZE) "int[]" -%typemap(jstype) (int *INTARRAY, int INTARRAYSIZE) "int[]" -%typemap(javain) (int *INTARRAY, int INTARRAYSIZE) "$javainput" - - - - diff --git a/android/android-opencv/jni/yuv2rgb16tab.c b/android/android-opencv/jni/yuv2rgb16tab.c deleted file mode 100644 index f9f6a14053..0000000000 --- a/android/android-opencv/jni/yuv2rgb16tab.c +++ /dev/null @@ -1,802 +0,0 @@ -/* YUV-> RGB conversion code. - * - * Copyright (C) 2008-9 Robin Watts (robin@wss.co.uk) for Pinknoise - * Productions Ltd. - * - * Licensed under the GNU GPL. If you need it under another license, contact - * me and ask. - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation ; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY ; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program ; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* For BREW or Symbian you might need to make this static const rather than - * just const, and introduce a function to get the address. */ - -#include "yuv2rgb.h" - -const uint32_t yuv2rgb565_table[256*3] = -{ - /* y_table */ - 0x7FFFFFEDU, - 0x7FFFFFEFU, - 0x7FFFFFF0U, - 0x7FFFFFF1U, - 0x7FFFFFF2U, - 0x7FFFFFF3U, - 0x7FFFFFF4U, - 0x7FFFFFF6U, - 0x7FFFFFF7U, - 0x7FFFFFF8U, - 0x7FFFFFF9U, - 0x7FFFFFFAU, - 0x7FFFFFFBU, - 0x7FFFFFFDU, - 0x7FFFFFFEU, - 0x7FFFFFFFU, - 0x80000000U, - 0x80400801U, - 0x80A01002U, - 0x80E01803U, - 0x81202805U, - 0x81803006U, - 0x81C03807U, - 0x82004008U, - 0x82604809U, - 0x82A0500AU, - 0x82E0600CU, - 0x8340680DU, - 0x8380700EU, - 0x83C0780FU, - 0x84208010U, - 0x84608811U, - 0x84A09813U, - 0x8500A014U, - 0x8540A815U, - 0x8580B016U, - 0x85E0B817U, - 0x8620C018U, - 0x8660D01AU, - 0x86C0D81BU, - 0x8700E01CU, - 0x8740E81DU, - 0x87A0F01EU, - 0x87E0F81FU, - 0x88210821U, - 0x88811022U, - 0x88C11823U, - 0x89012024U, - 0x89412825U, - 0x89A13026U, - 0x89E14028U, - 0x8A214829U, - 0x8A81502AU, - 0x8AC1582BU, - 0x8B01602CU, - 0x8B61682DU, - 0x8BA1782FU, - 0x8BE18030U, - 0x8C418831U, - 0x8C819032U, - 0x8CC19833U, - 0x8D21A034U, - 0x8D61B036U, - 0x8DA1B837U, - 0x8E01C038U, - 0x8E41C839U, - 0x8E81D03AU, - 0x8EE1D83BU, - 0x8F21E83DU, - 0x8F61F03EU, - 0x8FC1F83FU, - 0x90020040U, - 0x90420841U, - 0x90A21042U, - 0x90E22044U, - 0x91222845U, - 0x91823046U, - 0x91C23847U, - 0x92024048U, - 0x92624849U, - 0x92A2504AU, - 0x92E2604CU, - 0x9342684DU, - 0x9382704EU, - 0x93C2784FU, - 0x94228050U, - 0x94628851U, - 0x94A29853U, - 0x9502A054U, - 0x9542A855U, - 0x9582B056U, - 0x95E2B857U, - 0x9622C058U, - 0x9662D05AU, - 0x96C2D85BU, - 0x9702E05CU, - 0x9742E85DU, - 0x97A2F05EU, - 0x97E2F85FU, - 0x98230861U, - 0x98831062U, - 0x98C31863U, - 0x99032064U, - 0x99632865U, - 0x99A33066U, - 0x99E34068U, - 0x9A434869U, - 0x9A83506AU, - 0x9AC3586BU, - 0x9B23606CU, - 0x9B63686DU, - 0x9BA3786FU, - 0x9BE38070U, - 0x9C438871U, - 0x9C839072U, - 0x9CC39873U, - 0x9D23A074U, - 0x9D63B076U, - 0x9DA3B877U, - 0x9E03C078U, - 0x9E43C879U, - 0x9E83D07AU, - 0x9EE3D87BU, - 0x9F23E87DU, - 0x9F63F07EU, - 0x9FC3F87FU, - 0xA0040080U, - 0xA0440881U, - 0xA0A41082U, - 0xA0E42084U, - 0xA1242885U, - 0xA1843086U, - 0xA1C43887U, - 0xA2044088U, - 0xA2644889U, - 0xA2A4588BU, - 0xA2E4608CU, - 0xA344688DU, - 0xA384708EU, - 0xA3C4788FU, - 0xA4248090U, - 0xA4649092U, - 0xA4A49893U, - 0xA504A094U, - 0xA544A895U, - 0xA584B096U, - 0xA5E4B897U, - 0xA624C098U, - 0xA664D09AU, - 0xA6C4D89BU, - 0xA704E09CU, - 0xA744E89DU, - 0xA7A4F09EU, - 0xA7E4F89FU, - 0xA82508A1U, - 0xA88510A2U, - 0xA8C518A3U, - 0xA90520A4U, - 0xA96528A5U, - 0xA9A530A6U, - 0xA9E540A8U, - 0xAA4548A9U, - 0xAA8550AAU, - 0xAAC558ABU, - 0xAB2560ACU, - 0xAB6568ADU, - 0xABA578AFU, - 0xAC0580B0U, - 0xAC4588B1U, - 0xAC8590B2U, - 0xACE598B3U, - 0xAD25A0B4U, - 0xAD65B0B6U, - 0xADA5B8B7U, - 0xAE05C0B8U, - 0xAE45C8B9U, - 0xAE85D0BAU, - 0xAEE5D8BBU, - 0xAF25E8BDU, - 0xAF65F0BEU, - 0xAFC5F8BFU, - 0xB00600C0U, - 0xB04608C1U, - 0xB0A610C2U, - 0xB0E620C4U, - 0xB12628C5U, - 0xB18630C6U, - 0xB1C638C7U, - 0xB20640C8U, - 0xB26648C9U, - 0xB2A658CBU, - 0xB2E660CCU, - 0xB34668CDU, - 0xB38670CEU, - 0xB3C678CFU, - 0xB42680D0U, - 0xB46690D2U, - 0xB4A698D3U, - 0xB506A0D4U, - 0xB546A8D5U, - 0xB586B0D6U, - 0xB5E6B8D7U, - 0xB626C8D9U, - 0xB666D0DAU, - 0xB6C6D8DBU, - 0xB706E0DCU, - 0xB746E8DDU, - 0xB7A6F0DEU, - 0xB7E6F8DFU, - 0xB82708E1U, - 0xB88710E2U, - 0xB8C718E3U, - 0xB90720E4U, - 0xB96728E5U, - 0xB9A730E6U, - 0xB9E740E8U, - 0xBA4748E9U, - 0xBA8750EAU, - 0xBAC758EBU, - 0xBB2760ECU, - 0xBB6768EDU, - 0xBBA778EFU, - 0xBC0780F0U, - 0xBC4788F1U, - 0xBC8790F2U, - 0xBCE798F3U, - 0xBD27A0F4U, - 0xBD67B0F6U, - 0xBDC7B8F7U, - 0xBE07C0F8U, - 0xBE47C8F9U, - 0xBEA7D0FAU, - 0xBEE7D8FBU, - 0xBF27E8FDU, - 0xBF87F0FEU, - 0xBFC7F8FFU, - 0xC0080100U, - 0xC0480901U, - 0xC0A81102U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - 0xC0E82104U, - /* u_table */ - 0x0C400103U, - 0x0C200105U, - 0x0C200107U, - 0x0C000109U, - 0x0BE0010BU, - 0x0BC0010DU, - 0x0BA0010FU, - 0x0BA00111U, - 0x0B800113U, - 0x0B600115U, - 0x0B400117U, - 0x0B400119U, - 0x0B20011BU, - 0x0B00011DU, - 0x0AE0011FU, - 0x0AE00121U, - 0x0AC00123U, - 0x0AA00125U, - 0x0A800127U, - 0x0A600129U, - 0x0A60012BU, - 0x0A40012DU, - 0x0A20012FU, - 0x0A000131U, - 0x0A000132U, - 0x09E00134U, - 0x09C00136U, - 0x09A00138U, - 0x09A0013AU, - 0x0980013CU, - 0x0960013EU, - 0x09400140U, - 0x09400142U, - 0x09200144U, - 0x09000146U, - 0x08E00148U, - 0x08C0014AU, - 0x08C0014CU, - 0x08A0014EU, - 0x08800150U, - 0x08600152U, - 0x08600154U, - 0x08400156U, - 0x08200158U, - 0x0800015AU, - 0x0800015CU, - 0x07E0015EU, - 0x07C00160U, - 0x07A00162U, - 0x07A00164U, - 0x07800166U, - 0x07600168U, - 0x0740016AU, - 0x0720016CU, - 0x0720016EU, - 0x07000170U, - 0x06E00172U, - 0x06C00174U, - 0x06C00176U, - 0x06A00178U, - 0x0680017AU, - 0x0660017CU, - 0x0660017EU, - 0x06400180U, - 0x06200182U, - 0x06000184U, - 0x05E00185U, - 0x05E00187U, - 0x05C00189U, - 0x05A0018BU, - 0x0580018DU, - 0x0580018FU, - 0x05600191U, - 0x05400193U, - 0x05200195U, - 0x05200197U, - 0x05000199U, - 0x04E0019BU, - 0x04C0019DU, - 0x04C0019FU, - 0x04A001A1U, - 0x048001A3U, - 0x046001A5U, - 0x044001A7U, - 0x044001A9U, - 0x042001ABU, - 0x040001ADU, - 0x03E001AFU, - 0x03E001B1U, - 0x03C001B3U, - 0x03A001B5U, - 0x038001B7U, - 0x038001B9U, - 0x036001BBU, - 0x034001BDU, - 0x032001BFU, - 0x032001C1U, - 0x030001C3U, - 0x02E001C5U, - 0x02C001C7U, - 0x02A001C9U, - 0x02A001CBU, - 0x028001CDU, - 0x026001CFU, - 0x024001D1U, - 0x024001D3U, - 0x022001D5U, - 0x020001D7U, - 0x01E001D8U, - 0x01E001DAU, - 0x01C001DCU, - 0x01A001DEU, - 0x018001E0U, - 0x016001E2U, - 0x016001E4U, - 0x014001E6U, - 0x012001E8U, - 0x010001EAU, - 0x010001ECU, - 0x00E001EEU, - 0x00C001F0U, - 0x00A001F2U, - 0x00A001F4U, - 0x008001F6U, - 0x006001F8U, - 0x004001FAU, - 0x004001FCU, - 0x002001FEU, - 0x00000200U, - 0xFFE00202U, - 0xFFC00204U, - 0xFFC00206U, - 0xFFA00208U, - 0xFF80020AU, - 0xFF60020CU, - 0xFF60020EU, - 0xFF400210U, - 0xFF200212U, - 0xFF000214U, - 0xFF000216U, - 0xFEE00218U, - 0xFEC0021AU, - 0xFEA0021CU, - 0xFEA0021EU, - 0xFE800220U, - 0xFE600222U, - 0xFE400224U, - 0xFE200226U, - 0xFE200228U, - 0xFE000229U, - 0xFDE0022BU, - 0xFDC0022DU, - 0xFDC0022FU, - 0xFDA00231U, - 0xFD800233U, - 0xFD600235U, - 0xFD600237U, - 0xFD400239U, - 0xFD20023BU, - 0xFD00023DU, - 0xFCE0023FU, - 0xFCE00241U, - 0xFCC00243U, - 0xFCA00245U, - 0xFC800247U, - 0xFC800249U, - 0xFC60024BU, - 0xFC40024DU, - 0xFC20024FU, - 0xFC200251U, - 0xFC000253U, - 0xFBE00255U, - 0xFBC00257U, - 0xFBC00259U, - 0xFBA0025BU, - 0xFB80025DU, - 0xFB60025FU, - 0xFB400261U, - 0xFB400263U, - 0xFB200265U, - 0xFB000267U, - 0xFAE00269U, - 0xFAE0026BU, - 0xFAC0026DU, - 0xFAA0026FU, - 0xFA800271U, - 0xFA800273U, - 0xFA600275U, - 0xFA400277U, - 0xFA200279U, - 0xFA20027BU, - 0xFA00027CU, - 0xF9E0027EU, - 0xF9C00280U, - 0xF9A00282U, - 0xF9A00284U, - 0xF9800286U, - 0xF9600288U, - 0xF940028AU, - 0xF940028CU, - 0xF920028EU, - 0xF9000290U, - 0xF8E00292U, - 0xF8E00294U, - 0xF8C00296U, - 0xF8A00298U, - 0xF880029AU, - 0xF860029CU, - 0xF860029EU, - 0xF84002A0U, - 0xF82002A2U, - 0xF80002A4U, - 0xF80002A6U, - 0xF7E002A8U, - 0xF7C002AAU, - 0xF7A002ACU, - 0xF7A002AEU, - 0xF78002B0U, - 0xF76002B2U, - 0xF74002B4U, - 0xF74002B6U, - 0xF72002B8U, - 0xF70002BAU, - 0xF6E002BCU, - 0xF6C002BEU, - 0xF6C002C0U, - 0xF6A002C2U, - 0xF68002C4U, - 0xF66002C6U, - 0xF66002C8U, - 0xF64002CAU, - 0xF62002CCU, - 0xF60002CEU, - 0xF60002CFU, - 0xF5E002D1U, - 0xF5C002D3U, - 0xF5A002D5U, - 0xF5A002D7U, - 0xF58002D9U, - 0xF56002DBU, - 0xF54002DDU, - 0xF52002DFU, - 0xF52002E1U, - 0xF50002E3U, - 0xF4E002E5U, - 0xF4C002E7U, - 0xF4C002E9U, - 0xF4A002EBU, - 0xF48002EDU, - 0xF46002EFU, - 0xF46002F1U, - 0xF44002F3U, - 0xF42002F5U, - 0xF40002F7U, - 0xF3E002F9U, - 0xF3E002FBU, - /* v_table */ - 0x1A09A000U, - 0x19E9A800U, - 0x19A9B800U, - 0x1969C800U, - 0x1949D000U, - 0x1909E000U, - 0x18C9E800U, - 0x18A9F800U, - 0x186A0000U, - 0x182A1000U, - 0x180A2000U, - 0x17CA2800U, - 0x17AA3800U, - 0x176A4000U, - 0x172A5000U, - 0x170A6000U, - 0x16CA6800U, - 0x168A7800U, - 0x166A8000U, - 0x162A9000U, - 0x160AA000U, - 0x15CAA800U, - 0x158AB800U, - 0x156AC000U, - 0x152AD000U, - 0x14EAE000U, - 0x14CAE800U, - 0x148AF800U, - 0x146B0000U, - 0x142B1000U, - 0x13EB2000U, - 0x13CB2800U, - 0x138B3800U, - 0x134B4000U, - 0x132B5000U, - 0x12EB6000U, - 0x12CB6800U, - 0x128B7800U, - 0x124B8000U, - 0x122B9000U, - 0x11EBA000U, - 0x11ABA800U, - 0x118BB800U, - 0x114BC000U, - 0x112BD000U, - 0x10EBE000U, - 0x10ABE800U, - 0x108BF800U, - 0x104C0000U, - 0x100C1000U, - 0x0FEC2000U, - 0x0FAC2800U, - 0x0F8C3800U, - 0x0F4C4000U, - 0x0F0C5000U, - 0x0EEC5800U, - 0x0EAC6800U, - 0x0E6C7800U, - 0x0E4C8000U, - 0x0E0C9000U, - 0x0DEC9800U, - 0x0DACA800U, - 0x0D6CB800U, - 0x0D4CC000U, - 0x0D0CD000U, - 0x0CCCD800U, - 0x0CACE800U, - 0x0C6CF800U, - 0x0C4D0000U, - 0x0C0D1000U, - 0x0BCD1800U, - 0x0BAD2800U, - 0x0B6D3800U, - 0x0B2D4000U, - 0x0B0D5000U, - 0x0ACD5800U, - 0x0AAD6800U, - 0x0A6D7800U, - 0x0A2D8000U, - 0x0A0D9000U, - 0x09CD9800U, - 0x098DA800U, - 0x096DB800U, - 0x092DC000U, - 0x090DD000U, - 0x08CDD800U, - 0x088DE800U, - 0x086DF800U, - 0x082E0000U, - 0x07EE1000U, - 0x07CE1800U, - 0x078E2800U, - 0x076E3800U, - 0x072E4000U, - 0x06EE5000U, - 0x06CE5800U, - 0x068E6800U, - 0x064E7800U, - 0x062E8000U, - 0x05EE9000U, - 0x05CE9800U, - 0x058EA800U, - 0x054EB800U, - 0x052EC000U, - 0x04EED000U, - 0x04AED800U, - 0x048EE800U, - 0x044EF000U, - 0x042F0000U, - 0x03EF1000U, - 0x03AF1800U, - 0x038F2800U, - 0x034F3000U, - 0x030F4000U, - 0x02EF5000U, - 0x02AF5800U, - 0x028F6800U, - 0x024F7000U, - 0x020F8000U, - 0x01EF9000U, - 0x01AF9800U, - 0x016FA800U, - 0x014FB000U, - 0x010FC000U, - 0x00EFD000U, - 0x00AFD800U, - 0x006FE800U, - 0x004FF000U, - 0x00100000U, - 0xFFD01000U, - 0xFFB01800U, - 0xFF702800U, - 0xFF303000U, - 0xFF104000U, - 0xFED05000U, - 0xFEB05800U, - 0xFE706800U, - 0xFE307000U, - 0xFE108000U, - 0xFDD09000U, - 0xFD909800U, - 0xFD70A800U, - 0xFD30B000U, - 0xFD10C000U, - 0xFCD0D000U, - 0xFC90D800U, - 0xFC70E800U, - 0xFC30F000U, - 0xFBF10000U, - 0xFBD11000U, - 0xFB911800U, - 0xFB712800U, - 0xFB313000U, - 0xFAF14000U, - 0xFAD14800U, - 0xFA915800U, - 0xFA516800U, - 0xFA317000U, - 0xF9F18000U, - 0xF9D18800U, - 0xF9919800U, - 0xF951A800U, - 0xF931B000U, - 0xF8F1C000U, - 0xF8B1C800U, - 0xF891D800U, - 0xF851E800U, - 0xF831F000U, - 0xF7F20000U, - 0xF7B20800U, - 0xF7921800U, - 0xF7522800U, - 0xF7123000U, - 0xF6F24000U, - 0xF6B24800U, - 0xF6925800U, - 0xF6526800U, - 0xF6127000U, - 0xF5F28000U, - 0xF5B28800U, - 0xF5729800U, - 0xF552A800U, - 0xF512B000U, - 0xF4F2C000U, - 0xF4B2C800U, - 0xF472D800U, - 0xF452E800U, - 0xF412F000U, - 0xF3D30000U, - 0xF3B30800U, - 0xF3731800U, - 0xF3532800U, - 0xF3133000U, - 0xF2D34000U, - 0xF2B34800U, - 0xF2735800U, - 0xF2336800U, - 0xF2137000U, - 0xF1D38000U, - 0xF1B38800U, - 0xF1739800U, - 0xF133A800U, - 0xF113B000U, - 0xF0D3C000U, - 0xF093C800U, - 0xF073D800U, - 0xF033E000U, - 0xF013F000U, - 0xEFD40000U, - 0xEF940800U, - 0xEF741800U, - 0xEF342000U, - 0xEEF43000U, - 0xEED44000U, - 0xEE944800U, - 0xEE745800U, - 0xEE346000U, - 0xEDF47000U, - 0xEDD48000U, - 0xED948800U, - 0xED549800U, - 0xED34A000U, - 0xECF4B000U, - 0xECD4C000U, - 0xEC94C800U, - 0xEC54D800U, - 0xEC34E000U, - 0xEBF4F000U, - 0xEBB50000U, - 0xEB950800U, - 0xEB551800U, - 0xEB352000U, - 0xEAF53000U, - 0xEAB54000U, - 0xEA954800U, - 0xEA555800U, - 0xEA156000U, - 0xE9F57000U, - 0xE9B58000U, - 0xE9958800U, - 0xE9559800U, - 0xE915A000U, - 0xE8F5B000U, - 0xE8B5C000U, - 0xE875C800U, - 0xE855D800U, - 0xE815E000U, - 0xE7F5F000U, - 0xE7B60000U, - 0xE7760800U, - 0xE7561800U, - 0xE7162000U, - 0xE6D63000U, - 0xE6B64000U, - 0xE6764800U, - 0xE6365800U -}; diff --git a/android/android-opencv/jni/yuv2rgb_neon.c b/android/android-opencv/jni/yuv2rgb_neon.c deleted file mode 100644 index a845858ab7..0000000000 --- a/android/android-opencv/jni/yuv2rgb_neon.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -#include "yuv420sp2rgb.h" -#include -#include - -/* this source file should only be compiled by Android.mk when targeting - * the armeabi-v7a ABI, and should be built in NEON mode - */ -void fir_filter_neon_intrinsics(short *output, const short* input, const short* kernel, int width, int kernelSize) -{ -#if 1 - int nn, offset = -kernelSize / 2; - - for (nn = 0; nn < width; nn++) - { - int mm, sum = 0; - int32x4_t sum_vec = vdupq_n_s32(0); - for (mm = 0; mm < kernelSize / 4; mm++) - { - int16x4_t kernel_vec = vld1_s16(kernel + mm * 4); - int16x4_t input_vec = vld1_s16(input + (nn + offset + mm * 4)); - sum_vec = vmlal_s16(sum_vec, kernel_vec, input_vec); - } - - sum += vgetq_lane_s32(sum_vec, 0); - sum += vgetq_lane_s32(sum_vec, 1); - sum += vgetq_lane_s32(sum_vec, 2); - sum += vgetq_lane_s32(sum_vec, 3); - - if (kernelSize & 3) - { - for (mm = kernelSize - (kernelSize & 3); mm < kernelSize; mm++) - sum += kernel[mm] * input[nn + offset + mm]; - } - - output[nn] = (short)((sum + 0x8000) >> 16); - } -#else /* for comparison purposes only */ - int nn, offset = -kernelSize/2; - for (nn = 0; nn < width; nn++) - { - int sum = 0; - int mm; - for (mm = 0; mm < kernelSize; mm++) - { - sum += kernel[mm]*input[nn+offset+mm]; - } - output[n] = (short)((sum + 0x8000) >> 16); - } -#endif -} - -/* - YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved - U/V plane containing 8 bit 2x2 subsampled chroma samples. - except the interleave order of U and V is reversed. - - H V - Y Sample Period 1 1 - U (Cb) Sample Period 2 2 - V (Cr) Sample Period 2 2 - */ - -/* - size of a char: - find . -name limits.h -exec grep CHAR_BIT {} \; - */ - -#ifndef max -#define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) -#define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) -#endif - -#define bytes_per_pixel 2 -#define LOAD_Y(i,j) (pY + i * width + j) -#define LOAD_V(i,j) (pUV + (i / 2) * width + bytes_per_pixel * (j / 2)) -#define LOAD_U(i,j) (pUV + (i / 2) * width + bytes_per_pixel * (j / 2)+1) - -const uint8_t ZEROS[8] = {220,220, 220, 220, 220, 220, 220, 220}; -const uint8_t Y_SUBS[8] = {16, 16, 16, 16, 16, 16, 16, 16}; -const uint8_t UV_SUBS[8] = {128, 128, 128, 128, 128, 128, 128, 128}; - -const uint32_t UV_MULS[] = {833, 400, 833, 400}; - -void color_convert_common(unsigned char *pY, unsigned char *pUV, int width, int height, unsigned char *buffer, int grey) -{ - - int i, j; - int nR, nG, nB; - int nY, nU, nV; - unsigned char *out = buffer; - int offset = 0; - - uint8x8_t Y_SUBvec = vld1_u8(Y_SUBS); - uint8x8_t UV_SUBvec = vld1_u8(UV_SUBS); // v,u,v,u v,u,v,u - uint32x4_t UV_MULSvec = vld1q_u32(UV_MULS); - uint8x8_t ZEROSvec =vld1_u8(ZEROS); - - uint32_t UVvec_int[8]; - if (grey) - { - memcpy(out, pY, width * height * sizeof(unsigned char)); - } - else - // YUV 4:2:0 - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j += 8) - { - // nY = *(pY + i * width + j); - // nV = *(pUV + (i / 2) * width + bytes_per_pixel * (j / 2)); - // nU = *(pUV + (i / 2) * width + bytes_per_pixel * (j / 2) + 1); - - uint8x8_t nYvec = vld1_u8(LOAD_Y(i,j)); - uint8x8_t nUVvec = vld1_u8(LOAD_V(i,j)); // v,u,v,u v,u,v,u - - nYvec = vmul_u8(nYvec, vcle_u8(nYvec,ZEROSvec)); - - // Yuv Convert - // nY -= 16; - // nU -= 128; - // nV -= 128; - - // nYvec = vsub_u8(nYvec, Y_SUBvec); - // nUVvec = vsub_u8(nYvec, UV_SUBvec); - - uint16x8_t nYvec16 = vmovl_u8(vsub_u8(nYvec, Y_SUBvec)); - uint16x8_t nUVvec16 = vmovl_u8(vsub_u8(nYvec, UV_SUBvec)); - - uint16x4_t Y_low4 = vget_low_u16(nYvec16); - uint16x4_t Y_high4 = vget_high_u16(nYvec16); - uint16x4_t UV_low4 = vget_low_u16(nUVvec16); - uint16x4_t UV_high4 = vget_high_u16(nUVvec16); - - uint32x4_t UV_low4_int = vmovl_u16(UV_low4); - uint32x4_t UV_high4_int = vmovl_u16(UV_high4); - - uint32x4_t Y_low4_int = vmull_n_u16(Y_low4, 1192); - uint32x4_t Y_high4_int = vmull_n_u16(Y_high4, 1192); - - uint32x4x2_t UV_uzp = vuzpq_u32(UV_low4_int, UV_high4_int); - - uint32x2_t Vl = vget_low_u32(UV_uzp.val[0]);// vld1_u32(UVvec_int); - uint32x2_t Vh = vget_high_u32(UV_uzp.val[0]);//vld1_u32(UVvec_int + 2); - - uint32x2x2_t Vll_ = vzip_u32(Vl, Vl); - uint32x4_t* Vll = (uint32x4_t*)(&Vll_); - - uint32x2x2_t Vhh_ = vzip_u32(Vh, Vh); - uint32x4_t* Vhh = (uint32x4_t*)(&Vhh_); - - uint32x2_t Ul = vget_low_u32(UV_uzp.val[1]); - uint32x2_t Uh = vget_high_u32(UV_uzp.val[1]); - - uint32x2x2_t Ull_ = vzip_u32(Ul, Ul); - uint32x4_t* Ull = (uint32x4_t*)(&Ull_); - - uint32x2x2_t Uhh_ = vzip_u32(Uh, Uh); - uint32x4_t* Uhh = (uint32x4_t*)(&Uhh_); - - uint32x4_t B_int_low = vmlaq_n_u32(Y_low4_int, *Ull, 2066); //multiply by scalar accum - uint32x4_t B_int_high = vmlaq_n_u32(Y_high4_int, *Uhh, 2066); //multiply by scalar accum - uint32x4_t G_int_low = vsubq_u32(Y_low4_int, vmlaq_n_u32(vmulq_n_u32(*Vll, 833), *Ull, 400)); - uint32x4_t G_int_high = vsubq_u32(Y_high4_int, vmlaq_n_u32(vmulq_n_u32(*Vhh, 833), *Uhh, 400)); - uint32x4_t R_int_low = vmlaq_n_u32(Y_low4_int, *Vll, 1634); //multiply by scalar accum - uint32x4_t R_int_high = vmlaq_n_u32(Y_high4_int, *Vhh, 1634); //multiply by scalar accum - - B_int_low = vshrq_n_u32 (B_int_low, 10); - B_int_high = vshrq_n_u32 (B_int_high, 10); - G_int_low = vshrq_n_u32 (G_int_low, 10); - G_int_high = vshrq_n_u32 (G_int_high, 10); - R_int_low = vshrq_n_u32 (R_int_low, 10); - R_int_high = vshrq_n_u32 (R_int_high, 10); - - - uint8x8x3_t RGB; - RGB.val[0] = vmovn_u16(vcombine_u16(vqmovn_u32 (R_int_low),vqmovn_u32 (R_int_high))); - RGB.val[1] = vmovn_u16(vcombine_u16(vqmovn_u32 (G_int_low),vqmovn_u32 (G_int_high))); - RGB.val[2] = vmovn_u16(vcombine_u16(vqmovn_u32 (B_int_low),vqmovn_u32 (B_int_high))); - - vst3_u8 (out+i*width*3 + j*3, RGB); - } - } - -} - diff --git a/android/android-opencv/jni/yuv420rgb888.s b/android/android-opencv/jni/yuv420rgb888.s deleted file mode 100644 index 570ccc7d2c..0000000000 --- a/android/android-opencv/jni/yuv420rgb888.s +++ /dev/null @@ -1,379 +0,0 @@ -; YUV-> RGB conversion code Copyright (C) 2008 Robin Watts (robin;wss.co.uk). -; -; Licensed under the GPL. If you need it under another license, contact me -; and ask. -; -; This program is free software ; you can redistribute it and/or modify -; it under the terms of the GNU General Public License as published by -; the Free Software Foundation ; either version 2 of the License, or -; (at your option) any later version. -; -; This program is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY ; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with this program ; if not, write to the Free Software -; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -; -; -; The algorithm used here is based heavily on one created by Sophie Wilson -; of Acorn/e-14/Broadcomm. Many thanks. -; -; Additional tweaks (in the fast fixup code) are from Paul Gardiner. -; -; The old implementation of YUV -> RGB did: -; -; R = CLAMP((Y-16)*1.164 + 1.596*V) -; G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V) -; B = CLAMP((Y-16)*1.164 + 2.018*U ) -; -; We're going to bend that here as follows: -; -; R = CLAMP(y + 1.596*V) -; G = CLAMP(y - 0.383*U - 0.813*V) -; B = CLAMP(y + 1.976*U ) -; -; where y = 0 for Y <= 16, -; y = ( Y-16)*1.164, for 16 < Y <= 239, -; y = (239-16)*1.164, for 239 < Y -; -; i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in -; anyway). We then pick the B_U factor so that B never exceeds 511. We then -; shrink the G_U factor in line with that to avoid a colour shift as much as -; possible. -; -; We're going to use tables to do it faster, but rather than doing it using -; 5 tables as as the above suggests, we're going to do it using just 3. -; -; We do this by working in parallel within a 32 bit word, and using one -; table each for Y U and V. -; -; Source Y values are 0 to 255, so 0.. 260 after scaling -; Source U values are -128 to 127, so -49.. 49(G), -253..251(B) after -; Source V values are -128 to 127, so -204..203(R), -104..103(G) after -; -; So total summed values: -; -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511 -; -; We need to pack R G and B into a 32 bit word, and because of Bs range we -; need 2 bits above the valid range of B to detect overflow, and another one -; to detect the sense of the overflow. We therefore adopt the following -; representation: -; -; osGGGGGgggggosBBBBBbbbosRRRRRrrr -; -; Each such word breaks down into 3 ranges. -; -; osGGGGGggggg osBBBBBbbb osRRRRRrrr -; -; Thus we have 8 bits for each B and R table entry, and 10 bits for G (good -; as G is the most noticable one). The s bit for each represents the sign, -; and o represents the overflow. -; -; For R and B we pack the table by taking the 11 bit representation of their -; values, and toggling bit 10 in the U and V tables. -; -; For the green case we calculate 4*G (thus effectively using 10 bits for the -; valid range) truncate to 12 bits. We toggle bit 11 in the Y table. - -; Theorarm library -; Copyright (C) 2009 Robin Watts for Pinknoise Productions Ltd - - AREA |.text|, CODE, READONLY - - EXPORT yuv420_2_rgb888 - EXPORT yuv420_2_rgb888_PROFILE - -; void yuv420_2_rgb565 -; uint8_t *dst_ptr -; uint8_t *y_ptr -; uint8_t *u_ptr -; uint8_t *v_ptr -; int width -; int height -; int y_span -; int uv_span -; int dst_span -; int *tables -; int dither - -CONST_flags - DCD 0x40080100 -yuv420_2_rgb888 - ; r0 = dst_ptr - ; r1 = y_ptr - ; r2 = u_ptr - ; r3 = v_ptr - ; <> = width - ; <> = height - ; <> = y_span - ; <> = uv_span - ; <> = dst_span - ; <> = y_table - ; <> = dither - STMFD r13!,{r4-r11,r14} - - LDR r8, [r13,#10*4] ; r8 = height - LDR r10,[r13,#11*4] ; r10= y_span - LDR r9, [r13,#13*4] ; r9 = dst_span - LDR r14,[r13,#14*4] ; r14= y_table - LDR r5, CONST_flags - LDR r11,[r13,#9*4] ; r11= width - ADD r4, r14, #256*4 - SUBS r8, r8, #1 - BLT end - BEQ trail_row1 -yloop1 - SUB r8, r8, r11,LSL #16 ; r8 = height-(width<<16) - ADDS r8, r8, #1<<16 ; if (width == 1) - BGE trail_pair1 ; just do 1 column -xloop1 - LDRB r11,[r2], #1 ; r11 = u = *u_ptr++ - LDRB r12,[r3], #1 ; r12 = v = *v_ptr++ - LDRB r7, [r1, r10] ; r7 = y2 = y_ptr[stride] - LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ - ADD r12,r12,#512 - LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] - LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] - LDR r7, [r14,r7, LSL #2] ; r7 = y2 = y_table[y2] - LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] - ADD r11,r11,r12 ; r11 = uv = u+v - - ADD r7, r7, r11 ; r7 = y2 + uv - ADD r6, r6, r11 ; r6 = y0 + uv - ANDS r12,r7, r5 - TSTEQ r6, r5 - BNE fix101 -return101 - ; Store the bottom one first - ADD r12,r0, r9 - STRB r7,[r12],#1 ; Store R - MOV r7, r7, ROR #22 - STRB r7,[r12],#1 ; Store G - MOV r7, r7, ROR #21 - STRB r7,[r12],#1 ; Store B - - ; Then store the top one - STRB r6,[r0], #1 ; Store R - MOV r6, r6, ROR #22 - STRB r6,[r0], #1 ; Store G - - LDRB r7, [r1, r10] ; r7 = y3 = y_ptr[stride] - LDRB r12,[r1], #1 ; r12= y1 = *y_ptr++ - MOV r6, r6, ROR #21 - LDR r7, [r14, r7, LSL #2] ; r7 = y3 = y_table[y2] - LDR r12,[r14, r12,LSL #2] ; r12= y1 = y_table[y0] - STRB r6,[r0], #1 ; Store B - - ADD r7, r7, r11 ; r7 = y3 + uv - ADD r6, r12,r11 ; r6 = y1 + uv - ANDS r12,r7, r5 - TSTEQ r6, r5 - BNE fix102 -return102 - ; Store the bottom one first - ADD r12,r0, r9 - STRB r7,[r12],#1 ; Store R - MOV r7, r7, ROR #22 - STRB r7,[r12],#1 ; Store G - MOV r7, r7, ROR #21 - STRB r7,[r12],#1 ; Store B - - ; Then store the top one - STRB r6,[r0], #1 ; Store R - MOV r6, r6, ROR #22 - STRB r6,[r0], #1 ; Store G - MOV r6, r6, ROR #21 - STRB r6,[r0], #1 ; Store B - - ADDS r8, r8, #2<<16 - BLT xloop1 - MOVS r8, r8, LSL #16 ; Clear the top 16 bits of r8 - MOV r8, r8, LSR #16 ; If the C bit is clear we still have - BCC trail_pair1 ; 1 more pixel pair to do -end_xloop1 - LDR r11,[r13,#9*4] ; r11= width - LDR r12,[r13,#12*4] ; r12= uv_stride - ADD r0, r0, r9, LSL #1 - SUB r0, r0, r11,LSL #1 - SUB r0, r0, r11 - ADD r1, r1, r10,LSL #1 - SUB r1, r1, r11 - SUB r2, r2, r11,LSR #1 - SUB r3, r3, r11,LSR #1 - ADD r2, r2, r12 - ADD r3, r3, r12 - - SUBS r8, r8, #2 - BGT yloop1 - - LDMLTFD r13!,{r4-r11,pc} -trail_row1 - ; We have a row of pixels left to do - SUB r8, r8, r11,LSL #16 ; r8 = height-(width<<16) - ADDS r8, r8, #1<<16 ; if (width == 1) - BGE trail_pix1 ; just do 1 pixel -xloop12 - LDRB r11,[r2], #1 ; r11 = u = *u_ptr++ - LDRB r12,[r3], #1 ; r12 = v = *v_ptr++ - LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ - LDRB r7, [r1], #1 ; r7 = y1 = *y_ptr++ - ADD r12,r12,#512 - LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] - LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] - LDR r7, [r14,r7, LSL #2] ; r7 = y1 = y_table[y1] - LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] - ADD r11,r11,r12 ; r11 = uv = u+v - - ADD r6, r6, r11 ; r6 = y0 + uv - ADD r7, r7, r11 ; r7 = y1 + uv - ANDS r12,r7, r5 - TSTEQ r6, r5 - BNE fix104 -return104 - ; Store the bottom one first - STRB r6,[r0], #1 ; Store R - MOV r6, r6, ROR #22 - STRB r6,[r0], #1 ; Store G - MOV r6, r6, ROR #21 - STRB r6,[r0], #1 ; Store B - - ; Then store the top one - STRB r7,[r0], #1 ; Store R - MOV r7, r7, ROR #22 - STRB r7,[r0], #1 ; Store G - MOV r7, r7, ROR #21 - STRB r7,[r0], #1 ; Store B - - ADDS r8, r8, #2<<16 - BLT xloop12 - MOVS r8, r8, LSL #16 ; Clear the top 16 bits of r8 - MOV r8, r8, LSR #16 ; If the C bit is clear we still have - BCC trail_pix1 ; 1 more pixel pair to do -end - LDMFD r13!,{r4-r11,pc} -trail_pix1 - ; We have a single extra pixel to do - LDRB r11,[r2], #1 ; r11 = u = *u_ptr++ - LDRB r12,[r3], #1 ; r12 = v = *v_ptr++ - LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ - ADD r12,r12,#512 - LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] - LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] - LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] - ADD r11,r11,r12 ; r11 = uv = u+v - - ADD r6, r6, r11 ; r6 = y0 + uv - ANDS r12,r6, r5 - BNE fix105 -return105 - STRB r6,[r0], #1 ; Store R - MOV r6, r6, ROR #22 - STRB r6,[r0], #1 ; Store G - MOV r6, r6, ROR #21 - STRB r6,[r0], #1 ; Store B - - LDMFD r13!,{r4-r11,pc} - -trail_pair1 - ; We have a pair of pixels left to do - LDRB r11,[r2] ; r11 = u = *u_ptr++ - LDRB r12,[r3] ; r12 = v = *v_ptr++ - LDRB r7, [r1, r10] ; r7 = y2 = y_ptr[stride] - LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ - ADD r12,r12,#512 - LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] - LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] - LDR r7, [r14,r7, LSL #2] ; r7 = y2 = y_table[y2] - LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] - ADD r11,r11,r12 ; r11 = uv = u+v - - ADD r7, r7, r11 ; r7 = y2 + uv - ADD r6, r6, r11 ; r6 = y0 + uv - ANDS r12,r7, r5 - TSTEQ r6, r5 - BNE fix103 -return103 - ; Store the bottom one first - ADD r12,r0, r9 - STRB r7,[r12],#1 ; Store R - MOV r7, r7, ROR #22 - STRB r7,[r12],#1 ; Store G - MOV r7, r7, ROR #21 - STRB r7,[r12],#1 ; Store B - - ; Then store the top one - STRB r6,[r0], #1 ; Store R - MOV r6, r6, ROR #22 - STRB r6,[r0], #1 ; Store G - MOV r6, r6, ROR #21 - STRB r6,[r0], #1 ; Store B - B end_xloop1 -fix101 - ; r7 and r6 are the values, at least one of which has overflowed - ; r12 = r7 & mask = .s......s......s...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... - ADD r7, r7, r12,LSR #8 ; r7 = fixed value - - AND r12, r6, r5 ; r12 = .S......S......S...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... - ADD r6, r6, r12,LSR #8 ; r6 = fixed value - B return101 -fix102 - ; r7 and r6 are the values, at least one of which has overflowed - ; r12 = r7 & mask = .s......s......s...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... - ADD r7, r7, r12,LSR #8 ; r7 = fixed value - - AND r12, r6, r5 ; r12 = .S......S......S...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS..SSSSS.SSSSSS - ORR r6, r6, r12 ; r6 |= ..SSSSSS..SSSSS.SSSSSS - BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... - ADD r6, r6, r12,LSR #8 ; r6 = fixed value - B return102 -fix103 - ; r7 and r6 are the values, at least one of which has overflowed - ; r12 = r7 & mask = .s......s......s...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... - ADD r7, r7, r12,LSR #8 ; r7 = fixed value - - AND r12, r6, r5 ; r12 = .S......S......S...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... - ADD r6, r6, r12,LSR #8 ; r6 = fixed value - B return103 -fix104 - ; r7 and r6 are the values, at least one of which has overflowed - ; r12 = r7 & mask = .s......s......s...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... - ADD r7, r7, r12,LSR #8 ; r7 = fixed value - - AND r12, r6, r5 ; r12 = .S......S......S...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... - ADD r6, r6, r12,LSR #8 ; r6 = fixed value - B return104 -fix105 - ; r6 is the value, which has has overflowed - ; r12 = r7 & mask = .s......s......s...... - SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS - ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS - BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... - ADD r6, r6, r12,LSR #8 ; r6 = fixed value - B return105 - - END diff --git a/android/android-opencv/jni/yuv420rgb888c.c b/android/android-opencv/jni/yuv420rgb888c.c deleted file mode 100644 index c7ec52e34e..0000000000 --- a/android/android-opencv/jni/yuv420rgb888c.c +++ /dev/null @@ -1,208 +0,0 @@ -/* YUV-> RGB conversion code. (YUV420 to RGB565) - * - * Copyright (C) 2008-9 Robin Watts (robin@wss.co.uk) for Pinknoise - * Productions Ltd. - * - * Licensed under the GNU GPL. If you need it under another license, contact - * me and ask. - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation ; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY ; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program ; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * The algorithm used here is based heavily on one created by Sophie Wilson - * of Acorn/e-14/Broadcomm. Many thanks. - * - * Additional tweaks (in the fast fixup code) are from Paul Gardiner. - * - * The old implementation of YUV -> RGB did: - * - * R = CLAMP((Y-16)*1.164 + 1.596*V) - * G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V) - * B = CLAMP((Y-16)*1.164 + 2.018*U ) - * - * We're going to bend that here as follows: - * - * R = CLAMP(y + 1.596*V) - * G = CLAMP(y - 0.383*U - 0.813*V) - * B = CLAMP(y + 1.976*U ) - * - * where y = 0 for Y <= 16, - * y = ( Y-16)*1.164, for 16 < Y <= 239, - * y = (239-16)*1.164, for 239 < Y - * - * i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in - * anyway). We then pick the B_U factor so that B never exceeds 511. We then - * shrink the G_U factor in line with that to avoid a colour shift as much as - * possible. - * - * We're going to use tables to do it faster, but rather than doing it using - * 5 tables as as the above suggests, we're going to do it using just 3. - * - * We do this by working in parallel within a 32 bit word, and using one - * table each for Y U and V. - * - * Source Y values are 0 to 255, so 0.. 260 after scaling - * Source U values are -128 to 127, so -49.. 49(G), -253..251(B) after - * Source V values are -128 to 127, so -204..203(R), -104..103(G) after - * - * So total summed values: - * -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511 - * - * We need to pack R G and B into a 32 bit word, and because of Bs range we - * need 2 bits above the valid range of B to detect overflow, and another one - * to detect the sense of the overflow. We therefore adopt the following - * representation: - * - * osGGGGGgggggosBBBBBbbbosRRRRRrrr - * - * Each such word breaks down into 3 ranges. - * - * osGGGGGggggg osBBBBBbbb osRRRRRrrr - * - * Thus we have 8 bits for each B and R table entry, and 10 bits for G (good - * as G is the most noticable one). The s bit for each represents the sign, - * and o represents the overflow. - * - * For R and B we pack the table by taking the 11 bit representation of their - * values, and toggling bit 10 in the U and V tables. - * - * For the green case we calculate 4*G (thus effectively using 10 bits for the - * valid range) truncate to 12 bits. We toggle bit 11 in the Y table. - */ - -#include "yuv2rgb.h" - -enum -{ - FLAGS = 0x40080100 -}; - -#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) -#define READY(Y) tables[Y] -#define FIXUP(Y) \ -do { \ - int tmp = (Y) & FLAGS; \ - if (tmp != 0) \ - { \ - tmp -= tmp>>8; \ - (Y) |= tmp; \ - tmp = FLAGS & ~(Y>>1); \ - (Y) += tmp>>8; \ - } \ -} while (0 == 1) - -#define STORE(Y,DSTPTR) \ -do { \ - uint32_t Y2 = (Y); \ - uint8_t *DSTPTR2 = (DSTPTR); \ - (DSTPTR2)[0] = (Y2); \ - (DSTPTR2)[1] = (Y2)>>22; \ - (DSTPTR2)[2] = (Y2)>>11; \ -} while (0 == 1) - -void yuv420_2_rgb888(uint8_t *dst_ptr, - const uint8_t *y_ptr, - const uint8_t *u_ptr, - const uint8_t *v_ptr, - int32_t width, - int32_t height, - int32_t y_span, - int32_t uv_span, - int32_t dst_span, - const uint32_t *tables, - int32_t dither) -{ - height -= 1; - while (height > 0) - { - height -= width<<16; - height += 1<<16; - while (height < 0) - { - /* Do 2 column pairs */ - uint32_t uv, y0, y1; - - uv = READUV(*u_ptr++,*v_ptr++); - y1 = uv + READY(y_ptr[y_span]); - y0 = uv + READY(*y_ptr++); - FIXUP(y1); - FIXUP(y0); - STORE(y1, &dst_ptr[dst_span]); - STORE(y0, dst_ptr); - dst_ptr += 3; - y1 = uv + READY(y_ptr[y_span]); - y0 = uv + READY(*y_ptr++); - FIXUP(y1); - FIXUP(y0); - STORE(y1, &dst_ptr[dst_span]); - STORE(y0, dst_ptr); - dst_ptr += 3; - height += (2<<16); - } - if ((height>>16) == 0) - { - /* Trailing column pair */ - uint32_t uv, y0, y1; - - uv = READUV(*u_ptr,*v_ptr); - y1 = uv + READY(y_ptr[y_span]); - y0 = uv + READY(*y_ptr++); - FIXUP(y1); - FIXUP(y0); - STORE(y0, &dst_ptr[dst_span]); - STORE(y1, dst_ptr); - dst_ptr += 3; - } - dst_ptr += dst_span*2-width*3; - y_ptr += y_span*2-width; - u_ptr += uv_span-(width>>1); - v_ptr += uv_span-(width>>1); - height = (height<<16)>>16; - height -= 2; - } - if (height == 0) - { - /* Trail row */ - height -= width<<16; - height += 1<<16; - while (height < 0) - { - /* Do a row pair */ - uint32_t uv, y0, y1; - - uv = READUV(*u_ptr++,*v_ptr++); - y1 = uv + READY(*y_ptr++); - y0 = uv + READY(*y_ptr++); - FIXUP(y1); - FIXUP(y0); - STORE(y1, dst_ptr); - dst_ptr += 3; - STORE(y0, dst_ptr); - dst_ptr += 3; - height += (2<<16); - } - if ((height>>16) == 0) - { - /* Trailing pix */ - uint32_t uv, y0; - - uv = READUV(*u_ptr++,*v_ptr++); - y0 = uv + READY(*y_ptr++); - FIXUP(y0); - STORE(y0, dst_ptr); - dst_ptr += 3; - } - } -} diff --git a/android/android-opencv/jni/yuv420sp2rgb.c b/android/android-opencv/jni/yuv420sp2rgb.c deleted file mode 100644 index ef2eea30da..0000000000 --- a/android/android-opencv/jni/yuv420sp2rgb.c +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include - -#include -#include - -/* - YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved - U/V plane containing 8 bit 2x2 subsampled chroma samples. - except the interleave order of U and V is reversed. - - H V - Y Sample Period 1 1 - U (Cb) Sample Period 2 2 - V (Cr) Sample Period 2 2 - */ - -/* - size of a char: - find . -name limits.h -exec grep CHAR_BIT {} \; - */ - -#ifndef max -#define max(a,b) (a > b ? a : b ) -#define min(a,b) (a < b ? a : b ) -#endif -enum -{ - FLAGS = 0x40080100 -}; - -#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) -#define READY(Y) tables[Y] -#define FIXUP(Y) \ -do { \ - int tmp = (Y) & FLAGS; \ - if (tmp != 0) \ - { \ - tmp -= tmp>>8; \ - (Y) |= tmp; \ - tmp = FLAGS & ~(Y>>1); \ - (Y) += tmp>>8; \ - } \ -} while (0 == 1) - -#define STORE(Y,DSTPTR) \ -do { \ - uint32_t Y2 = (Y); \ - uint8_t *DSTPTR2 = (DSTPTR); \ - (DSTPTR2)[2] = (Y2); \ - (DSTPTR2)[1] = (Y2)>>22; \ - (DSTPTR2)[0] = (Y2)>>11; \ -} while (0 == 1) - -typedef unsigned char byte; -const int bytes_per_pixel = 2; -void color_convert_common(const unsigned char *pY, const unsigned char *pUV, int width, int height, - unsigned char *buffer, int grey) -{ -#define LOOKUP 1 -#if ! LOOKUP - int nR, nG, nB; -#endif - int dest_span = 3 * width; - unsigned char *out = buffer; - if (grey) - { - memcpy(out, pY, width * height * sizeof(unsigned char)); - } - else - { - -#if LOOKUP - const uint32_t* tables = yuv2rgb565_table; - const byte* nY = pY; - const byte* nUV = pUV; - int idx = 0; - while (nY+width < pUV) - { - int y = (idx / width); - int x = (idx % width); - byte Y = *nY; - byte Y2 = nY[width]; - byte V = *nUV; - byte U = *(nUV + 1); - /* Do 2 row pairs */ - uint32_t uv, y0, y1; - - uv = READUV(U,V); - y1 = uv + READY(Y); - y0 = uv + READY(Y2); - FIXUP(y1); - FIXUP(y0); - STORE(y1, &out[dest_span]); - STORE(y0, out); - out += 3; - Y = *(++nY); - Y2 = nY[width]; - y1 = uv + READY(Y); - y0 = uv + READY(Y2); - FIXUP(y1); - FIXUP(y0); - STORE(y1, &out[dest_span]); - STORE(y0, out); - out += 3; - height += (2 << 16); - ++nY; - nUV = pUV + (y / 2) * width + 2 * (x / 2); - idx+=2; - } -#else - const byte* nY = pY; - const byte* nUV = pUV; - int idx = 0; - while (nY < pUV) - { - - int y = (idx / width); - int x = (idx % width); - int Y = *nY; - int V = *nUV; - int U = *(nUV + 1); - - Y -= 16; - V -= 128; - U -= 128; - if (y < 0) - y = 0; - - nB = (int)(1192 * Y + 2066 * U); - nG = (int)(1192 * Y - 833 * V - 400 * U); - nR = (int)(1192 * Y + 1634 * V); - - nR = min(262143, max(0, nR)); - nG = min(262143, max(0, nG)); - nB = min(262143, max(0, nB)); - - nR >>= 10; - nR &= 0xff; - nG >>= 10; - nG &= 0xff; - nB >>= 10; - nB &= 0xff; - - *(out++) = (unsigned char)nR; - *(out++) = (unsigned char)nG; - *(out++) = (unsigned char)nB; - nY += 1; - nUV = pUV + (y / 2) * width + 2 * (x / 2); - ++idx; - } -#endif - } - - -} diff --git a/android/android-opencv/project_create.sh b/android/android-opencv/project_create.sh deleted file mode 100755 index 0a1b6bd308..0000000000 --- a/android/android-opencv/project_create.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -#this generates an ant based cli build of the android-jni project -android update project --name android-opencv \ ---path . diff --git a/android/android-opencv/res/drawable-mdpi/cameraback.jpg b/android/android-opencv/res/drawable-mdpi/cameraback.jpg deleted file mode 100644 index b53ffd4891..0000000000 Binary files a/android/android-opencv/res/drawable-mdpi/cameraback.jpg and /dev/null differ diff --git a/android/android-opencv/res/layout/calibrationviewer.xml b/android/android-opencv/res/layout/calibrationviewer.xml deleted file mode 100644 index 00dea195c3..0000000000 --- a/android/android-opencv/res/layout/calibrationviewer.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/android/android-opencv/res/layout/camera.xml b/android/android-opencv/res/layout/camera.xml deleted file mode 100644 index 560e3d429a..0000000000 --- a/android/android-opencv/res/layout/camera.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - diff --git a/android/android-opencv/res/layout/camerasettings.xml b/android/android-opencv/res/layout/camerasettings.xml deleted file mode 100644 index 4366ad396d..0000000000 --- a/android/android-opencv/res/layout/camerasettings.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/android-opencv/res/layout/chesssizer.xml b/android/android-opencv/res/layout/chesssizer.xml deleted file mode 100644 index b93bc0bdea..0000000000 --- a/android/android-opencv/res/layout/chesssizer.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/android/android-opencv/res/values/attrs.xml b/android/android-opencv/res/values/attrs.xml deleted file mode 100644 index 89727ff51b..0000000000 --- a/android/android-opencv/res/values/attrs.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/android/android-opencv/res/values/chessnumbers.xml b/android/android-opencv/res/values/chessnumbers.xml deleted file mode 100644 index c0b37fa9b5..0000000000 --- a/android/android-opencv/res/values/chessnumbers.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 - - -Choose the width: - -Choose the height: - diff --git a/android/android-opencv/res/values/settingnumbers.xml b/android/android-opencv/res/values/settingnumbers.xml deleted file mode 100644 index 54771c1e53..0000000000 --- a/android/android-opencv/res/values/settingnumbers.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - -320x240 -400x300 -640x480 -800x600 -1000x800 - - -color -BW - - -Image Size:\n(may not be exact) - - -Camera Mode: - - - -auto -incandescent -fluorescent -daylight -cloudy-daylight - - -Whitebalance: - - \ No newline at end of file diff --git a/android/android-opencv/res/values/strings.xml b/android/android-opencv/res/values/strings.xml deleted file mode 100644 index 541de3682b..0000000000 --- a/android/android-opencv/res/values/strings.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - Calibration - Pattern Size - Please choose the width and height (number of inside corners) of the checker - board pattern you will be using for calibration. Default is 6 by 8 corners. You may find a checkerboard pattern at - http://opencv.willowgarage.com/pattern - - http://opencv.willowgarage.com/pattern - Camera Settings - Change the camera settings. Be aware that BW is much faster for previewing, than color. Also, if you change the image size, you should - rerun calibration. Default values: BW and 640x480 are a good start. - - Calibration calculations have started... - Calibration calculations has stopped. - Calibration finished, you camera is calibrated. - Calibration - Please capture atleast 10 images of the pattern! - - diff --git a/android/android-opencv/src/com/opencv/OpenCV.java b/android/android-opencv/src/com/opencv/OpenCV.java deleted file mode 100644 index 0fced8026f..0000000000 --- a/android/android-opencv/src/com/opencv/OpenCV.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.opencv; - -import java.util.LinkedList; - -import android.app.Activity; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.Window; -import android.view.WindowManager; -import android.view.ViewGroup.LayoutParams; -import android.widget.FrameLayout; -import android.widget.LinearLayout; - -import com.opencv.camera.NativePreviewer; -import com.opencv.camera.NativeProcessor; -import com.opencv.camera.NativeProcessor.PoolCallback; -import com.opencv.opengl.GL2CameraViewer; - -public class OpenCV extends Activity { - private NativePreviewer mPreview; - - private GL2CameraViewer glview; - - /* - * (non-Javadoc) - * - * @see android.app.Activity#onKeyUp(int, android.view.KeyEvent) - */ - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - - return super.onKeyUp(keyCode, event); - } - - /* - * (non-Javadoc) - * - * @see android.app.Activity#onKeyLongPress(int, android.view.KeyEvent) - */ - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - - return super.onKeyLongPress(keyCode, event); - } - - /** - * Avoid that the screen get's turned off by the system. - */ - public void disableScreenTurnOff() { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - /** - * Set's the orientation to landscape, as this is needed by AndAR. - */ - public void setOrientation() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - - /** - * Maximize the application. - */ - public void setFullscreen() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - public void setNoTitle() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // menu.add("Sample"); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // if(item.getTitle().equals("Sample")){ - // //do stuff... - // } - - return true; - - } - - @Override - public void onOptionsMenuClosed(Menu menu) { - // TODO Auto-generated method stub - super.onOptionsMenuClosed(menu); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setFullscreen(); - disableScreenTurnOff(); - - FrameLayout frame = new FrameLayout(getApplication()); - - // Create our Preview view and set it as the content of our activity. - mPreview = new NativePreviewer(getApplication(), 640, 480); - - LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - params.height = getWindowManager().getDefaultDisplay().getHeight(); - params.width = (int) (params.height * 4.0 / 2.88); - - LinearLayout vidlay = new LinearLayout(getApplication()); - - vidlay.setGravity(Gravity.CENTER); - vidlay.addView(mPreview, params); - frame.addView(vidlay); - - // make the glview overlay ontop of video preview - mPreview.setZOrderMediaOverlay(false); - - glview = new GL2CameraViewer(getApplication(), false, 0, 0); - glview.setZOrderMediaOverlay(true); - glview.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.FILL_PARENT)); - frame.addView(glview); - - setContentView(frame); - } - - @Override - protected void onPause() { - super.onPause(); - - mPreview.onPause(); - - glview.onPause(); - - - } - - @Override - protected void onResume() { - super.onResume(); - glview.onResume(); - LinkedList callbackstack = new LinkedList(); - callbackstack.add(glview.getDrawCallback()); - mPreview.addCallbackStack(callbackstack); - mPreview.onResume(); - - } - -} diff --git a/android/android-opencv/src/com/opencv/calibration/CalibrationViewer.java b/android/android-opencv/src/com/opencv/calibration/CalibrationViewer.java deleted file mode 100644 index 2ae6b7871d..0000000000 --- a/android/android-opencv/src/com/opencv/calibration/CalibrationViewer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.opencv.calibration; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; - -import android.app.Activity; -import android.os.Bundle; -import android.text.method.ScrollingMovementMethod; -import android.util.Log; -import android.widget.TextView; - -import com.opencv.R; - -public class CalibrationViewer extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - // TODO Auto-generated method stub - super.onCreate(savedInstanceState); - setContentView(R.layout.calibrationviewer); - - Bundle extras = getIntent().getExtras(); - String filename = extras.getString("calibfile"); - if (filename != null) { - TextView text = (TextView) findViewById(R.id.calibtext); - text.setMovementMethod(new ScrollingMovementMethod()); - try { - BufferedReader reader = new BufferedReader(new FileReader( - filename)); - while (reader.ready()) { - text.append(reader.readLine() +"\n"); - } - - } catch (FileNotFoundException e) { - Log.e("opencv", "could not open calibration file at:" - + filename); - } catch (IOException e) { - Log.e("opencv", "error reading file: " - + filename); - } - } - - } - -} diff --git a/android/android-opencv/src/com/opencv/calibration/Calibrator.java b/android/android-opencv/src/com/opencv/calibration/Calibrator.java deleted file mode 100644 index 699a196e83..0000000000 --- a/android/android-opencv/src/com/opencv/calibration/Calibrator.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.opencv.calibration; - - -import java.io.File; -import java.io.IOException; -import java.util.concurrent.locks.ReentrantLock; - -import android.os.AsyncTask; - -import com.opencv.camera.NativeProcessor; -import com.opencv.camera.NativeProcessor.PoolCallback; -import com.opencv.jni.Calibration; -import com.opencv.jni.Size; -import com.opencv.jni.image_pool; - - - -public class Calibrator implements PoolCallback { - private Calibration calibration; - - static public interface CalibrationCallback{ - public void onFoundChessboard(Calibrator calibrator); - public void onDoneCalibration(Calibrator calibration, File calibfile); - public void onFailedChessboard(Calibrator calibrator); - } - private CalibrationCallback callback; - public Calibrator(CalibrationCallback callback) { - calibration = new Calibration(); - this.callback = callback; - } - - public void resetCalibration(){ - calibration.resetChess(); - } - - public void setPatternSize(Size size){ - Size csize = calibration.getPatternsize(); - if(size.getWidth() == csize.getWidth()&& - size.getHeight() == csize.getHeight()) - return; - calibration.setPatternsize(size); - resetCalibration(); - } - public void setPatternSize(int width, int height){ - Size patternsize = new Size(width,height); - setPatternSize(patternsize); - } - - private boolean capture_chess; - - ReentrantLock lock = new ReentrantLock(); - public void calibrate(File calibration_file) throws IOException{ - if(getNumberPatternsDetected() < 3){ - return; - } - CalibrationTask calibtask = new CalibrationTask(calibration_file); - calibtask.execute((Object[])null); - } - - public void queueChessCapture(){ - capture_chess = true; - } - -private class CalibrationTask extends AsyncTask { - File calibfile; - - public CalibrationTask(File calib) throws IOException{ - super(); - calibfile = calib; - calibfile.createNewFile(); - } - - @Override - protected Object doInBackground(Object... params) { - lock.lock(); - try{ - calibration.calibrate(calibfile.getAbsolutePath()); - } - finally{ - lock.unlock(); - } - return null; - - } - - @Override - protected void onPostExecute(Object result) { - callback.onDoneCalibration(Calibrator.this, calibfile); - } - - } - - - //@Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - if(lock.tryLock()){ - try{ - if(capture_chess){ - if(calibration.detectAndDrawChessboard(idx, pool)){ - callback.onFoundChessboard(this); - - }else - callback.onFailedChessboard(this); - capture_chess = false; - } - }finally{ - lock.unlock(); - } - } - } - - - public int getNumberPatternsDetected(){ - return calibration.getNumberDetectedChessboards(); - } - - public void setCallback(CalibrationCallback callback) { - this.callback = callback; - - } - - -} diff --git a/android/android-opencv/src/com/opencv/calibration/ChessBoardChooser.java b/android/android-opencv/src/com/opencv/calibration/ChessBoardChooser.java deleted file mode 100644 index 461a37d9be..0000000000 --- a/android/android-opencv/src/com/opencv/calibration/ChessBoardChooser.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.opencv.calibration; - -import com.opencv.R; -import com.opencv.jni.Size; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.Spinner; - -public class ChessBoardChooser extends Activity { - public static final String CHESS_SIZE = "chess_size"; - public static final int DEFAULT_WIDTH = 6; - public static final int DEFAULT_HEIGHT = 8; - public static final int LOWEST = 2; - - class DimChooser implements OnItemSelectedListener { - private String dim; - - public DimChooser(String dim) { - this.dim = dim; - } - - @Override - public void onItemSelected(AdapterView arg0, View arg1, int pos, - long arg3) { - SharedPreferences settings = getSharedPreferences(CHESS_SIZE, 0); - Editor editor = settings.edit(); - editor.putInt(dim, pos + LOWEST); - editor.commit(); - } - - @Override - public void onNothingSelected(AdapterView arg0) { - } - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - // TODO Auto-generated method stub - super.onCreate(savedInstanceState); - setContentView(R.layout.chesssizer); - // Restore preferences - SharedPreferences settings = getSharedPreferences(CHESS_SIZE, 0); - int width = settings.getInt("width", 6); - - int height = settings.getInt("height", 8); - - Spinner wspin, hspin; - wspin = (Spinner) findViewById(R.id.rows); - hspin = (Spinner) findViewById(R.id.cols); - - wspin.setSelection(width - LOWEST); - hspin.setSelection(height - LOWEST); - - wspin.setOnItemSelectedListener(new DimChooser("width")); - hspin.setOnItemSelectedListener(new DimChooser("height")); - - } - - public static Size getPatternSize(Context ctx) { - SharedPreferences settings = ctx.getSharedPreferences(CHESS_SIZE, 0); - int width = settings.getInt("width", 6); - - int height = settings.getInt("height", 8); - - return new Size(width, height); - } - -} diff --git a/android/android-opencv/src/com/opencv/calibration/services/CalibrationService.java b/android/android-opencv/src/com/opencv/calibration/services/CalibrationService.java deleted file mode 100644 index 754e2f1ee3..0000000000 --- a/android/android-opencv/src/com/opencv/calibration/services/CalibrationService.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.opencv.calibration.services; - -import java.io.File; -import java.io.IOException; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Intent; -import android.os.Binder; -import android.os.IBinder; -import android.util.Log; -import android.widget.Toast; - - -import com.opencv.R; -import com.opencv.calibration.CalibrationViewer; -import com.opencv.calibration.Calibrator; -import com.opencv.calibration.Calibrator.CalibrationCallback; - - -public class CalibrationService extends Service implements CalibrationCallback { - - Class activity; - int icon; - File calibration_file; - public void startCalibrating(Class activitycaller,int icon_id, Calibrator calibrator, File calibration_file) - throws IOException { - activity = activitycaller; - icon = icon_id; - // Display a notification about us starting. We put an icon in the - // status bar. - showNotification(); - this.calibration_file = calibration_file; - calibrator.setCallback(this); - calibrator.calibrate(calibration_file); - - - } - - private NotificationManager mNM; - - /** - * Class for clients to access. Because we know this service always runs in - * the same process as its clients, we don't need to deal with IPC. - */ - public class CalibrationServiceBinder extends Binder { - public CalibrationService getService() { - return CalibrationService.this; - } - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.i("LocalService", "Received start id " + startId + ": " + intent); - // We want this service to continue running until it is explicitly - // stopped, so return sticky. - return START_NOT_STICKY; - } - - @Override - public void onCreate() { - mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - - - } - - @Override - public void onDestroy() { - // Cancel the persistent notification. - // mNM.cancel(R.string.calibration_service_started); - - // Tell the user we stopped. - Toast.makeText(this, R.string.calibration_service_finished, - Toast.LENGTH_SHORT).show(); - } - - private final IBinder mBinder = new CalibrationServiceBinder(); - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - /** - * Show a notification while this service is running. - */ - private void showNotification() { - // In this sample, we'll use the same text for the ticker and the - // expanded notification - CharSequence text = getText(R.string.calibration_service_started); - - // Set the icon, scrolling text and timestamp - Notification notification = new Notification(icon, text, - System.currentTimeMillis()); - - // The PendingIntent to launch our activity if the user selects this - // notification - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, - new Intent(this, activity), 0); - - // Set the info for the views that show in the notification panel. - notification.setLatestEventInfo(this, - getText(R.string.calibration_service_label), text, - contentIntent); - - notification.defaults |= Notification.DEFAULT_SOUND; - // Send the notification. - // We use a layout id because it is a unique number. We use it later to - // cancel. - mNM.notify(R.string.calibration_service_started, notification); - } - - /** - * Show a notification while this service is running. - */ - private void doneNotification() { - // In this sample, we'll use the same text for the ticker and the - // expanded notification - CharSequence text = getText(R.string.calibration_service_finished); - - // Set the icon, scrolling text and timestamp - Notification notification = new Notification(icon, text, - System.currentTimeMillis()); - - Intent intent = new Intent(this,CalibrationViewer.class); - intent.putExtra("calibfile", calibration_file.getAbsolutePath()); - // The PendingIntent to launch our activity if the user selects this - // notification - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, - intent, 0); - - - // Set the info for the views that show in the notification panel. - notification.setLatestEventInfo(this, - getText(R.string.calibration_service_label), text, - contentIntent); - - - notification.defaults |= Notification.DEFAULT_SOUND; - // Send the notification. - // We use a layout id because it is a unique number. We use it later to - // cancel. - mNM.notify(R.string.calibration_service_started, notification); - } - - @Override - public void onFoundChessboard(Calibrator calibrator) { - // TODO Auto-generated method stub - - } - - @Override - public void onDoneCalibration(Calibrator calibration, File calibfile) { - doneNotification(); - stopSelf(); - } - - @Override - public void onFailedChessboard(Calibrator calibrator) { - // TODO Auto-generated method stub - - } - -} diff --git a/android/android-opencv/src/com/opencv/camera/CameraActivity.java b/android/android-opencv/src/com/opencv/camera/CameraActivity.java deleted file mode 100644 index ddb35a5649..0000000000 --- a/android/android-opencv/src/com/opencv/camera/CameraActivity.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.opencv.camera; - -import java.util.LinkedList; - -import android.app.Activity; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.Window; -import android.view.WindowManager; -import android.widget.LinearLayout; - -import com.opencv.camera.CameraButtonsHandler.CaptureListener; -import com.opencv.opengl.GL2CameraViewer; - -public abstract class CameraActivity extends Activity implements CaptureListener { - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setFullscreen(); - setOrientation(); - disableScreenTurnOff(); - setContentView(com.opencv.R.layout.camera); - cameraButtonHandler = new CameraButtonsHandler(this,this); - mPreview = (NativePreviewer) findViewById(com.opencv.R.id.nativepreviewer); - LinearLayout glview_layout = (LinearLayout) findViewById(com.opencv.R.id.glview_layout); - glview = new GL2CameraViewer(getApplication(), true, 0, 0); - glview_layout.addView(glview); - } - - /** - * Handle the capture button as follows... - */ - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - - switch (keyCode) { - case KeyEvent.KEYCODE_CAMERA: - case KeyEvent.KEYCODE_SPACE: - case KeyEvent.KEYCODE_DPAD_CENTER: - cameraButtonHandler.setIsCapture(true); - return true; - - default: - return super.onKeyUp(keyCode, event); - } - - } - - /** - * Handle the capture button as follows... On some phones there is no - * capture button, only trackball - */ - @Override - public boolean onTrackballEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - cameraButtonHandler.setIsCapture(true); - return true; - } - return super.onTrackballEvent(event); - } - - /** - * Avoid that the screen get's turned off by the system. - */ - public void disableScreenTurnOff() { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - /** - * Set's the orientation to landscape, as this is needed by AndAR. - */ - public void setOrientation() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - - /** - * Maximize the application. - */ - public void setFullscreen() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - @Override - protected void onPause() { - super.onPause(); - mPreview.onPause(); - glview.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - mPreview.setParamsFromPrefs(getApplicationContext()); - glview.onResume(); - mPreview.onResume(); - setCallbackStack(); - } - - protected void setCallbackStack() { - LinkedList callbackstack = getCallBackStack(); - if (callbackstack == null){ - callbackstack = new LinkedList(); - callbackstack.add(glview.getDrawCallback()); - } - mPreview.addCallbackStack(callbackstack); - } - - /** - * Overide this and provide your processors to the camera - * - * @return null for default drawing - */ - protected abstract LinkedList getCallBackStack(); - public void onCapture(){ - - } - - protected NativePreviewer mPreview; - protected GL2CameraViewer glview; - protected CameraButtonsHandler cameraButtonHandler; -} diff --git a/android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java b/android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java deleted file mode 100644 index bbf5c2d7b3..0000000000 --- a/android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.opencv.camera; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; - -public class CameraButtonsHandler { - /** Constructs a buttons handler, will register with the capture button - * and the camera settings button. - * @param a The activity that has inflated the com.opencv.R.layout.camera - * as its layout. - */ - public CameraButtonsHandler(Activity a, CaptureListener l) { - ImageButton capture = (ImageButton) a - .findViewById(com.opencv.R.id.button_capture); - ImageButton settings = (ImageButton) a - .findViewById(com.opencv.R.id.button_camera_settings); - capture.setOnClickListener(capture_listener); - settings.setOnClickListener(settings_listener); - captureListener = l; - ctx = a; - } - - public CameraButtonsHandler(Activity a) { - ImageButton capture = (ImageButton) a - .findViewById(com.opencv.R.id.button_capture); - ImageButton settings = (ImageButton) a - .findViewById(com.opencv.R.id.button_camera_settings); - capture.setOnClickListener(capture_listener); - settings.setOnClickListener(settings_listener); - ctx = a; - } - - - /** Check if the capture button has been pressed - * @return true if the capture button has been pressed - */ - synchronized public boolean isCapture(){ - return capture_flag; - } - - /** Reset the capture flag - */ - synchronized public void resetIsCapture(){ - capture_flag = false; - } - - /** Manually set the flag - call this on any event that should trigger - * a capture - * @param isCapture true if a capture should take place - */ - synchronized public void setIsCapture(boolean isCapture){ - capture_flag = isCapture; - if(capture_flag && captureListener != null){ - captureListener.onCapture(); - } - } - - private OnClickListener capture_listener = new View.OnClickListener() { - @Override - public void onClick(View v) { - setIsCapture(true); - } - }; - private OnClickListener settings_listener = new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent configurer = new Intent(ctx, - CameraConfig.class); - ctx.startActivity(configurer); - } - }; - - interface CaptureListener{ - public void onCapture(); - } - private CaptureListener captureListener; - private Context ctx; - private boolean capture_flag = false; -} diff --git a/android/android-opencv/src/com/opencv/camera/CameraConfig.java b/android/android-opencv/src/com/opencv/camera/CameraConfig.java deleted file mode 100644 index fcedd1b28b..0000000000 --- a/android/android-opencv/src/com/opencv/camera/CameraConfig.java +++ /dev/null @@ -1,214 +0,0 @@ -package com.opencv.camera; - -import com.opencv.R; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.Spinner; - -public class CameraConfig extends Activity { - public static final String CAMERA_SETTINGS = "CAMERA_SETTINGS"; - public static final String CAMERA_MODE = "camera_mode"; - public static final String IMAGE_WIDTH = "IMAGE_WIDTH"; - public static final String IMAGE_HEIGHT = "IMAGE_HEIGHT"; - public static final int CAMERA_MODE_BW = 0; - public static final int CAMERA_MODE_COLOR = 1; - private static final String WHITEBALANCE = "WHITEBALANCE"; - - public static int readCameraMode(Context ctx) { - // Restore preferences - SharedPreferences settings = ctx.getSharedPreferences(CAMERA_SETTINGS, - 0); - int mode = settings.getInt(CAMERA_MODE, CAMERA_MODE_BW); - return mode; - } - - public static String readWhitebalace(Context ctx) { - // Restore preferences - SharedPreferences settings = ctx.getSharedPreferences(CAMERA_SETTINGS, - 0); - return settings.getString(WHITEBALANCE, "auto"); - } - - static public void setCameraMode(Context context, String mode) { - int m = 0; - if (mode.equals("BW")) { - m = CAMERA_MODE_BW; - } else if (mode.equals("color")) - m = CAMERA_MODE_COLOR; - setCameraMode(context, m); - } - - private static String sizeToString(int[] size) { - return size[0] + "x" + size[1]; - } - - private static void parseStrToSize(String ssize, int[] size) { - String sz[] = ssize.split("x"); - size[0] = Integer.valueOf(sz[0]); - size[1] = Integer.valueOf(sz[1]); - } - - public static void readImageSize(Context ctx, int[] size) { - // Restore preferences - SharedPreferences settings = ctx.getSharedPreferences(CAMERA_SETTINGS, - 0); - size[0] = settings.getInt(IMAGE_WIDTH, 640); - size[1] = settings.getInt(IMAGE_HEIGHT, 480); - - } - - public static void setCameraMode(Context ctx, int mode) { - // Restore preferences - SharedPreferences settings = ctx.getSharedPreferences(CAMERA_SETTINGS, - 0); - Editor editor = settings.edit(); - editor.putInt(CAMERA_MODE, mode); - editor.commit(); - } - - public static void setImageSize(Context ctx, String strsize) { - int size[] = { 0, 0 }; - parseStrToSize(strsize, size); - setImageSize(ctx, size[0], size[1]); - } - - public static void setImageSize(Context ctx, int width, int height) { - // Restore preferences - SharedPreferences settings = ctx.getSharedPreferences(CAMERA_SETTINGS, - 0); - Editor editor = settings.edit(); - editor.putInt(IMAGE_WIDTH, width); - editor.putInt(IMAGE_HEIGHT, height); - editor.commit(); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - // TODO Auto-generated method stub - super.onCreate(savedInstanceState); - setContentView(R.layout.camerasettings); - int mode = readCameraMode(this); - int size[] = { 0, 0 }; - readImageSize(this, size); - - final Spinner size_spinner; - final Spinner mode_spinner; - final Spinner whitebalance_spinner; - size_spinner = (Spinner) findViewById(R.id.image_size); - mode_spinner = (Spinner) findViewById(R.id.camera_mode); - whitebalance_spinner = (Spinner) findViewById(R.id.whitebalance); - - String strsize = sizeToString(size); - String strmode = modeToString(mode); - String wbmode = readWhitebalace(getApplicationContext()); - - String sizes[] = getResources().getStringArray(R.array.image_sizes); - - int i = 1; - for (String x : sizes) { - if (x.equals(strsize)) - break; - i++; - } - if(i <= sizes.length) - size_spinner.setSelection(i-1); - - i = 1; - String modes[] = getResources().getStringArray(R.array.camera_mode); - for (String x :modes) { - if (x.equals(strmode)) - break; - i++; - } - if(i <= modes.length) - mode_spinner.setSelection(i-1); - - i = 1; - String wbmodes[] = getResources().getStringArray(R.array.whitebalance); - for (String x :wbmodes) { - if (x.equals(wbmode)) - break; - i++; - } - if(i <= wbmodes.length) - whitebalance_spinner.setSelection(i-1); - - size_spinner.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView arg0, View spinner, - int position, long arg3) { - Object o = size_spinner.getItemAtPosition(position); - if (o != null) - setImageSize(spinner.getContext(), (String) o); - } - - @Override - public void onNothingSelected(AdapterView arg0) { - - } - }); - mode_spinner.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView arg0, View spinner, - int position, long arg3) { - Object o = mode_spinner.getItemAtPosition(position); - if (o != null) - setCameraMode(spinner.getContext(), (String) o); - - } - - @Override - public void onNothingSelected(AdapterView arg0) { - - } - }); - - whitebalance_spinner.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView arg0, View spinner, - int position, long arg3) { - Object o = whitebalance_spinner.getItemAtPosition(position); - if (o != null) - setWhitebalance(spinner.getContext(), (String) o); - - } - - - @Override - public void onNothingSelected(AdapterView arg0) { - - } - }); - - } - - public static void setWhitebalance(Context ctx, String o) { - SharedPreferences settings = ctx.getSharedPreferences(CAMERA_SETTINGS, - 0); - Editor editor = settings.edit(); - editor.putString(WHITEBALANCE, o); - editor.commit(); - - } - - private String modeToString(int mode) { - switch (mode) { - case CAMERA_MODE_BW: - return "BW"; - case CAMERA_MODE_COLOR: - return "color"; - default: - return ""; - } - } -} diff --git a/android/android-opencv/src/com/opencv/camera/NativePreviewer.java b/android/android-opencv/src/com/opencv/camera/NativePreviewer.java deleted file mode 100644 index 1accee723e..0000000000 --- a/android/android-opencv/src/com/opencv/camera/NativePreviewer.java +++ /dev/null @@ -1,476 +0,0 @@ -package com.opencv.camera; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.hardware.Camera; -import android.hardware.Camera.PreviewCallback; -import android.hardware.Camera.Size; -import android.os.Handler; -import android.util.AttributeSet; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -import com.opencv.camera.NativeProcessor.NativeProcessorCallback; -import com.opencv.camera.NativeProcessor.PoolCallback; - -public class NativePreviewer extends SurfaceView implements - SurfaceHolder.Callback, Camera.PreviewCallback, NativeProcessorCallback { - - private String whitebalance_mode = "auto"; - - /** - * Constructor useful for defining a NativePreviewer in android layout xml - * - * @param context - * @param attributes - */ - public NativePreviewer(Context context, AttributeSet attributes) { - super(context, attributes); - listAllCameraMethods(); - // Install a SurfaceHolder.Callback so we get notified when the - // underlying surface is created and destroyed. - mHolder = getHolder(); - mHolder.addCallback(this); - mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - - /* - * TODO get this working! Can't figure out how to define these in xml - */ - preview_width = attributes.getAttributeIntValue("opencv", - "preview_width", 600); - preview_height = attributes.getAttributeIntValue("opencv", - "preview_height", 600); - - Log.d("NativePreviewer", "Trying to use preview size of " - + preview_width + " " + preview_height); - - processor = new NativeProcessor(); - - setZOrderMediaOverlay(false); - } - - /** - * - * @param context - * @param preview_width - * the desired camera preview width - will attempt to get as - * close to this as possible - * @param preview_height - * the desired camera preview height - */ - public NativePreviewer(Context context, int preview_width, - int preview_height) { - super(context); - - listAllCameraMethods(); - // Install a SurfaceHolder.Callback so we get notified when the - // underlying surface is created and destroyed. - mHolder = getHolder(); - mHolder.addCallback(this); - mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - - this.preview_width = preview_width; - this.preview_height = preview_height; - - processor = new NativeProcessor(); - setZOrderMediaOverlay(false); - - } - - /** - * Only call in the oncreate function of the instantiating activity - * - * @param width - * desired width - * @param height - * desired height - */ - public void setPreviewSize(int width, int height){ - preview_width = width; - preview_height = height; - - Log.d("NativePreviewer", "Trying to use preview size of " - + preview_width + " " + preview_height); - - } - - public void setParamsFromPrefs(Context ctx){ - int size[] ={0,0}; - CameraConfig.readImageSize(ctx, size); - int mode = CameraConfig.readCameraMode(ctx); - setPreviewSize(size[0], size[1]); - setGrayscale(mode == CameraConfig.CAMERA_MODE_BW ? true : false); - whitebalance_mode = CameraConfig.readWhitebalace(ctx); - } - - public void surfaceCreated(SurfaceHolder holder) { - - } - - public void surfaceDestroyed(SurfaceHolder holder) { - releaseCamera(); - } - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - - try { - initCamera(mHolder); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return; - } - - // Now that the size is known, set up the camera parameters and begin - // the preview. - - Camera.Parameters parameters = mCamera.getParameters(); - List pvsizes = mCamera.getParameters() - .getSupportedPreviewSizes(); - int best_width = 1000000; - int best_height = 1000000; - int bdist = 100000; - for (Size x : pvsizes) { - if (Math.abs(x.width - preview_width) < bdist) { - bdist = Math.abs(x.width - preview_width); - best_width = x.width; - best_height = x.height; - } - } - preview_width = best_width; - preview_height = best_height; - - Log.d("NativePreviewer", "Determined compatible preview size is: (" - + preview_width + "," + preview_height + ")"); - - Log.d("NativePreviewer", "Supported params: " - + mCamera.getParameters().flatten()); - - List whiteBalanceModes = parameters.getSupportedWhiteBalance(); - if (whiteBalanceModes != null - && whiteBalanceModes.contains(whitebalance_mode) ) { - parameters.setWhiteBalance(whitebalance_mode); - } - - if (parameters.get("meter-mode") != null) - parameters.set("meter-mode", "meter-average"); - - List fmodes = mCamera.getParameters().getSupportedFocusModes(); - if(fmodes != null) - { - int idx = fmodes.indexOf(Camera.Parameters.FOCUS_MODE_INFINITY); - if (idx != -1) { - parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); - } else if (fmodes.indexOf(Camera.Parameters.FOCUS_MODE_FIXED) != -1) { - parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); - } - - if (fmodes.indexOf(Camera.Parameters.FOCUS_MODE_AUTO) != -1) { - hasAutoFocus = true; - } - } - - List scenemodes = mCamera.getParameters() - .getSupportedSceneModes(); - if (scenemodes != null) - if (scenemodes.indexOf(Camera.Parameters.SCENE_MODE_ACTION) != -1) { - parameters.setSceneMode(Camera.Parameters.SCENE_MODE_ACTION); - Log.d("NativePreviewer", "set scenemode to action"); - } - - parameters.setPreviewSize(preview_width, preview_height); - - mCamera.setParameters(parameters); - - pixelinfo = new PixelFormat(); - pixelformat = mCamera.getParameters().getPreviewFormat(); - PixelFormat.getPixelFormatInfo(pixelformat, pixelinfo); - - Size preview_size = mCamera.getParameters().getPreviewSize(); - preview_width = preview_size.width; - preview_height = preview_size.height; - int bufSize = preview_width * preview_height * pixelinfo.bitsPerPixel - / 8; - - // Must call this before calling addCallbackBuffer to get all the - // reflection variables setup - initForACB(); - initForPCWB(); - - // Use only one buffer, so that we don't preview too many frames and bog - // down system - byte[] buffer = new byte[bufSize]; - addCallbackBuffer(buffer); - setPreviewCallbackWithBuffer(); - - mCamera.startPreview(); - - } - - public void postautofocus(int delay) { - if (hasAutoFocus) - handler.postDelayed(autofocusrunner, delay); - - } - - /** - * Demonstration of how to use onPreviewFrame. In this case I'm not - * processing the data, I'm just adding the buffer back to the buffer queue - * for re-use - */ - public void onPreviewFrame(byte[] data, Camera camera) { - - if (start == null) { - start = new Date(); - } - - processor.post(data, preview_width, preview_height, pixelformat, - System.nanoTime(), this); - - fcount++; - if (fcount % 100 == 0) { - double ms = (new Date()).getTime() - start.getTime(); - Log.i("NativePreviewer", "fps:" + fcount / (ms / 1000.0)); - start = new Date(); - fcount = 0; - } - - } - - @Override - public void onDoneNativeProcessing(byte[] buffer) { - addCallbackBuffer(buffer); - } - - public void addCallbackStack(LinkedList callbackstack) { - processor.addCallbackStack(callbackstack); - } - - /** - * This must be called when the activity pauses, in Activity.onPause This - * has the side effect of clearing the callback stack. - * - */ - public void onPause() { - - releaseCamera(); - - addCallbackStack(null); - - processor.stop(); - - } - - public void onResume() { - - processor.start(); - - } - - private Method mPCWB; - - private void initForPCWB() { - - try { - - mPCWB = Class.forName("android.hardware.Camera").getMethod( - "setPreviewCallbackWithBuffer", PreviewCallback.class); - - } catch (Exception e) { - Log.e("NativePreviewer", - "Problem setting up for setPreviewCallbackWithBuffer: " - + e.toString()); - } - - } - - /** - * This method allows you to add a byte buffer to the queue of buffers to be - * used by preview. See: - * http://android.git.kernel.org/?p=platform/frameworks - * /base.git;a=blob;f=core/java/android/hardware/Camera.java;hb=9d - * b3d07b9620b4269ab33f78604a36327e536ce1 - * - * @param b - * The buffer to register. Size should be width * height * - * bitsPerPixel / 8. - */ - private void addCallbackBuffer(byte[] b) { - - try { - - mAcb.invoke(mCamera, b); - } catch (Exception e) { - Log.e("NativePreviewer", - "invoking addCallbackBuffer failed: " + e.toString()); - } - } - - /** - * Use this method instead of setPreviewCallback if you want to use manually - * allocated buffers. Assumes that "this" implements Camera.PreviewCallback - */ - private void setPreviewCallbackWithBuffer() { - // mCamera.setPreviewCallback(this); - // return; - try { - - // If we were able to find the setPreviewCallbackWithBuffer method - // of Camera, - // we can now invoke it on our Camera instance, setting 'this' to be - // the - // callback handler - mPCWB.invoke(mCamera, this); - - // Log.d("NativePrevier","setPreviewCallbackWithBuffer: Called method"); - - } catch (Exception e) { - - Log.e("NativePreviewer", e.toString()); - } - } - - @SuppressWarnings("unused") - private void clearPreviewCallbackWithBuffer() { - // mCamera.setPreviewCallback(this); - // return; - try { - - // If we were able to find the setPreviewCallbackWithBuffer method - // of Camera, - // we can now invoke it on our Camera instance, setting 'this' to be - // the - // callback handler - mPCWB.invoke(mCamera, (PreviewCallback) null); - - // Log.d("NativePrevier","setPreviewCallbackWithBuffer: cleared"); - - } catch (Exception e) { - - Log.e("NativePreviewer", e.toString()); - } - } - - /** - * These variables are re-used over and over by addCallbackBuffer - */ - private Method mAcb; - - private void initForACB() { - try { - - mAcb = Class.forName("android.hardware.Camera").getMethod( - "addCallbackBuffer", byte[].class); - - } catch (Exception e) { - Log.e("NativePreviewer", - "Problem setting up for addCallbackBuffer: " + e.toString()); - } - } - - private Runnable autofocusrunner = new Runnable() { - - @Override - public void run() { - mCamera.autoFocus(autocallback); - } - }; - - private Camera.AutoFocusCallback autocallback = new Camera.AutoFocusCallback() { - - @Override - public void onAutoFocus(boolean success, Camera camera) { - if (!success) - postautofocus(1000); - } - }; - - /** - * This method will list all methods of the android.hardware.Camera class, - * even the hidden ones. With the information it provides, you can use the - * same approach I took below to expose methods that were written but hidden - * in eclair - */ - private void listAllCameraMethods() { - try { - Class c = Class.forName("android.hardware.Camera"); - Method[] m = c.getMethods(); - for (int i = 0; i < m.length; i++) { - Log.d("NativePreviewer", " method:" + m[i].toString()); - } - } catch (Exception e) { - // TODO Auto-generated catch block - Log.e("NativePreviewer", e.toString()); - } - } - - private void initCamera(SurfaceHolder holder) throws InterruptedException { - if (mCamera == null) { - // The Surface has been created, acquire the camera and tell it - // where - // to draw. - int i = 0; - while (i++ < 5) { - try { - mCamera = Camera.open(); - break; - } catch (RuntimeException e) { - Thread.sleep(200); - } - } - try { - mCamera.setPreviewDisplay(holder); - } catch (IOException exception) { - mCamera.release(); - mCamera = null; - - } catch (RuntimeException e) { - Log.e("camera", "stacktrace", e); - } - } - } - - private void releaseCamera() { - if (mCamera != null) { - // Surface will be destroyed when we return, so stop the preview. - // Because the CameraDevice object is not a shared resource, it's - // very - // important to release it when the activity is paused. - mCamera.stopPreview(); - mCamera.release(); - } - - // processor = null; - mCamera = null; - mAcb = null; - mPCWB = null; - } - - private Handler handler = new Handler(); - - private Date start; - private int fcount = 0; - private boolean hasAutoFocus = false; - private SurfaceHolder mHolder; - private Camera mCamera; - - private NativeProcessor processor; - - private int preview_width, preview_height; - private int pixelformat; - private PixelFormat pixelinfo; - - public void setGrayscale(boolean b) { - processor.setGrayscale(b); - - } - -} - diff --git a/android/android-opencv/src/com/opencv/camera/NativeProcessor.java b/android/android-opencv/src/com/opencv/camera/NativeProcessor.java deleted file mode 100644 index 4dce3bb617..0000000000 --- a/android/android-opencv/src/com/opencv/camera/NativeProcessor.java +++ /dev/null @@ -1,285 +0,0 @@ -package com.opencv.camera; - -import java.util.LinkedList; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import android.graphics.PixelFormat; -import android.util.Log; - -import com.opencv.jni.image_pool; -import com.opencv.jni.opencv; - -/** The NativeProcessor is a native processing stack engine. - * - * What this means is that the NativeProcessor handles loading - * live camera frames into native memory space, i.e. the image_pool - * and then calling a stack of PoolCallback's and passing them the - * image_pool. - * - * The image_pool index 0 is populated with the live video image - * - * And any modifications to this the pool are in place, so you may - * pass on changes to the pool to the next PoolCallback in the stack. - * - */ -public class NativeProcessor { - /** Users that would like to be able to have access to live video frames - * should implement a PoolCallback - * the idx and pool contain the images, specifically at idx == 0 is the - * live video frame. - */ - static public interface PoolCallback { - void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor); - } - - - - /**At every frame, each PoolCallback is called in order and is passed the - * the same pool and index - * - * @param stack A list of PoolCallback objects, that will be called in order - */ - public void addCallbackStack(LinkedList stack) { - - try { - while (!stacklock.tryLock(10, TimeUnit.MILLISECONDS)) { - - } - try { - nextStack = stack; - } finally { - stacklock.unlock(); - } - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - - } - - } - - /** - * Create a NativeProcessor. The processor will not start running until - * start is called, at which point it will operate in its own thread and - * sleep until a post is called. The processor should not be started until - * an onSurfaceChange event, and should be shut down when the surface is - * destroyed by calling interupt. - * - */ - public NativeProcessor() { - gray_scale_only = false; - } - - - - /** Grayscale only is much faster because the yuv does not get decoded, and grayscale is only one - * byter per pixel - giving fast opengl texture loading. - * - * You still have access to the whole yuv image, but grayscale is only immediately available to - * use without further effort. - * - * Suggestion - use grayscale only and save your yuv images to disk if you would like color images - * - * Also, in grayscale mode, the images in the pool are only single channel, so please keep this in mind - * when accessing the color images - check the cv::Mat::channels() or cv::Mat::type() if your messing - * with color channels - * - * @param grayscale true if you want to only process grayscale images - */ - public void setGrayscale(boolean grayscale){ - gray_scale_only = grayscale; - } - - - /** - * A callback that allows the NativeProcessor to pass back the buffer when - * it has completed processing a frame. - */ - static protected interface NativeProcessorCallback { - /** - * Called after processing, meant to be recieved by the NativePreviewer - * wich reuses the byte buffer for the camera preview... - * - * @param buffer - * the buffer passed to the NativeProcessor with post. - */ - void onDoneNativeProcessing(byte[] buffer); - } - - - protected void stop() { - mthread.interrupt(); - try { - mthread.join(); - } catch (InterruptedException e) { - Log.w("NativeProcessor", - "interupted while stoping " + e.getMessage()); - } - mthread = null; - } - - protected void start() { - mthread = new ProcessorThread(); - mthread.start(); - } - /** - * post is used to notify the processor that a preview frame is ready, this - * will return almost immediately. if the processor is busy, returns false - * and is essentially a nop. - * - * @param buffer - * a preview frame from the Android Camera onPreviewFrame - * callback - * @param width - * of preview frame - * @param height - * of preview frame - * @param format - * of preview frame - * @return true if the processor wasn't busy and accepted the post, false if - * the processor is still processing. - */ - - protected boolean post(byte[] buffer, int width, int height, int format, - long timestamp, NativeProcessorCallback callback) { - - lock.lock(); - try { - NPPostObject pobj = new NPPostObject(buffer, width, height, format, - timestamp, callback); - postobjects.addFirst(pobj); - } finally { - lock.unlock(); - } - return true; - - } - - private class ProcessorThread extends Thread { - - private void process(NPPostObject pobj) throws Exception { - - if (pobj.format == PixelFormat.YCbCr_420_SP) { - // add as color image, because we know how to decode this - opencv.addYUVtoPool(pool, pobj.buffer, 0, pobj.width, - pobj.height, gray_scale_only); - - } else if (pobj.format == PixelFormat.YCbCr_422_SP) { - // add as gray image, because this format is not coded - // for...//TODO figure out how to decode this - // format - opencv.addYUVtoPool(pool, pobj.buffer, 0, pobj.width, - pobj.height, true); - } else - throw new Exception("bad pixel format!"); - - for (PoolCallback x : stack) { - if (interrupted()) { - throw new InterruptedException( - "Native Processor interupted while processing"); - } - x.process(0, pool, pobj.timestamp, NativeProcessor.this); - } - - pobj.done(); // tell the postobject that we're done doing - // all the processing. - - } - - @Override - public void run() { - - try { - while (true) { - yield(); - - while (!stacklock.tryLock(5, TimeUnit.MILLISECONDS)) { - } - try { - if (nextStack != null) { - stack = nextStack; - nextStack = null; - } - } finally { - stacklock.unlock(); - } - - NPPostObject pobj = null; - - while (!lock.tryLock(5, TimeUnit.MILLISECONDS)) { - } - try { - if (postobjects.isEmpty()) - continue; - pobj = postobjects.removeLast(); - - } finally { - lock.unlock(); - - } - - if (interrupted()) - throw new InterruptedException(); - - if (stack != null && pobj != null) - process(pobj); - - } - } catch (InterruptedException e) { - - Log.i("NativeProcessor", - "native processor interupted, ending now"); - - } catch (Exception e) { - - e.printStackTrace(); - } finally { - - } - } - - } - - static private class NPPostObject { - public NPPostObject(byte[] buffer, int width, int height, int format, - long timestamp, NativeProcessorCallback callback) { - this.buffer = buffer; - this.width = width; - this.height = height; - this.format = format; - this.timestamp = timestamp; - this.callback = callback; - } - - public void done() { - callback.onDoneNativeProcessing(buffer); - - } - - int width, height; - byte[] buffer; - int format; - long timestamp; - NativeProcessorCallback callback; - } - - - private LinkedList postobjects = new LinkedList(); - - private image_pool pool = new image_pool(); - - private final Lock lock = new ReentrantLock(); - - private LinkedList stack = new LinkedList(); - private boolean gray_scale_only; - - private Lock stacklock = new ReentrantLock(); - - private LinkedList nextStack; - - private ProcessorThread mthread; - -} \ No newline at end of file diff --git a/android/android-opencv/src/com/opencv/opengl/GL2CameraViewer.java b/android/android-opencv/src/com/opencv/opengl/GL2CameraViewer.java deleted file mode 100644 index 237ae8251c..0000000000 --- a/android/android-opencv/src/com/opencv/opengl/GL2CameraViewer.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.opencv.opengl; -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.opengles.GL10; - -import com.opencv.camera.NativeProcessor; -import com.opencv.camera.NativeProcessor.PoolCallback; -import com.opencv.jni.glcamera; -import com.opencv.jni.image_pool; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.util.Log; - - - -/** - * A simple GLSurfaceView sub-class that demonstrate how to perform - * OpenGL ES 2.0 rendering into a GL Surface. Note the following important - * details: - * - * - The class must use a custom context factory to enable 2.0 rendering. - * See ContextFactory class definition below. - * - * - The class must use a custom EGLConfigChooser to be able to select - * an EGLConfig that supports 2.0. This is done by providing a config - * specification to eglChooseConfig() that has the attribute - * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag - * set. See ConfigChooser class definition below. - * - * - The class must select the surface's format, then choose an EGLConfig - * that matches it exactly (with regards to red/green/blue/alpha channels - * bit depths). Failure to do so would result in an EGL_BAD_MATCH error. - */ -public class GL2CameraViewer extends GLSurfaceView{ - private static String TAG = "GL2JNIView"; - private static final boolean DEBUG = false; - - private PoolCallback poolcallback = new PoolCallback() { - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor){ - - - drawMatToGL(idx, pool); - - requestRender(); - - - } - }; - - public GL2CameraViewer(Context context,AttributeSet attributeSet) { - super(context,attributeSet); - - init(false, 0, 0); - setZOrderMediaOverlay(true); - } - public GL2CameraViewer(Context context) { - super(context); - init(false, 0, 0); - setZOrderMediaOverlay(true); - } - - public GL2CameraViewer(Context context, boolean translucent, int depth, int stencil) { - super(context); - init(translucent, depth, stencil); - setZOrderMediaOverlay(true); - } - - private void init(boolean translucent, int depth, int stencil) { - - - /* By default, GLSurfaceView() creates a RGB_565 opaque surface. - * If we want a translucent one, we should change the surface's - * format here, using PixelFormat.TRANSLUCENT for GL Surfaces - * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. - */ - if (translucent) { - this.getHolder().setFormat(PixelFormat.TRANSLUCENT); - } - - /* Setup the context factory for 2.0 rendering. - * See ContextFactory class definition below - */ - setEGLContextFactory(new ContextFactory()); - - /* We need to choose an EGLConfig that matches the format of - * our surface exactly. This is going to be done in our - * custom config chooser. See ConfigChooser class definition - * below. - */ - setEGLConfigChooser( translucent ? - new ConfigChooser(8, 8, 8, 8, depth, stencil) : - new ConfigChooser(5, 6, 5, 0, depth, stencil) ); - - /* Set the renderer responsible for frame rendering */ - setRenderer(new Renderer()); - setRenderMode(RENDERMODE_WHEN_DIRTY); - - } - - private static class ContextFactory implements GLSurfaceView.EGLContextFactory { - private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - Log.w(TAG, "creating OpenGL ES 2.0 context"); - checkEglError("Before eglCreateContext", egl); - int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; - EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); - checkEglError("After eglCreateContext", egl); - return context; - } - - public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { - egl.eglDestroyContext(display, context); - } - } - - private static void checkEglError(String prompt, EGL10 egl) { - int error; - while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { - Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); - } - } - - private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { - - public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { - mRedSize = r; - mGreenSize = g; - mBlueSize = b; - mAlphaSize = a; - mDepthSize = depth; - mStencilSize = stencil; - } - - /* This EGL config specification is used to specify 2.0 rendering. - * We use a minimum size of 4 bits for red/green/blue, but will - * perform actual matching in chooseConfig() below. - */ - private static int EGL_OPENGL_ES2_BIT = 4; - private static int[] s_configAttribs2 = - { - EGL10.EGL_RED_SIZE, 4, - EGL10.EGL_GREEN_SIZE, 4, - EGL10.EGL_BLUE_SIZE, 4, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL10.EGL_NONE - }; - - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { - - /* Get the number of minimally matching EGL configurations - */ - int[] num_config = new int[1]; - egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); - - int numConfigs = num_config[0]; - - if (numConfigs <= 0) { - throw new IllegalArgumentException("No configs match configSpec"); - } - - /* Allocate then read the array of minimally matching EGL configs - */ - EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); - - if (DEBUG) { - printConfigs(egl, display, configs); - } - /* Now return the "best" one - */ - return chooseConfig(egl, display, configs); - } - - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - for(EGLConfig config : configs) { - int d = findConfigAttrib(egl, display, config, - EGL10.EGL_DEPTH_SIZE, 0); - int s = findConfigAttrib(egl, display, config, - EGL10.EGL_STENCIL_SIZE, 0); - - // We need at least mDepthSize and mStencilSize bits - if (d < mDepthSize || s < mStencilSize) - continue; - - // We want an *exact* match for red/green/blue/alpha - int r = findConfigAttrib(egl, display, config, - EGL10.EGL_RED_SIZE, 0); - int g = findConfigAttrib(egl, display, config, - EGL10.EGL_GREEN_SIZE, 0); - int b = findConfigAttrib(egl, display, config, - EGL10.EGL_BLUE_SIZE, 0); - int a = findConfigAttrib(egl, display, config, - EGL10.EGL_ALPHA_SIZE, 0); - - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) - return config; - } - return null; - } - - private int findConfigAttrib(EGL10 egl, EGLDisplay display, - EGLConfig config, int attribute, int defaultValue) { - - if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { - return mValue[0]; - } - return defaultValue; - } - - private void printConfigs(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - int numConfigs = configs.length; - Log.w(TAG, String.format("%d configurations", numConfigs)); - for (int i = 0; i < numConfigs; i++) { - Log.w(TAG, String.format("Configuration %d:\n", i)); - printConfig(egl, display, configs[i]); - } - } - - private void printConfig(EGL10 egl, EGLDisplay display, - EGLConfig config) { - int[] attributes = { - EGL10.EGL_BUFFER_SIZE, - EGL10.EGL_ALPHA_SIZE, - EGL10.EGL_BLUE_SIZE, - EGL10.EGL_GREEN_SIZE, - EGL10.EGL_RED_SIZE, - EGL10.EGL_DEPTH_SIZE, - EGL10.EGL_STENCIL_SIZE, - EGL10.EGL_CONFIG_CAVEAT, - EGL10.EGL_CONFIG_ID, - EGL10.EGL_LEVEL, - EGL10.EGL_MAX_PBUFFER_HEIGHT, - EGL10.EGL_MAX_PBUFFER_PIXELS, - EGL10.EGL_MAX_PBUFFER_WIDTH, - EGL10.EGL_NATIVE_RENDERABLE, - EGL10.EGL_NATIVE_VISUAL_ID, - EGL10.EGL_NATIVE_VISUAL_TYPE, - 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, - EGL10.EGL_SAMPLES, - EGL10.EGL_SAMPLE_BUFFERS, - EGL10.EGL_SURFACE_TYPE, - EGL10.EGL_TRANSPARENT_TYPE, - EGL10.EGL_TRANSPARENT_RED_VALUE, - EGL10.EGL_TRANSPARENT_GREEN_VALUE, - EGL10.EGL_TRANSPARENT_BLUE_VALUE, - 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, - 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, - 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, - 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, - EGL10.EGL_LUMINANCE_SIZE, - EGL10.EGL_ALPHA_MASK_SIZE, - EGL10.EGL_COLOR_BUFFER_TYPE, - EGL10.EGL_RENDERABLE_TYPE, - 0x3042 // EGL10.EGL_CONFORMANT - }; - String[] names = { - "EGL_BUFFER_SIZE", - "EGL_ALPHA_SIZE", - "EGL_BLUE_SIZE", - "EGL_GREEN_SIZE", - "EGL_RED_SIZE", - "EGL_DEPTH_SIZE", - "EGL_STENCIL_SIZE", - "EGL_CONFIG_CAVEAT", - "EGL_CONFIG_ID", - "EGL_LEVEL", - "EGL_MAX_PBUFFER_HEIGHT", - "EGL_MAX_PBUFFER_PIXELS", - "EGL_MAX_PBUFFER_WIDTH", - "EGL_NATIVE_RENDERABLE", - "EGL_NATIVE_VISUAL_ID", - "EGL_NATIVE_VISUAL_TYPE", - "EGL_PRESERVED_RESOURCES", - "EGL_SAMPLES", - "EGL_SAMPLE_BUFFERS", - "EGL_SURFACE_TYPE", - "EGL_TRANSPARENT_TYPE", - "EGL_TRANSPARENT_RED_VALUE", - "EGL_TRANSPARENT_GREEN_VALUE", - "EGL_TRANSPARENT_BLUE_VALUE", - "EGL_BIND_TO_TEXTURE_RGB", - "EGL_BIND_TO_TEXTURE_RGBA", - "EGL_MIN_SWAP_INTERVAL", - "EGL_MAX_SWAP_INTERVAL", - "EGL_LUMINANCE_SIZE", - "EGL_ALPHA_MASK_SIZE", - "EGL_COLOR_BUFFER_TYPE", - "EGL_RENDERABLE_TYPE", - "EGL_CONFORMANT" - }; - int[] value = new int[1]; - for (int i = 0; i < attributes.length; i++) { - int attribute = attributes[i]; - String name = names[i]; - if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { - Log.w(TAG, String.format(" %s: %d\n", name, value[0])); - } else { - // Log.w(TAG, String.format(" %s: failed\n", name)); - while (egl.eglGetError() != EGL10.EGL_SUCCESS); - } - } - } - - // Subclasses can adjust these values: - protected int mRedSize; - protected int mGreenSize; - protected int mBlueSize; - protected int mAlphaSize; - protected int mDepthSize; - protected int mStencilSize; - private int[] mValue = new int[1]; - } - - glcamera mglcamera; - public void drawMatToGL(int idx, image_pool pool){ - if(mglcamera != null) - mglcamera.drawMatToGL(idx, pool); - else - Log.e("android-opencv", "null glcamera!!!!"); - } - public void clear(){ - if(mglcamera != null) - mglcamera.clear(); - else - Log.e("android-opencv", "null glcamera!!!!"); - } - - private class Renderer implements GLSurfaceView.Renderer { - - public void onDrawFrame(GL10 gl) { - - mglcamera.step(); - } - - public void onSurfaceChanged(GL10 gl, int width, int height) { - - mglcamera.init(width, height); - } - - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - - } - } - - - @Override - public void onPause() { - mglcamera = null; - // TODO Auto-generated method stub - super.onPause(); - - } - - @Override - public void onResume() { - mglcamera = new glcamera(); - // TODO Auto-generated method stub - super.onResume(); - - } - - public PoolCallback getDrawCallback() { - // TODO Auto-generated method stub - return poolcallback; - } - - -} diff --git a/android/android-opencv/src/com/opencv/utils/BitmapBridge.java b/android/android-opencv/src/com/opencv/utils/BitmapBridge.java deleted file mode 100644 index 573e7ae05c..0000000000 --- a/android/android-opencv/src/com/opencv/utils/BitmapBridge.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.opencv.utils; - -import java.nio.ByteBuffer; - -import com.opencv.jni.Mat; -import com.opencv.jni.Size; -import com.opencv.jni.opencv; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; - -public class BitmapBridge { - static void copyBitmap(Bitmap bmap, Mat mat) throws Exception { - if ((bmap.getConfig() == null) || bmap.getConfig() == Config.ARGB_8888) - throw new Exception("bad config"); - Size sz = new Size(bmap.getWidth(), bmap.getHeight()); - mat.create(sz, opencv.CV_8UC4); - ByteBuffer buffer = ByteBuffer.allocate(4 * bmap.getWidth() - * bmap.getHeight()); - bmap.copyPixelsToBuffer(buffer); - opencv.copyBufferToMat(mat, buffer); - - } - - static Bitmap matToBitmap(Mat mat) { - Bitmap bmap = Bitmap.createBitmap(mat.getCols(), mat.getRows(), - Config.ARGB_8888); - ByteBuffer buffer = ByteBuffer.allocate(4 * bmap.getWidth() - * bmap.getHeight()); - opencv.copyMatToBuffer(buffer, mat); - bmap.copyPixelsFromBuffer(buffer); - return bmap; - } -} diff --git a/android/android.toolchain.cmake b/android/android.toolchain.cmake index fab1c7f324..640f469cec 100644 --- a/android/android.toolchain.cmake +++ b/android/android.toolchain.cmake @@ -1,5 +1,5 @@ # ---------------------------------------------------------------------------- -# Android CMake toolchain file, for use with the ndk r5 +# Android CMake toolchain file, for use with the ndk r5,r6 # See home page: http://code.google.com/p/android-cmake/ # # Usage Linux: @@ -16,13 +16,13 @@ # You need native port of make to build your project. # For example this one: http://gnuwin32.sourceforge.net/packages/make.htm # -# $ SET ANDROID_NDK=C:\\android-ndk-r5c +# $ SET ANDROID_NDK=C:\\android-ndk-r6 # $ cmake.exe -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=\android.toolchain.cmake -DCMAKE_MAKE_PROGRAM=C:\\make.exe .. # $ C:\\make.exe # # # Toolchain options (can be set as cmake parameters: -D=): -# ANDROID_NDK=/opt/android-ndk-r5c - path to NDK root. +# ANDROID_NDK=/opt/android-ndk-r6 - path to NDK root. # Can be set as environment variable. # # ANDROID_NDK_TOOLCHAIN_ROOT=/opt/android-toolchain - path to standalone toolchain. @@ -38,8 +38,6 @@ # # NO_UNDEFINED=true - set true to show all undefined symbols will as linker errors even if they are not used. # -# NO_SWIG=false - set true to disable SWIG package -# # # Toolcahin will search for NDK/toolchain in following order: # ANDROID_NDK - cmake parameter @@ -94,6 +92,13 @@ # [~] default NDK path is updated for version r5c # [+] variable CMAKE_SYSTEM_PROCESSOR is set based on ARM_TARGET # [~] toolchain install directory is added to linker paths +# [-] removed SWIG-related stuff from toolchain +# [+] added macro find_host_package, find_host_program to search packages/programs on host system +# [~] fixed path to STL library +# - modified July 2011 Andrey Kamaev andrey.kamaev@itseez.com +# [~] fixed options caching +# [~] search for all supported NDK versions +# [~] allowed spaces in NDK path # ---------------------------------------------------------------------------- # this one is important @@ -101,7 +106,8 @@ set( CMAKE_SYSTEM_NAME Linux ) #this one not so much set( CMAKE_SYSTEM_VERSION 1 ) -set( ANDROID_NDK_DEFAULT_SEARCH_PATH /opt/android-ndk-r5c ) +set( ANDROID_NDK_DEFAULT_SEARCH_PATH /opt/android-ndk ) +set( ANDROID_NDK_SUPPORTED_VERSIONS -r6 -r5c -r5b -r5 "") set( ANDROID_NDK_TOOLCHAIN_DEFAULT_SEARCH_PATH /opt/android-toolchain ) set( TOOL_OS_SUFFIX "" ) @@ -124,21 +130,28 @@ macro( __TOOLCHAIN_DETECT_API_LEVEL _path ) set( ANDROID_API_LEVEL ${ANDROID_LEVEL_FOUND} CACHE STRING "android API level" FORCE ) endmacro() -#set path for android NDK -- look if( NOT DEFINED ANDROID_NDK ) set( ANDROID_NDK $ENV{ANDROID_NDK} ) endif() -if( NOT EXISTS ${ANDROID_NDK} ) - if( EXISTS ${ANDROID_NDK_DEFAULT_SEARCH_PATH} ) - set ( ANDROID_NDK ${ANDROID_NDK_DEFAULT_SEARCH_PATH} ) - message( STATUS "Using default path for android NDK ${ANDROID_NDK}" ) - message( STATUS "If you prefer to use a different location, please define the environment variable: ANDROID_NDK" ) - endif() +if( NOT DEFINED ANDROID_NDK_TOOLCHAIN_ROOT ) + set( ANDROID_NDK_TOOLCHAIN_ROOT $ENV{ANDROID_NDK_TOOLCHAIN_ROOT} ) endif() -if( EXISTS ${ANDROID_NDK} ) - set( ANDROID_NDK ${ANDROID_NDK} CACHE PATH "root of the android ndk" FORCE ) +#set path for android NDK -- look +if( NOT EXISTS "${ANDROID_NDK}" AND NOT DEFINED ANDROID_NDK_TOOLCHAIN_ROOT ) + foreach(ndk_version ${ANDROID_NDK_SUPPORTED_VERSIONS}) + if( EXISTS ${ANDROID_NDK_DEFAULT_SEARCH_PATH}${ndk_version} ) + set ( ANDROID_NDK ${ANDROID_NDK_DEFAULT_SEARCH_PATH}${ndk_version} ) + message( STATUS "Using default path for android NDK ${ANDROID_NDK}" ) + message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_NDK" ) + break() + endif() + endforeach() +endif() + +if( EXISTS "${ANDROID_NDK}" ) + set( ANDROID_NDK "${ANDROID_NDK}" CACHE PATH "root of the android ndk" FORCE ) if( APPLE ) set( NDKSYSTEM "darwin-x86" ) @@ -162,7 +175,7 @@ if( EXISTS ${ANDROID_NDK} ) if( NOT ANDROID_API_LEVEL GREATER 2 ) set( ANDROID_API_LEVEL 8) message( STATUS "Using default android API level android-${ANDROID_API_LEVEL}" ) - message( STATUS "If you prefer to use a different API level, please define the environment variable: ANDROID_API_LEVEL" ) + message( STATUS " If you prefer to use a different API level, please define the variable: ANDROID_API_LEVEL" ) endif() set( ANDROID_NDK_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/${NDKSYSTEM}" ) @@ -174,20 +187,16 @@ if( EXISTS ${ANDROID_NDK} ) set( BUILD_WITH_ANDROID_NDK True ) else() #try to find toolchain - if( NOT DEFINED ANDROID_NDK_TOOLCHAIN_ROOT ) - set( ANDROID_NDK_TOOLCHAIN_ROOT $ENV{ANDROID_NDK_TOOLCHAIN_ROOT} ) - endif() - - if( NOT EXISTS ${ANDROID_NDK_TOOLCHAIN_ROOT} ) - set( ANDROID_NDK_TOOLCHAIN_ROOT ${ANDROID_NDK_TOOLCHAIN_DEFAULT_SEARCH_PATH} ) + if( NOT EXISTS "${ANDROID_NDK_TOOLCHAIN_ROOT}" ) + set( ANDROID_NDK_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAIN_DEFAULT_SEARCH_PATH}" ) message( STATUS "Using default path for toolchain ${ANDROID_NDK_TOOLCHAIN_ROOT}" ) - message( STATUS "If you prefer to use a different location, please define the environment variable: ANDROID_NDK_TOOLCHAIN_ROOT" ) + message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_NDK_TOOLCHAIN_ROOT" ) endif() - set( ANDROID_NDK_TOOLCHAIN_ROOT ${ANDROID_NDK_TOOLCHAIN_ROOT} CACHE PATH "root of the Android NDK standalone toolchain" FORCE ) + set( ANDROID_NDK_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAIN_ROOT}" CACHE PATH "root of the Android NDK standalone toolchain" FORCE ) set( ANDROID_NDK_SYSROOT "${ANDROID_NDK_TOOLCHAIN_ROOT}/sysroot" ) - if( NOT EXISTS ${ANDROID_NDK_TOOLCHAIN_ROOT} ) + if( NOT EXISTS "${ANDROID_NDK_TOOLCHAIN_ROOT}" ) message( FATAL_ERROR "neither ${ANDROID_NDK} nor ${ANDROID_NDK_TOOLCHAIN_ROOT} does not exist! You should either set an environment variable: export ANDROID_NDK=~/my-android-ndk @@ -205,26 +214,28 @@ else() endif() # specify the cross compiler -set( CMAKE_C_COMPILER ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-gcc${TOOL_OS_SUFFIX} CACHE PATH "gcc" FORCE ) -set( CMAKE_CXX_COMPILER ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-g++${TOOL_OS_SUFFIX} CACHE PATH "g++" FORCE ) +set( CMAKE_C_COMPILER "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-gcc${TOOL_OS_SUFFIX}" CACHE PATH "gcc" FORCE ) +set( CMAKE_CXX_COMPILER "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-g++${TOOL_OS_SUFFIX}" CACHE PATH "g++" FORCE ) #there may be a way to make cmake deduce these TODO deduce the rest of the tools -set( CMAKE_AR ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ar${TOOL_OS_SUFFIX} CACHE PATH "archive" FORCE ) -set( CMAKE_LINKER ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ld${TOOL_OS_SUFFIX} CACHE PATH "linker" FORCE ) -set( CMAKE_NM ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-nm${TOOL_OS_SUFFIX} CACHE PATH "nm" FORCE ) -set( CMAKE_OBJCOPY ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-objcopy${TOOL_OS_SUFFIX} CACHE PATH "objcopy" FORCE ) -set( CMAKE_OBJDUMP ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-objdump${TOOL_OS_SUFFIX} CACHE PATH "objdump" FORCE ) -set( CMAKE_STRIP ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-strip${TOOL_OS_SUFFIX} CACHE PATH "strip" FORCE ) -set( CMAKE_RANLIB ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ranlib${TOOL_OS_SUFFIX} CACHE PATH "ranlib" FORCE ) +set( CMAKE_AR "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" FORCE ) +set( CMAKE_LINKER "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" FORCE ) +set( CMAKE_NM "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" FORCE ) +set( CMAKE_OBJCOPY "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" FORCE ) +set( CMAKE_OBJDUMP "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" FORCE ) +set( CMAKE_STRIP "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" FORCE ) +set( CMAKE_RANLIB "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" FORCE ) #setup build targets, mutually exclusive set( PossibleArmTargets "armeabi;armeabi-v7a;armeabi-v7a with NEON;armeabi-v7a with VFPV3" ) -set( ARM_TARGET "armeabi-v7a" CACHE STRING "the arm target for android, recommend armeabi-v7a for floating point support and NEON." ) -set_property( CACHE ARM_TARGET PROPERTY STRINGS ${PossibleArmTargets} ) - #compatibility junk for previous version of toolchain if( DEFINED ARM_TARGETS AND NOT DEFINED ARM_TARGET ) - SET( ARM_TARGET "${ARM_TARGETS}" ) + set( ARM_TARGET "${ARM_TARGETS}" ) endif() +IF( NOT ARM_TARGET) + set( ARM_TARGET armeabi-v7a ) +ENDIF() +set( ARM_TARGET "${ARM_TARGET}" CACHE INTERNAL "the arm target for android, recommend armeabi-v7a for floating point support and NEON." ) +set_property( CACHE ARM_TARGET PROPERTY STRINGS ${PossibleArmTargets} ) #set these flags for client use if( ARM_TARGET STREQUAL "armeabi" ) @@ -253,36 +264,42 @@ set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library o SET( DO_NOT_CHANGE_OUTPUT_PATHS_ON_FIRST_PASS OFF CACHE BOOL "") if( DO_NOT_CHANGE_OUTPUT_PATHS_ON_FIRST_PASS ) - #some cmake standard modules work incorrectly if output paths are changed - if( EXISTS ${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt ) - # these paths are required for jni part of Android projects - # but they may conflict with traditional unix makefile's folder structure - set( LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ARMEABI_NDK_NAME} CACHE PATH "path for android libs" FORCE ) - set( EXECUTABLE_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ARMEABI_NDK_NAME} CACHE PATH "Output directory for applications" FORCE) + if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) + set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ARMEABI_NDK_NAME}" CACHE PATH "Output directory for applications") + else() + set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications") endif() - set( CMAKE_INSTALL_PREFIX ${ANDROID_NDK_TOOLCHAIN_ROOT}/user/${ARMEABI_NDK_NAME} CACHE STRING "path for installing" FORCE ) + set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ARMEABI_NDK_NAME}" CACHE PATH "path for android libs") + set( CMAKE_INSTALL_PREFIX "${ANDROID_NDK_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) endif() SET( DO_NOT_CHANGE_OUTPUT_PATHS_ON_FIRST_PASS ON CACHE INTERNAL "" FORCE) # where is the target environment -set( CMAKE_FIND_ROOT_PATH ${ANDROID_NDK_TOOLCHAIN_ROOT}/bin ${ANDROID_NDK_TOOLCHAIN_ROOT}/arm-linux-androideabi ${ANDROID_NDK_SYSROOT} ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_PREFIX}/share ) +set( CMAKE_FIND_ROOT_PATH "${ANDROID_NDK_TOOLCHAIN_ROOT}/bin" "${ANDROID_NDK_TOOLCHAIN_ROOT}/arm-linux-androideabi" "${ANDROID_NDK_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) if( BUILD_WITH_ANDROID_NDK ) set( STL_PATH "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) set( STL_LIBRARIES_PATH "${STL_PATH}/libs/${ARMEABI_NDK_NAME}" ) - include_directories( ${STL_PATH}/include ${STL_LIBRARIES_PATH}/include ) + include_directories(SYSTEM "${STL_PATH}/include" "${STL_LIBRARIES_PATH}/include" ) +# if ( NOT ARMEABI AND NOT FORCE_ARM ) +# set( STL_LIBRARIES_PATH "${ANDROID_NDK_TOOLCHAIN_ROOT}/arm-linux-androideabi/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) +# endif() endif() if( BUILD_WITH_ANDROID_NDK_TOOLCHAIN ) - set( STL_LIBRARIES_PATH "${CMAKE_INSTALL_PREFIX}/lib" ) + set( STL_LIBRARIES_PATH "${ANDROID_NDK_TOOLCHAIN_ROOT}/arm-linux-androideabi/lib" ) + if( NOT ARMEABI ) + set( STL_LIBRARIES_PATH "${STL_LIBRARIES_PATH}/${CMAKE_SYSTEM_PROCESSOR}" ) + endif() + if( NOT FORCE_ARM ) + set( STL_LIBRARIES_PATH "${STL_LIBRARIES_PATH}/thumb" ) + endif() #for some reason this is needed? TODO figure out why... - include_directories( ${ANDROID_NDK_TOOLCHAIN_ROOT}/arm-linux-androideabi/include/c++/4.4.3/arm-linux-androideabi ) + include_directories(SYSTEM "${ANDROID_NDK_TOOLCHAIN_ROOT}/arm-linux-androideabi/include/c++/4.4.3/arm-linux-androideabi" ) endif() -# allow programs like swig to be found -- but can be deceiving for -# system tool dependencies. -set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) # only search for libraries and includes in the ndk toolchain +set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) @@ -301,8 +318,14 @@ else() endif() if( BUILD_WITH_ANDROID_NDK ) - set( CMAKE_CXX_FLAGS "--sysroot=${ANDROID_NDK_SYSROOT} ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "--sysroot=${ANDROID_NDK_SYSROOT} ${CMAKE_C_FLAGS}" ) + set( CMAKE_CXX_FLAGS "--sysroot=\"${ANDROID_NDK_SYSROOT}\" ${CMAKE_CXX_FLAGS}" ) + set( CMAKE_C_FLAGS "--sysroot=\"${ANDROID_NDK_SYSROOT}\" ${CMAKE_C_FLAGS}" ) + + # workaround for ugly cmake bug - compiler identification replaces all spaces (and somethimes " !!!) in compiler flags with ; symbol + # as result identification fails if ANDROID_NDK_SYSROOT contain spaces + include(CMakeForceCompiler) + CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" GNU) + CMAKE_FORCE_CXX_COMPILER("${CMAKE_CXX_COMPILER}" GNU) endif() if( ARMEABI_V7A ) @@ -325,7 +348,7 @@ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags" ) #-L${LIBCPP_LINK_DIR} -lstdc++ -lsupc++ #Also, this is *required* to use the following linker flags that routes around #a CPU bug in some Cortex-A8 implementations: -set( LINKER_FLAGS "-Wl,--fix-cortex-a8 -L${STL_LIBRARIES_PATH} -L${CMAKE_INSTALL_PREFIX}/lib -lstdc++ -lsupc++ " ) +set( LINKER_FLAGS "-Wl,--fix-cortex-a8 -L\"${STL_LIBRARIES_PATH}\" -L\"${CMAKE_INSTALL_PREFIX}/libs/${ARMEABI_NDK_NAME}\" -lstdc++ -lsupc++ " ) set( NO_UNDEFINED ON CACHE BOOL "Don't all undefined symbols" ) if( NO_UNDEFINED ) @@ -340,28 +363,45 @@ set( CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}" CACHE STRING "linker flags" FORCE set( ANDROID True ) set( BUILD_ANDROID True ) -#SWIG junk... -set( NO_SWIG OFF CACHE BOOL "Don't search for SWIG" ) -if( NOT NO_SWIG ) - #need to search in the host for swig to be found - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH ) - find_package( SWIG QUIET ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) - - if( SWIG_FOUND ) - set( SWIG_USE_FILE ${CMAKE_ROOT}/Modules/UseSWIG.cmake CACHE PATH "Use Swig cmake module" ) - set( SWIG_OUTPUT_ROOT ${LIBRARY_OUTPUT_PATH_ROOT}/src CACHE PATH "Where swig generated files will be placed relative to, /com/mylib/foo/jni ..." FORCE ) - - #convenience macro for swig java packages - macro( SET_SWIG_JAVA_PACKAGE package_name ) - string( REGEX REPLACE "[.]" "/" package_name_output ${package_name} ) - set( CMAKE_SWIG_OUTDIR ${SWIG_OUTPUT_ROOT}/${package_name_output} ) - set( CMAKE_SWIG_FLAGS "-package" "\"${package_name}\"" ) - endmacro() - else() - message( STATUS "SWIG is not found" ) - set( NO_SWIG ON CACHE BOOL "Don't search for SWIG" FORCE ) +#macro to find packages on the host OS +macro(find_host_package) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) + if( CMAKE_HOST_WIN32 ) + SET( WIN32 1 ) + SET( UNIX ) + elseif( CMAKE_HOST_APPLE ) + SET( APPLE 1 ) + SET( UNIX ) endif() -endif() + find_package( ${ARGN} ) + SET( WIN32 ) + SET( APPLE ) + SET( UNIX 1) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) +endmacro() +#macro to find programs on the host OS +macro(find_host_program) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) + if( CMAKE_HOST_WIN32 ) + SET( WIN32 1 ) + SET( UNIX ) + elseif( CMAKE_HOST_APPLE ) + SET( APPLE 1 ) + SET( UNIX ) + endif() + find_program( ${ARGN} ) + SET( WIN32 ) + SET( APPLE ) + SET( UNIX 1) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) +endmacro() + +MARK_AS_ADVANCED(FORCE_ARM NO_UNDEFINED) diff --git a/android/apps/CVCamera/AndroidManifest.xml b/android/apps/CVCamera/AndroidManifest.xml deleted file mode 100644 index 227f23ac36..0000000000 --- a/android/apps/CVCamera/AndroidManifest.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/apps/CVCamera/CMakeLists.txt b/android/apps/CVCamera/CMakeLists.txt deleted file mode 100644 index e82fbdf4c3..0000000000 --- a/android/apps/CVCamera/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(CVCamera) - -add_subdirectory(jni) diff --git a/android/apps/CVCamera/README.txt b/android/apps/CVCamera/README.txt deleted file mode 100644 index 8bc5b3a90e..0000000000 --- a/android/apps/CVCamera/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -see http://code.google.com/p/android-opencv/wiki/CVCamera - diff --git a/android/apps/CVCamera/default.properties b/android/apps/CVCamera/default.properties deleted file mode 100644 index 248b9a0428..0000000000 --- a/android/apps/CVCamera/default.properties +++ /dev/null @@ -1,12 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -android.library.reference.1=../../android-opencv -# Project target. -target=android-7 diff --git a/android/apps/CVCamera/jni/CMakeLists.txt b/android/apps/CVCamera/jni/CMakeLists.txt deleted file mode 100644 index 3ea00cb19b..0000000000 --- a/android/apps/CVCamera/jni/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -######################################################### -# Find opencv and android-opencv -######################################################### - -set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../../build - CACHE PATH "The path where you built opencv for android") -set(AndroidOpenCV_DIR ${CMAKE_SOURCE_DIR}/../../android-opencv/build - CACHE PATH "The path where you built android-opencv") - -find_package(OpenCV REQUIRED) -FIND_PACKAGE(AndroidOpenCV REQUIRED ) - -######################################################### -#c flags, included, and lib dependencies -######################################################### - -#notice the "recycling" of CMAKE_C_FLAGS -#this is necessary to pick up android flags -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" ) - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -set( LIBRARY_DEPS ${AndroidOpenCV_LIBS} ${OpenCV_LIBS} ) -if(ANDROID) - set( LIBRARY_DEPS ${LIBRARY_DEPS} log dl) -endif(ANDROID) - -######################################################### -#SWIG STUFF -######################################################### -#the java package to place swig generated java files in -set(MY_PACKAGE com.theveganrobot.cvcamera.jni) - -if(NOT ANDROID) - #non android swig and jni - #jni is available by default on android - find_package(JNI REQUIRED) - include_directories(${JNI_INCLUDE_DIRS}) - FIND_PACKAGE(SWIG) -endif() - -INCLUDE(${SWIG_USE_FILE}) #on android this is found by the cmake toolchain - -if(ANDROID) - #this will set the output path for the java package - #and properly create the package declarations in generated java sources - SET_SWIG_JAVA_PACKAGE( ${MY_PACKAGE} ) #defined in the android toolchain -endif(ANDROID) - -#this add's the swig path for the opencv wrappers -SET(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} "-I${AndroidOpenCV_SWIG_DIR}" ) - -SET_SOURCE_FILES_PROPERTIES(cvcamera.i PROPERTIES CPLUSPLUS ON) - -#add the swig module, giving it the name, java, and then all of the source files -SWIG_ADD_MODULE(cvcamera java - cvcamera.i #swig file - Processor.cpp #cpp files can be compiled to - ) - -#link the module like any other -target_link_libraries(cvcamera ${LIBRARY_DEPS} ) diff --git a/android/apps/CVCamera/jni/Processor.cpp b/android/apps/CVCamera/jni/Processor.cpp deleted file mode 100644 index eaf0e5b747..0000000000 --- a/android/apps/CVCamera/jni/Processor.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Processor.cpp - * - * Created on: Jun 13, 2010 - * Author: ethan - */ - -#include "Processor.h" - -#include - -using namespace cv; - -Processor::Processor() : - stard(20/*max_size*/, 8/*response_threshold*/, 15/*line_threshold_projected*/, 8/*line_threshold_binarized*/, 5/*suppress_nonmax_size*/), - fastd(20/*threshold*/, true/*nonmax_suppression*/), - surfd(100./*hessian_threshold*/, 1/*octaves*/, 2/*octave_layers*/) - -{ - -} - -Processor::~Processor() -{ - // TODO Auto-generated destructor stub -} - -void Processor::detectAndDrawFeatures(int input_idx, image_pool* pool, int feature_type) -{ - FeatureDetector* fd = 0; - - switch (feature_type) - { - case DETECT_SURF: - fd = &surfd; - break; - case DETECT_FAST: - fd = &fastd; - break; - case DETECT_STAR: - fd = &stard; - break; - } - - Mat greyimage = pool->getGrey(input_idx); - - Mat img = pool->getImage(input_idx); - - if (img.empty() || greyimage.empty() || fd == 0) - return; //no image at input_idx! - - - keypoints.clear(); - - //if(grayimage->step1() > sizeof(uchar)) return; - //cvtColor(*img,*grayimage,CV_RGB2GRAY); - - - fd->detect(greyimage, keypoints); - - for (vector::const_iterator it = keypoints.begin(); it != keypoints.end(); ++it) - { - circle(img, it->pt, 3, cvScalar(255, 0, 255, 0)); - } - - //pool->addImage(output_idx,outimage); - -} -static double computeReprojectionErrors(const vector >& objectPoints, - const vector >& imagePoints, const vector& rvecs, - const vector& tvecs, const Mat& cameraMatrix, const Mat& distCoeffs, - vector& perViewErrors) -{ - vector imagePoints2; - int i, totalPoints = 0; - double totalErr = 0, err; - perViewErrors.resize(objectPoints.size()); - - for (i = 0; i < (int)objectPoints.size(); i++) - { - projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, distCoeffs, imagePoints2); - err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L1); - int n = (int)objectPoints[i].size(); - perViewErrors[i] = err / n; - totalErr += err; - totalPoints += n; - } - - return totalErr / totalPoints; -} - -static void calcChessboardCorners(Size boardSize, float squareSize, vector& corners) -{ - corners.resize(0); - - for (int i = 0; i < boardSize.height; i++) - for (int j = 0; j < boardSize.width; j++) - corners.push_back(Point3f(float(j * squareSize), float(i * squareSize), 0)); -} - -/**from opencv/samples/cpp/calibration.cpp - * - */ -static bool runCalibration(vector > imagePoints, Size imageSize, Size boardSize, float squareSize, - float aspectRatio, int flags, Mat& cameraMatrix, Mat& distCoeffs, vector& rvecs, - vector& tvecs, vector& reprojErrs, double& totalAvgErr) -{ - cameraMatrix = Mat::eye(3, 3, CV_64F); - if (flags & CV_CALIB_FIX_ASPECT_RATIO) - cameraMatrix.at (0, 0) = aspectRatio; - - distCoeffs = Mat::zeros(5, 1, CV_64F); - - vector > objectPoints(1); - calcChessboardCorners(boardSize, squareSize, objectPoints[0]); - for (size_t i = 1; i < imagePoints.size(); i++) - objectPoints.push_back(objectPoints[0]); - - calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags); - - bool ok = checkRange(cameraMatrix, CV_CHECK_QUIET) && checkRange(distCoeffs, CV_CHECK_QUIET); - - totalAvgErr - = computeReprojectionErrors(objectPoints, imagePoints, rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs); - - return ok; -} - -bool Processor::detectAndDrawChessboard(int idx, image_pool* pool) -{ - - Mat grey = pool->getGrey(idx); - if (grey.empty()) - return false; - vector corners; - - IplImage iplgrey = grey; - if (!cvCheckChessboard(&iplgrey, Size(6, 8))) - return false; - bool patternfound = findChessboardCorners(grey, Size(6, 8), corners); - - Mat img = pool->getImage(idx); - - if (corners.size() < 1) - return false; - - cornerSubPix(grey, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); - - if (patternfound) - imagepoints.push_back(corners); - - drawChessboardCorners(img, Size(6, 8), Mat(corners), patternfound); - - imgsize = grey.size(); - - return patternfound; - -} - -void Processor::drawText(int i, image_pool* pool, const char* ctext) -{ - // Use "y" to show that the baseLine is about - string text = ctext; - int fontFace = FONT_HERSHEY_COMPLEX_SMALL; - double fontScale = .8; - int thickness = .5; - - Mat img = pool->getImage(i); - - int baseline = 0; - Size textSize = getTextSize(text, fontFace, fontScale, thickness, &baseline); - baseline += thickness; - - // center the text - Point textOrg((img.cols - textSize.width) / 2, (img.rows - textSize.height * 2)); - - // draw the box - rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0, 0, 255), - CV_FILLED); - // ... and the baseline first - line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255)); - - // then put the text itself - putText(img, text, textOrg, fontFace, fontScale, Scalar::all(255), thickness, 8); -} -void saveCameraParams(const string& filename, Size imageSize, Size boardSize, float squareSize, float aspectRatio, - int flags, const Mat& cameraMatrix, const Mat& distCoeffs, const vector& rvecs, - const vector& tvecs, const vector& reprojErrs, - const vector >& imagePoints, double totalAvgErr) -{ - FileStorage fs(filename, FileStorage::WRITE); - - time_t t; - time(&t); - struct tm *t2 = localtime(&t); - char buf[1024]; - strftime(buf, sizeof(buf) - 1, "%c", t2); - - fs << "calibration_time" << buf; - - if (!rvecs.empty() || !reprojErrs.empty()) - fs << "nframes" << (int)std::max(rvecs.size(), reprojErrs.size()); - fs << "image_width" << imageSize.width; - fs << "image_height" << imageSize.height; - fs << "board_width" << boardSize.width; - fs << "board_height" << boardSize.height; - fs << "squareSize" << squareSize; - - if (flags & CV_CALIB_FIX_ASPECT_RATIO) - fs << "aspectRatio" << aspectRatio; - - if (flags != 0) - { - sprintf(buf, "flags: %s%s%s%s", flags & CV_CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "", flags - & CV_CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "", flags & CV_CALIB_FIX_PRINCIPAL_POINT - ? "+fix_principal_point" : "", flags & CV_CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : ""); - cvWriteComment(*fs, buf, 0); - } - - fs << "flags" << flags; - - fs << "camera_matrix" << cameraMatrix; - fs << "distortion_coefficients" << distCoeffs; - - fs << "avg_reprojection_error" << totalAvgErr; - if (!reprojErrs.empty()) - fs << "per_view_reprojection_errors" << Mat(reprojErrs); - - if (!rvecs.empty() && !tvecs.empty()) - { - Mat bigmat(rvecs.size(), 6, CV_32F); - for (size_t i = 0; i < rvecs.size(); i++) - { - Mat r = bigmat(Range(i, i + 1), Range(0, 3)); - Mat t = bigmat(Range(i, i + 1), Range(3, 6)); - rvecs[i].copyTo(r); - tvecs[i].copyTo(t); - } - cvWriteComment(*fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0); - fs << "extrinsic_parameters" << bigmat; - } - - if (!imagePoints.empty()) - { - Mat imagePtMat(imagePoints.size(), imagePoints[0].size(), CV_32FC2); - for (size_t i = 0; i < imagePoints.size(); i++) - { - Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols); - Mat(imagePoints[i]).copyTo(r); - } - fs << "image_points" << imagePtMat; - } -} -void Processor::resetChess() -{ - - imagepoints.clear(); -} - -void Processor::calibrate(const char* filename) -{ - - vector rvecs, tvecs; - vector reprojErrs; - double totalAvgErr = 0; - int flags = 0; - bool writeExtrinsics = true; - bool writePoints = true; - - bool ok = runCalibration(imagepoints, imgsize, Size(6, 8), 1.f, 1.f, flags, K, distortion, rvecs, tvecs, reprojErrs, - totalAvgErr); - - if (ok) - { - - saveCameraParams(filename, imgsize, Size(6, 8), 1.f, 1.f, flags, K, distortion, writeExtrinsics ? rvecs : vector< - Mat> (), writeExtrinsics ? tvecs : vector (), writeExtrinsics ? reprojErrs : vector (), writePoints - ? imagepoints : vector > (), totalAvgErr); - } - -} - -int Processor::getNumberDetectedChessboards() -{ - return imagepoints.size(); -} diff --git a/android/apps/CVCamera/jni/Processor.h b/android/apps/CVCamera/jni/Processor.h deleted file mode 100644 index cf61571ab5..0000000000 --- a/android/apps/CVCamera/jni/Processor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Processor.h - * - * Created on: Jun 13, 2010 - * Author: ethan - */ - -#ifndef PROCESSOR_H_ -#define PROCESSOR_H_ - -#include -#include -#include -#include -#include - -#include - -#include "image_pool.h" - -#define DETECT_FAST 0 -#define DETECT_STAR 1 -#define DETECT_SURF 2 - -class Processor -{ -public: - - Processor(); - virtual ~Processor(); - - void detectAndDrawFeatures(int idx, image_pool* pool, int feature_type); - - bool detectAndDrawChessboard(int idx, image_pool* pool); - - void resetChess(); - - int getNumberDetectedChessboards(); - - void calibrate(const char* filename); - - void drawText(int idx, image_pool* pool, const char* text); -private: - cv::StarFeatureDetector stard; - cv::FastFeatureDetector fastd; - cv::SurfFeatureDetector surfd; - std::vector keypoints; - std::vector > imagepoints; - - cv::Mat K; - cv::Mat distortion; - cv::Size imgsize; - -}; - -#endif /* PROCESSOR_H_ */ diff --git a/android/apps/CVCamera/jni/Processor.i b/android/apps/CVCamera/jni/Processor.i deleted file mode 100644 index ff66d53070..0000000000 --- a/android/apps/CVCamera/jni/Processor.i +++ /dev/null @@ -1,51 +0,0 @@ -/* - * include the headers required by the generated cpp code - */ -%{ -#include "Processor.h" -#include "image_pool.h" -using namespace cv; -%} - - -/** - * some constants, see Processor.h - */ -#define DETECT_FAST 0 -#define DETECT_STAR 1 -#define DETECT_SURF 2 - -//import the android-cv.i file so that swig is aware of all that has been previous defined -//notice that it is not an include.... -%import "android-cv.i" - -//make sure to import the image_pool as it is -//referenced by the Processor java generated -//class -%typemap(javaimports) Processor " -import com.opencv.jni.image_pool;// import the image_pool interface for playing nice with - // android-opencv - -/** Processor - for processing images that are stored in an image pool -*/" - -class Processor { -public: - Processor(); - virtual ~Processor(); - - - - void detectAndDrawFeatures(int idx, image_pool* pool, int feature_type); - - bool detectAndDrawChessboard(int idx,image_pool* pool); - - void resetChess(); - - int getNumberDetectedChessboards(); - - void calibrate(const char* filename); - - void drawText(int idx, image_pool* pool, const char* text); - -}; diff --git a/android/apps/CVCamera/jni/cvcamera.i b/android/apps/CVCamera/jni/cvcamera.i deleted file mode 100644 index ccca8d91a0..0000000000 --- a/android/apps/CVCamera/jni/cvcamera.i +++ /dev/null @@ -1,36 +0,0 @@ -/* File : android-cv.i */ - -%module cvcamera - - -/* - * the java import code muse be included for the opencv jni wrappers - * this means that the android project must reference opencv/android as a project - * see the default.properties for how this is done - */ -%pragma(java) jniclassimports=%{ -import com.opencv.jni.*; //import the android-opencv jni wrappers -%} - -%pragma(java) jniclasscode=%{ - static { - try { - //load the cvcamera library, make sure that libcvcamera.so is in your /libs/armeabi directory - //so that android sdk automatically installs it along with the app. - - //the android-opencv lib must be loaded first inorder for the cvcamera - //lib to be found - //check the apk generated, by opening it in an archive manager, to verify that - //both these libraries are present - System.loadLibrary("android-opencv"); - System.loadLibrary("cvcamera"); - } catch (UnsatisfiedLinkError e) { - //badness - throw e; - } - } - -%} - -//include the Processor class swig interface file -%include "Processor.i" \ No newline at end of file diff --git a/android/apps/CVCamera/project_create.sh b/android/apps/CVCamera/project_create.sh deleted file mode 100755 index ec7672872e..0000000000 --- a/android/apps/CVCamera/project_create.sh +++ /dev/null @@ -1,2 +0,0 @@ -android update project --name CVCamera \ ---path . diff --git a/android/apps/CVCamera/res/drawable-ldpi/icon.png b/android/apps/CVCamera/res/drawable-ldpi/icon.png deleted file mode 100644 index 5e11406cb2..0000000000 Binary files a/android/apps/CVCamera/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/android/apps/CVCamera/res/drawable-mdpi/icon.png b/android/apps/CVCamera/res/drawable-mdpi/icon.png deleted file mode 100644 index a591eb892d..0000000000 Binary files a/android/apps/CVCamera/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/android/apps/CVCamera/res/layout/main.xml b/android/apps/CVCamera/res/layout/main.xml deleted file mode 100644 index ae6cdd14df..0000000000 --- a/android/apps/CVCamera/res/layout/main.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/android/apps/CVCamera/res/values/strings.xml b/android/apps/CVCamera/res/values/strings.xml deleted file mode 100644 index 5fe379d698..0000000000 --- a/android/apps/CVCamera/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - CVCamera -app to demo using android camera and passing data to opencv layer. -Release 0.0.1 - first demo of using the OpenCV library with camera data - diff --git a/android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java b/android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java deleted file mode 100644 index b1fcbfabc8..0000000000 --- a/android/apps/CVCamera/src/com/theveganrobot/cvcamera/CVCamera.java +++ /dev/null @@ -1,505 +0,0 @@ -package com.theveganrobot.cvcamera; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.LinkedList; -import java.util.Scanner; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.os.Environment; -import android.util.Log; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.Window; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.Toast; - -import com.opencv.camera.CameraConfig; -import com.opencv.camera.NativePreviewer; -import com.opencv.camera.NativeProcessor; -import com.opencv.camera.NativeProcessor.PoolCallback; -import com.opencv.jni.image_pool; -import com.opencv.opengl.GL2CameraViewer; -import com.theveganrobot.cvcamera.jni.Processor; -import com.theveganrobot.cvcamera.jni.cvcamera; - -public class CVCamera extends Activity { - - static final int DIALOG_CALIBRATING = 0; - static final int DIALOG_CALIBRATION_FILE = 1; - private static final int DIALOG_OPENING_TUTORIAL = 2; - private static final int DIALOG_TUTORIAL_FAST = 3; - private static final int DIALOG_TUTORIAL_SURF = 4; - private static final int DIALOG_TUTORIAL_STAR = 5; - private static final int DIALOG_TUTORIAL_CHESS = 6; - private boolean captureChess; - - ProgressDialog makeCalibDialog() { - ProgressDialog progressDialog; - progressDialog = new ProgressDialog(this); - progressDialog.setMessage("Callibrating. Please wait..."); - progressDialog.setCancelable(false); - - return progressDialog; - } - - void toasts(int id) { - switch (id) { - case DIALOG_OPENING_TUTORIAL: - Toast.makeText(this, "Try clicking the menu for CV options.", - Toast.LENGTH_LONG).show(); - break; - case DIALOG_TUTORIAL_FAST: - Toast.makeText(this, "Detecting and Displaying FAST features", - Toast.LENGTH_LONG).show(); - break; - case DIALOG_TUTORIAL_SURF: - Toast.makeText(this, "Detecting and Displaying SURF features", - Toast.LENGTH_LONG).show(); - break; - case DIALOG_TUTORIAL_STAR: - Toast.makeText(this, "Detecting and Displaying STAR features", - Toast.LENGTH_LONG).show(); - break; - case DIALOG_TUTORIAL_CHESS: - Toast.makeText( - this, - "Calibration Mode, Point at a chessboard pattern and press the camera button, space," - + "or the DPAD to capture.", Toast.LENGTH_LONG) - .show(); - break; - - default: - break; - } - - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog; - switch (id) { - case DIALOG_CALIBRATING: - dialog = makeCalibDialog(); - break; - - case DIALOG_CALIBRATION_FILE: - dialog = makeCalibFileAlert(); - break; - default: - dialog = null; - } - return dialog; - } - - private Dialog makeCalibFileAlert() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(calib_text) - .setTitle("camera.yml at " + calib_file_loc) - .setCancelable(false) - .setPositiveButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - - } - }); - AlertDialog alert = builder.create(); - return alert; - } - - /* - * (non-Javadoc) - * - * @see android.app.Activity#onKeyUp(int, android.view.KeyEvent) - */ - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - - switch (keyCode) { - case KeyEvent.KEYCODE_CAMERA: - case KeyEvent.KEYCODE_SPACE: - case KeyEvent.KEYCODE_DPAD_CENTER: - captureChess = true; - return true; - - default: - return super.onKeyUp(keyCode, event); - } - - } - - /* - * (non-Javadoc) - * - * @see android.app.Activity#onKeyLongPress(int, android.view.KeyEvent) - */ - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - - return super.onKeyLongPress(keyCode, event); - } - - /** - * Avoid that the screen get's turned off by the system. - */ - public void disableScreenTurnOff() { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - /** - * Set's the orientation to landscape, as this is needed by AndAR. - */ - public void setOrientation() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - - /** - * Maximize the application. - */ - public void setFullscreen() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - public void setNoTitle() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add("FAST"); - menu.add("STAR"); - menu.add("SURF"); - menu.add("Chess"); - menu.add("Settings"); - return true; - } - - private NativePreviewer mPreview; - private GL2CameraViewer glview; - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - LinkedList defaultcallbackstack = new LinkedList(); - defaultcallbackstack.addFirst(glview.getDrawCallback()); - if (item.getTitle().equals("FAST")) { - - defaultcallbackstack.addFirst(new FastProcessor()); - toasts(DIALOG_TUTORIAL_FAST); - } - - else if (item.getTitle().equals("Chess")) { - - defaultcallbackstack.addFirst(new CalibrationProcessor()); - toasts(DIALOG_TUTORIAL_CHESS); - - } - - else if (item.getTitle().equals("STAR")) { - - defaultcallbackstack.addFirst(new STARProcessor()); - toasts(DIALOG_TUTORIAL_STAR); - - } - - else if (item.getTitle().equals("SURF")) { - - defaultcallbackstack.addFirst(new SURFProcessor()); - toasts(DIALOG_TUTORIAL_SURF); - - } - - else if (item.getTitle().equals("Settings")) { - - Intent intent = new Intent(this,CameraConfig.class); - startActivity(intent); - } - - mPreview.addCallbackStack(defaultcallbackstack); - - return true; - } - - @Override - public void onOptionsMenuClosed(Menu menu) { - // TODO Auto-generated method stub - super.onOptionsMenuClosed(menu); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setFullscreen(); - disableScreenTurnOff(); - - FrameLayout frame = new FrameLayout(this); - - // Create our Preview view and set it as the content of our activity. - mPreview = new NativePreviewer(getApplication(), 640, 480); - - LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - params.height = getWindowManager().getDefaultDisplay().getHeight(); - params.width = (int) (params.height * 4.0 / 2.88); - - LinearLayout vidlay = new LinearLayout(getApplication()); - - vidlay.setGravity(Gravity.CENTER); - vidlay.addView(mPreview, params); - frame.addView(vidlay); - - // make the glview overlay ontop of video preview - mPreview.setZOrderMediaOverlay(false); - - glview = new GL2CameraViewer(getApplication(), false, 0, 0); - glview.setZOrderMediaOverlay(true); - - LinearLayout gllay = new LinearLayout(getApplication()); - - gllay.setGravity(Gravity.CENTER); - gllay.addView(glview, params); - frame.addView(gllay); - - ImageButton capture_button = new ImageButton(getApplicationContext()); - capture_button.setImageDrawable(getResources().getDrawable( - android.R.drawable.ic_menu_camera)); - capture_button.setLayoutParams(new LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - capture_button.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - captureChess = true; - - } - }); - - LinearLayout buttons = new LinearLayout(getApplicationContext()); - buttons.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT)); - - buttons.addView(capture_button); - - Button focus_button = new Button(getApplicationContext()); - focus_button.setLayoutParams(new LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - focus_button.setText("Focus"); - focus_button.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - mPreview.postautofocus(100); - } - }); - buttons.addView(focus_button); - - frame.addView(buttons); - setContentView(frame); - toasts(DIALOG_OPENING_TUTORIAL); - } - - @Override - public boolean onTrackballEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - captureChess = true; - return true; - } - return super.onTrackballEvent(event); - } - - @Override - protected void onPause() { - super.onPause(); - - // clears the callback stack - mPreview.onPause(); - - glview.onPause(); - - } - - @Override - protected void onResume() { - super.onResume(); - glview.onResume(); - mPreview.setParamsFromPrefs(getApplicationContext()); - // add an initiall callback stack to the preview on resume... - // this one will just draw the frames to opengl - LinkedList cbstack = new LinkedList(); - cbstack.add(glview.getDrawCallback()); - mPreview.addCallbackStack(cbstack); - mPreview.onResume(); - - } - - // final processor so taht these processor callbacks can access it - final Processor processor = new Processor(); - - class FastProcessor implements NativeProcessor.PoolCallback { - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - processor.detectAndDrawFeatures(idx, pool, cvcamera.DETECT_FAST); - - } - - } - - class STARProcessor implements NativeProcessor.PoolCallback { - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - processor.detectAndDrawFeatures(idx, pool, cvcamera.DETECT_STAR); - - } - - } - - class SURFProcessor implements NativeProcessor.PoolCallback { - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - processor.detectAndDrawFeatures(idx, pool, cvcamera.DETECT_SURF); - - } - - } - - String calib_text = null; - String calib_file_loc = null; - - class CalibrationProcessor implements NativeProcessor.PoolCallback { - - boolean calibrated = false; - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - - if (calibrated) { - processor.drawText(idx, pool, "Calibrated successfully"); - return; - } - if (processor.getNumberDetectedChessboards() == 10) { - - File opencvdir = new File( - Environment.getExternalStorageDirectory(), "opencv"); - if (!opencvdir.exists()) { - opencvdir.mkdir(); - } - File calibfile = new File(opencvdir, "camera.yml"); - - calib_file_loc = calibfile.getAbsolutePath(); - processor.calibrate(calibfile.getAbsolutePath()); - Log.i("chessboard", "calibrated"); - calibrated = true; - processor.resetChess(); - runOnUiThread(new Runnable() { - - @Override - public void run() { - removeDialog(DIALOG_CALIBRATING); - - } - }); - - try { - - StringBuilder text = new StringBuilder(); - String NL = System.getProperty("line.separator"); - Scanner scanner = new Scanner(calibfile); - - try { - while (scanner.hasNextLine()) { - text.append(scanner.nextLine() + NL); - } - } finally { - scanner.close(); - } - - calib_text = text.toString(); - - runOnUiThread(new Runnable() { - - @Override - public void run() { - showDialog(DIALOG_CALIBRATION_FILE); - - } - }); - - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } else if (captureChess - && processor.detectAndDrawChessboard(idx, pool)) { - - runOnUiThread(new Runnable() { - - String numchess = String.valueOf(processor - .getNumberDetectedChessboards()); - - @Override - public void run() { - Toast.makeText(CVCamera.this, - "Detected " + numchess + " of 10 chessboards", - Toast.LENGTH_SHORT).show(); - - } - }); - Log.i("cvcamera", - "detected a chessboard, n chess boards found: " - + String.valueOf(processor - .getNumberDetectedChessboards())); - - } - - captureChess = false; - - if (processor.getNumberDetectedChessboards() == 10) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - showDialog(DIALOG_CALIBRATING); - - } - }); - - processor.drawText(idx, pool, "Calibrating, please wait."); - } - if (processor.getNumberDetectedChessboards() < 10) { - - processor.drawText(idx, pool, - "found " + processor.getNumberDetectedChessboards() - + "/10 chessboards"); - } - - } - - } - -} diff --git a/android/apps/CVCamera/uninstall.phone.sh b/android/apps/CVCamera/uninstall.phone.sh deleted file mode 100755 index 06b78cabec..0000000000 --- a/android/apps/CVCamera/uninstall.phone.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -echo uninstalling CVCamera from phone -adb uninstall com.theveganrobot.cvcamera diff --git a/android/apps/Calibration/AndroidManifest.xml b/android/apps/Calibration/AndroidManifest.xml deleted file mode 100644 index 295dc9d432..0000000000 --- a/android/apps/Calibration/AndroidManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/apps/Calibration/README.txt b/android/apps/Calibration/README.txt deleted file mode 100644 index 17e3222933..0000000000 --- a/android/apps/Calibration/README.txt +++ /dev/null @@ -1,10 +0,0 @@ -to build completeley from command line: -sh project_create.sh -ant debug -ant install - -That assumes that you have already build the opencv/android/android-jni project - -If you're in eclipse, try to create a new android project from existing sources. -Make sure that you also have the android-jni project open in eclipse is this is the case -or the android library dependency will give you errors. \ No newline at end of file diff --git a/android/apps/Calibration/artwork/icon.xcf b/android/apps/Calibration/artwork/icon.xcf deleted file mode 100644 index aa7bb992b0..0000000000 Binary files a/android/apps/Calibration/artwork/icon.xcf and /dev/null differ diff --git a/android/apps/Calibration/default.properties b/android/apps/Calibration/default.properties deleted file mode 100644 index 7f801f9c35..0000000000 --- a/android/apps/Calibration/default.properties +++ /dev/null @@ -1,12 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -android.library.reference.1=../../android-opencv/ -# Project target. -target=android-7 diff --git a/android/apps/Calibration/project_create.sh b/android/apps/Calibration/project_create.sh deleted file mode 100755 index f8c9c51ff2..0000000000 --- a/android/apps/Calibration/project_create.sh +++ /dev/null @@ -1,2 +0,0 @@ -android update project --name Calibration \ ---path . diff --git a/android/apps/Calibration/res/drawable-hdpi/icon.png b/android/apps/Calibration/res/drawable-hdpi/icon.png deleted file mode 100644 index ab9f932889..0000000000 Binary files a/android/apps/Calibration/res/drawable-hdpi/icon.png and /dev/null differ diff --git a/android/apps/Calibration/res/drawable-ldpi/icon.png b/android/apps/Calibration/res/drawable-ldpi/icon.png deleted file mode 100644 index ab9f932889..0000000000 Binary files a/android/apps/Calibration/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/android/apps/Calibration/res/drawable-mdpi/cameraback.jpg b/android/apps/Calibration/res/drawable-mdpi/cameraback.jpg deleted file mode 100644 index b53ffd4891..0000000000 Binary files a/android/apps/Calibration/res/drawable-mdpi/cameraback.jpg and /dev/null differ diff --git a/android/apps/Calibration/res/drawable-mdpi/icon.png b/android/apps/Calibration/res/drawable-mdpi/icon.png deleted file mode 100644 index ab9f932889..0000000000 Binary files a/android/apps/Calibration/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/android/apps/Calibration/res/drawable-mdpi/patternicon.png b/android/apps/Calibration/res/drawable-mdpi/patternicon.png deleted file mode 100644 index 879044ad09..0000000000 Binary files a/android/apps/Calibration/res/drawable-mdpi/patternicon.png and /dev/null differ diff --git a/android/apps/Calibration/res/layout/calib_camera.xml b/android/apps/Calibration/res/layout/calib_camera.xml deleted file mode 100644 index 35dc96f06c..0000000000 --- a/android/apps/Calibration/res/layout/calib_camera.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/apps/Calibration/res/menu/calibrationmenu.xml b/android/apps/Calibration/res/menu/calibrationmenu.xml deleted file mode 100644 index c157df9223..0000000000 --- a/android/apps/Calibration/res/menu/calibrationmenu.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/android/apps/Calibration/res/values/color.xml b/android/apps/Calibration/res/values/color.xml deleted file mode 100644 index e33983712b..0000000000 --- a/android/apps/Calibration/res/values/color.xml +++ /dev/null @@ -1,5 +0,0 @@ - - -#00ff00 -#FF0000 - diff --git a/android/apps/Calibration/res/values/strings.xml b/android/apps/Calibration/res/values/strings.xml deleted file mode 100644 index 9e57fdef8c..0000000000 --- a/android/apps/Calibration/res/values/strings.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - /opencv/camera.yml - /opencv - - Calibration calculations have started... - Calibration calculations has stopped. - Calibration finished, you camera is calibrated. - Calibration - Please capture atleast 10 images of the pattern! - Please make sure that you\'re sdcard is not mounted to you\'re computer, and that you have an sdcard that is writable on your device. - - diff --git a/android/apps/Calibration/src/com/opencv/calibration/Calibration.java b/android/apps/Calibration/src/com/opencv/calibration/Calibration.java deleted file mode 100644 index 64217fb610..0000000000 --- a/android/apps/Calibration/src/com/opencv/calibration/Calibration.java +++ /dev/null @@ -1,325 +0,0 @@ -package com.opencv.calibration; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedList; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.os.IBinder; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import com.opencv.calibration.Calibrator.CalibrationCallback; -import com.opencv.calibration.services.CalibrationService; -import com.opencv.camera.CameraConfig; -import com.opencv.camera.NativePreviewer; -import com.opencv.camera.NativeProcessor; -import com.opencv.misc.SDCardChecker; -import com.opencv.opengl.GL2CameraViewer; - -public class Calibration extends Activity implements CalibrationCallback { - private NativePreviewer mPreview; - - private GL2CameraViewer glview; - private Calibrator calibrator; - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - - switch (keyCode) { - case KeyEvent.KEYCODE_CAMERA: - case KeyEvent.KEYCODE_SPACE: - case KeyEvent.KEYCODE_DPAD_CENTER: - calibrator.queueChessCapture(); - return true; - default: - return super.onKeyUp(keyCode, event); - } - - } - - @Override - public boolean onTrackballEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - calibrator.queueChessCapture(); - return true; - } - return super.onTrackballEvent(event); - } - - /** - * Avoid that the screen get's turned off by the system. - */ - public void disableScreenTurnOff() { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - /** - * Set's the orientation to landscape, as this is needed by AndAR. - */ - public void setOrientation() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - - /** - * Maximize the application. - */ - public void setFullscreen() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - public void setNoTitle() { - requestWindowFeature(Window.FEATURE_NO_TITLE); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.calibrationmenu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.patternsize: { - Intent sizer = new Intent(getApplicationContext(), - ChessBoardChooser.class); - startActivity(sizer); - } - break; - case R.id.help: - help(); - break; - case R.id.calibrate: - calibrate(); - break; - case R.id.settings: - Intent configurer = new Intent(getApplicationContext(), - CameraConfig.class); - startActivity(configurer); - - } - - return true; - - } - - private void help() { - // TODO Auto-generated method stub - - } - - @Override - public void onOptionsMenuClosed(Menu menu) { - // TODO Auto-generated method stub - super.onOptionsMenuClosed(menu); - } - - private ServiceConnection mConnection = new ServiceConnection() { - - @Override - public void onServiceDisconnected(ComponentName name) { - - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - - CalibrationService calibservice = ((CalibrationService.CalibrationServiceBinder) service) - .getService(); - if (!SDCardChecker.CheckStorage(Calibration.this)) - return; - SDCardChecker.MakeDataDir(Calibration.this); - - File calibfile = SDCardChecker.getFile(calibservice, - R.string.calibfile); - try { - - Calibrator tcalib = calibrator; - calibrator = new Calibrator(Calibration.this); - setCallbackStack(); - calibservice.startCalibrating(Calibration.class, R.drawable.icon,tcalib, calibfile); - } catch (IOException e) { - e.printStackTrace(); - } - - // Tell the user about this for our demo. - Toast.makeText(Calibration.this, - "Starting calibration in the background.", - Toast.LENGTH_SHORT).show(); - unbindService(this); - } - - }; - - public static File getCalibrationFile(Context ctx) { - return SDCardChecker.getFile(ctx, R.string.calibfile); - } - - void doBindCalibService() { - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - bindService(new Intent(Calibration.this, CalibrationService.class), - mConnection, Context.BIND_AUTO_CREATE); - } - - void calibrate() { - if (calibrator.getNumberPatternsDetected() < 3) { - Toast.makeText(this, getText(R.string.calibration_not_enough), - Toast.LENGTH_LONG).show(); - return; - } - Intent calibservice = new Intent(Calibration.this, - CalibrationService.class); - startService(calibservice); - doBindCalibService(); - - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setFullscreen(); - disableScreenTurnOff(); - setContentView(R.layout.calib_camera); - mPreview = (NativePreviewer) findViewById(R.id.nativepreviewer); - mPreview.setPreviewSize(800, 400); - mPreview.setGrayscale(true); - LinearLayout glview_layout = (LinearLayout) findViewById(R.id.glview_layout); - glview = new GL2CameraViewer(getApplication(), false, 0, 0); - glview_layout.addView(glview); - calibrator = new Calibrator(this); - - ImageButton capturebutton = (ImageButton) findViewById(R.id.capture); - capturebutton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - calibrator.queueChessCapture(); - - } - }); - ImageButton calibbutton = (ImageButton) findViewById(R.id.calibrate); - calibbutton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - calibrate(); - } - }); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - } - - @Override - protected void onPause() { - super.onPause(); - - mPreview.onPause(); - - glview.onPause(); - - } - - protected void setCallbackStack() { - calibrator.setPatternSize(ChessBoardChooser.getPatternSize(this)); - - LinkedList callbackstack = new LinkedList(); - callbackstack.add(calibrator); - callbackstack.add(glview.getDrawCallback()); - mPreview.addCallbackStack(callbackstack); - updateNumber(calibrator); - } - - @Override - protected void onResume() { - super.onResume(); - int size[] ={0,0}; - CameraConfig.readImageSize(getApplicationContext(), size); - int mode = CameraConfig.readCameraMode(getApplicationContext()); - mPreview.setPreviewSize(size[0], size[1]); - mPreview.setGrayscale(mode == CameraConfig.CAMERA_MODE_BW ? true : false); - - glview.onResume(); - mPreview.onResume(); - setCallbackStack(); - - } - - void updateNumber(Calibrator calibrator) { - TextView numbertext = (TextView) findViewById(R.id.numberpatterns); - int numdetectd = calibrator.getNumberPatternsDetected(); - if (numdetectd > 2) { - numbertext - .setTextColor(getResources().getColor(R.color.good_color)); - - } else - numbertext.setTextColor(getResources().getColor(R.color.bad_color)); - - numbertext.setText(String.valueOf(numdetectd)); - - } - - @Override - public void onFoundChessboard(final Calibrator calibrator) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - Toast.makeText(Calibration.this, - "Captured a calibration pattern!", Toast.LENGTH_SHORT) - .show(); - updateNumber(calibrator); - - } - }); - - } - - @Override - public void onDoneCalibration(Calibrator calibration, File calibfile) { - - } - - @Override - public void onFailedChessboard(final Calibrator calibrator) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - Toast.makeText( - Calibration.this, - "No pattern found. Make sure its the right dimensions, and close enough...", - Toast.LENGTH_LONG).show(); - updateNumber(calibrator); - - } - }); - - } - -} \ No newline at end of file diff --git a/android/apps/Calibration/src/com/opencv/misc/SDCardChecker.java b/android/apps/Calibration/src/com/opencv/misc/SDCardChecker.java deleted file mode 100644 index 1a7d2b7e2c..0000000000 --- a/android/apps/Calibration/src/com/opencv/misc/SDCardChecker.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.opencv.misc; - -import java.io.File; - -import android.content.Context; -import android.os.Environment; -import android.widget.Toast; - -import com.opencv.calibration.R; - -public class SDCardChecker { - - public static File createThumb(Context ctx, File workingDir) { - return new File(workingDir, "thumb.jpg"); - } - - public static File getDir(Context ctx, String relativename) { - return new File(Environment.getExternalStorageDirectory() - + relativename); - } - - public static File getDir(Context ctx, int id) { - return new File(Environment.getExternalStorageDirectory() - + ctx.getResources().getString(id)); - } - - public static File getFile(Context ctx, int id) { - return new File(Environment.getExternalStorageDirectory() - + ctx.getResources().getString(id)); - } - - public static void MakeDataDir(Context ctx) { - File dir = getDir(ctx, R.string.sdcarddir); - dir.mkdirs(); - } - - public static boolean CheckStorage(Context ctx) { - boolean mExternalStorageAvailable = false; - boolean mExternalStorageWriteable = false; - String state = Environment.getExternalStorageState(); - - if (Environment.MEDIA_MOUNTED.equals(state)) { - // We can read and write the media - mExternalStorageAvailable = mExternalStorageWriteable = true; - } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { - // We can only read the media - mExternalStorageAvailable = true; - mExternalStorageWriteable = false; - } else { - // Something else is wrong. It may be one of many other states, but - // all we need - // to know is we can neither read nor write - mExternalStorageAvailable = mExternalStorageWriteable = false; - } - boolean goodmount = mExternalStorageAvailable - && mExternalStorageWriteable; - if (!goodmount) { - Toast.makeText(ctx, ctx.getString(R.string.sdcard_error_msg), - Toast.LENGTH_LONG).show(); - } - return goodmount; - } - -} diff --git a/android/apps/HelloAndroid/cmake_android.cmd b/android/apps/HelloAndroid/cmake_android.cmd deleted file mode 100644 index e43e39016b..0000000000 --- a/android/apps/HelloAndroid/cmake_android.cmd +++ /dev/null @@ -1,9 +0,0 @@ -@ECHO OFF -SETLOCAL -PUSHD %~dp0 -SET PROJECT_NAME=HelloAndroid -SET BUILD_DIR=build_armeabi -SET ARM_TARGET=armeabi -CALL ..\..\scripts\build.cmd %* -POPD -ENDLOCAL \ No newline at end of file diff --git a/android/apps/OpenCV_SAMPLE/AndroidManifest.xml b/android/apps/OpenCV_SAMPLE/AndroidManifest.xml deleted file mode 100644 index c129d813a6..0000000000 --- a/android/apps/OpenCV_SAMPLE/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/apps/OpenCV_SAMPLE/CMakeLists.txt b/android/apps/OpenCV_SAMPLE/CMakeLists.txt deleted file mode 100644 index 954ba5b963..0000000000 --- a/android/apps/OpenCV_SAMPLE/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(OpenCV_SAMPLE) - -add_subdirectory(jni) diff --git a/android/apps/OpenCV_SAMPLE/cmake_android.cmd b/android/apps/OpenCV_SAMPLE/cmake_android.cmd deleted file mode 100644 index ce41d62b7c..0000000000 --- a/android/apps/OpenCV_SAMPLE/cmake_android.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@ECHO OFF -SETLOCAL -PUSHD %~dp0 -SET PROJECT_NAME=OpenCV_SAMPLE -CALL ..\..\scripts\build.cmd %* -POPD -ENDLOCAL \ No newline at end of file diff --git a/android/apps/OpenCV_SAMPLE/cmake_android_neon.sh b/android/apps/OpenCV_SAMPLE/cmake_android_neon.sh deleted file mode 100644 index 66a680e598..0000000000 --- a/android/apps/OpenCV_SAMPLE/cmake_android_neon.sh +++ /dev/null @@ -1,4 +0,0 @@ -mkdir build_neon -cd build_neon -cmake -DOpenCV_DIR=../../../build_neon -DAndroidOpenCV_DIR=../../../android-opencv/build_neon -DARM_TARGETS="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN .. - diff --git a/android/apps/OpenCV_SAMPLE/default.properties b/android/apps/OpenCV_SAMPLE/default.properties deleted file mode 100644 index 5d6911a8a9..0000000000 --- a/android/apps/OpenCV_SAMPLE/default.properties +++ /dev/null @@ -1,12 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Project target. -target=android-7 -android.library.reference.1=../../android-opencv/ diff --git a/android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt b/android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt deleted file mode 100644 index 823101c664..0000000000 --- a/android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -######################################################### -# Find opencv and android-opencv -######################################################### - -set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../../build - CACHE PATH "The path where you built opencv for android") -set(AndroidOpenCV_DIR ${CMAKE_SOURCE_DIR}/../../android-opencv/build - CACHE PATH "The path where you built android-opencv") - -find_package(OpenCV REQUIRED) -FIND_PACKAGE(AndroidOpenCV REQUIRED ) - -######################################################### -#c flags, included, and lib dependencies -######################################################### - -#notice the "recycling" of CMAKE_C_FLAGS -#this is necessary to pick up android flags -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" ) - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -set( LIBRARY_DEPS ${AndroidOpenCV_LIBS} ${OpenCV_LIBS} ) -if(ANDROID) - set( LIBRARY_DEPS ${LIBRARY_DEPS} log dl) -endif(ANDROID) - -######################################################### -#SWIG STUFF -######################################################### -#the java package to place swig generated java files in -set(MY_PACKAGE com.OpenCV_SAMPLE.jni ) -set(MY_MODULE OpenCV_SAMPLE ) -set(MY_SWIG - OpenCV_SAMPLE.i #swig file - ) -set(MY_SRCS - cvsample.cpp #cpp files can be compiled to - ) - -if(NOT ANDROID) - #non android swig and jni - #jni is available by default on android - find_package(JNI REQUIRED) - include_directories(${JNI_INCLUDE_DIRS}) - FIND_PACKAGE(SWIG) -endif() - -INCLUDE(${SWIG_USE_FILE}) #on android this is found by the cmake toolchain - -if(ANDROID) - #this will set the output path for the java package - #and properly create the package declarations in generated java sources - SET_SWIG_JAVA_PACKAGE( ${MY_PACKAGE} ) #defined in the android toolchain -endif(ANDROID) - -#this add's the swig path for the opencv wrappers -SET(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} "-I${AndroidOpenCV_SWIG_DIR}" ) - -SET_SOURCE_FILES_PROPERTIES(${MY_SWIG} PROPERTIES CPLUSPLUS ON) - -#add the swig module, giving it the name, java, and then all of the source files -SWIG_ADD_MODULE(${MY_MODULE} java - ${MY_SWIG} - ${MY_SRCS} - ) -#link the module like any other -target_link_libraries(${MY_MODULE} ${LIBRARY_DEPS} ) diff --git a/android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i b/android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i deleted file mode 100644 index 93b6c89466..0000000000 --- a/android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i +++ /dev/null @@ -1,48 +0,0 @@ -/* File : foobar.i */ -%module OpenCV_SAMPLE - -/* - * the java import code muse be included for the opencv jni wrappers - * this means that the android project must reference opencv/android as a project - * see the default.properties for how this is done - */ -%pragma(java) jniclassimports=%{ -import com.opencv.jni.*; //import the android-opencv jni wrappers -%} - -%pragma(java) jniclasscode=%{ - static { - try { - //load up our shared libraries - System.loadLibrary("android-opencv"); - System.loadLibrary("OpenCV_SAMPLE"); - } catch (UnsatisfiedLinkError e) { - //badness - throw e; - } - } - -%} - -//import the android-cv.i file so that swig is aware of all that has been previous defined -//notice that it is not an include.... -%import "android-cv.i" - -%{ -#include "cvsample.h" -using cv::Mat; -%} - -//make sure to import the image_pool as it is -//referenced by the Processor java generated -//class -%typemap(javaimports) CVSample " -import com.opencv.jni.*;// import the opencv java bindings -" -class CVSample -{ -public: - void canny(const Mat& input, Mat& output, int edgeThresh); - void invert(Mat& inout); - void blur(Mat& inout, int half_kernel_size); -}; diff --git a/android/apps/OpenCV_SAMPLE/jni/cvsample.cpp b/android/apps/OpenCV_SAMPLE/jni/cvsample.cpp deleted file mode 100644 index 0f9eea9dc6..0000000000 --- a/android/apps/OpenCV_SAMPLE/jni/cvsample.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "cvsample.h" -#include - -void CVSample::canny(const cv::Mat& input, cv::Mat& output, int edgeThresh) -{ - if (input.empty()) - return; - cv::Mat gray; - if (input.channels() == 3) - { - cv::cvtColor(input, gray, CV_RGB2GRAY); - } - else - gray = input; - cv::Canny(gray, output, edgeThresh, edgeThresh * 3, 3); -} - -void CVSample::invert(cv::Mat& inout) -{ - cv::bitwise_not(inout, inout); -} -void CVSample::blur(cv::Mat& inout, int half_kernel_size) -{ - int ksz = half_kernel_size*2 + 1; - cv::Size kernel(ksz,ksz); - cv::blur(inout,inout,kernel); -} diff --git a/android/apps/OpenCV_SAMPLE/jni/cvsample.h b/android/apps/OpenCV_SAMPLE/jni/cvsample.h deleted file mode 100644 index 345a35c3b6..0000000000 --- a/android/apps/OpenCV_SAMPLE/jni/cvsample.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -class CVSample -{ -public: - void canny(const cv::Mat& input, cv::Mat& output, int edgeThresh); - void invert(cv::Mat& inout); - void blur(cv::Mat& inout, int half_kernel_size); -}; diff --git a/android/apps/OpenCV_SAMPLE/project_create.sh b/android/apps/OpenCV_SAMPLE/project_create.sh deleted file mode 100755 index c058d198bb..0000000000 --- a/android/apps/OpenCV_SAMPLE/project_create.sh +++ /dev/null @@ -1,3 +0,0 @@ -#this generates an ant based cli build of the android-jni project -android update project --name OpenCV_SAMPLE \ ---path . diff --git a/android/apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png b/android/apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png deleted file mode 100644 index 5e11406cb2..0000000000 Binary files a/android/apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/android/apps/OpenCV_SAMPLE/res/drawable-mdpi/icon.png b/android/apps/OpenCV_SAMPLE/res/drawable-mdpi/icon.png deleted file mode 100644 index a591eb892d..0000000000 Binary files a/android/apps/OpenCV_SAMPLE/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml b/android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml deleted file mode 100644 index 8cf02d7b7f..0000000000 --- a/android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/android/apps/OpenCV_SAMPLE/res/values/strings.xml b/android/apps/OpenCV_SAMPLE/res/values/strings.xml deleted file mode 100644 index 1b7d2e73b6..0000000000 --- a/android/apps/OpenCV_SAMPLE/res/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - Hello World, OpenCV_SAMPLE! - OpenCV SAMPLE - diff --git a/android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java b/android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java deleted file mode 100644 index 7002cee8fd..0000000000 --- a/android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.OpenCV_SAMPLE; - -import java.util.LinkedList; - -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import com.OpenCV_SAMPLE.jni.CVSample; -import com.opencv.camera.CameraActivity; -import com.opencv.camera.NativeProcessor; -import com.opencv.camera.NativeProcessor.PoolCallback; -import com.opencv.jni.Mat; -import com.opencv.jni.image_pool; - -public class OpenCV_SAMPLE extends CameraActivity { - - private int do_what = R.id.cv_menu_nothing; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater menu_flater = new MenuInflater(this); - menu_flater.inflate(R.menu.sample_menu, menu); - return true; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - switch (item.getItemId()) { - case R.id.cv_menu_blur: - case R.id.cv_menu_canny: - case R.id.cv_menu_invert: - case R.id.cv_menu_nothing: - do_what = item.getItemId(); - break; - default: - return false; - - } - return true; - } - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Override - protected LinkedList getCallBackStack() { - LinkedList list = new LinkedList(); - list.add(samplePoolCallback); - return list; - } - - CVSample cvsample = new CVSample(); - Mat canny = new Mat(); - PoolCallback samplePoolCallback = new PoolCallback() { - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - Mat grey = pool.getGrey(idx); - Mat color = pool.getImage(idx); - Mat draw_img = color; - switch (do_what) { - case R.id.cv_menu_blur: - cvsample.blur(draw_img, 5); - break; - case R.id.cv_menu_canny: - cvsample.canny(grey, canny, 15); - draw_img = canny; - break; - case R.id.cv_menu_invert: - cvsample.invert(draw_img); - break; - case R.id.cv_menu_nothing: - break; - } - pool.addImage(idx + 1, draw_img); - glview.getDrawCallback().process(idx + 1, pool, timestamp, - nativeProcessor); - } - }; - -} \ No newline at end of file diff --git a/android/apps/camera_template/AndroidManifest.xml b/android/apps/camera_template/AndroidManifest.xml deleted file mode 100644 index 6af45ffec0..0000000000 --- a/android/apps/camera_template/AndroidManifest.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/apps/camera_template/Makefile b/android/apps/camera_template/Makefile deleted file mode 100644 index 4bec050c02..0000000000 --- a/android/apps/camera_template/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -#Re-usable Makefile template for -#android-ndk + swig projects -# The path to the NDK, requires crystax version r-4 for now, due to support -# for the standard library - -# load environment from local make file -LOCAL_ENV_MK=local.env.mk -ifneq "$(wildcard $(LOCAL_ENV_MK))" "" -include $(LOCAL_ENV_MK) -else -$(shell cp sample.$(LOCAL_ENV_MK) $(LOCAL_ENV_MK)) -$(info ERROR local environement not setup! try:) -$(info gedit $(LOCAL_ENV_MK)) -$(error Please setup the $(LOCAL_ENV_MK) - the default was just created') -endif -ifndef ARM_TARGETS -ARM_TARGETS="armeabi armeabi-v7a" -endif -ANDROID_NDK_BASE = $(ANDROID_NDK_ROOT) - -$(info OPENCV_CONFIG = $(OPENCV_CONFIG)) - -ifndef PROJECT_PATH -$(info PROJECT_PATH defaulting to this directory) -PROJECT_PATH=. -endif - -android_jni=../../android-jni/jni - -# The name of the native library -LIBNAME = libfoobar.so - -#define the main jni swig interface file -#the desired java package name -#and the desired java directory -#notice that the package and the java dir -#are related... -SWIG_MAIN = jni/foobar.i -SWIG_JAVA_PACKAGE = com.foo.bar.jni -SWIG_JAVA_DIR = src/com/foo/bar/jni - -SWIG_BASE = foobar - -#swig definitions - auto as long as all the -#swig interface files are in jni/*.i -SWIG_JAVA_OUT = $(wildcard $(SWIG_JAVA_DIR)/*.java) -SWIG_IS = $(wildcard jni/*.i) -#the main swig file that includes others -SWIG_MAIN = jni/foobar.i -SWIG_C_DIR = jni/gen -SWIG_C_OUT = $(SWIG_C_DIR)/foo_swig.cpp - -# Find all the C++ sources in the native folder -SOURCES = $(wildcard jni/*.cpp) -HEADERS = $(wildcard jni/*.h) - -ANDROID_MKS = $(wildcard jni/*.mk) - - -BUILD_DEFS=OPENCV_CONFIG=$(OPENCV_CONFIG) \ - PROJECT_PATH=$(PROJECT_PATH) \ - V=$(V) \ - $(NDK_FLAGS) \ - ARM_TARGETS=$(ARM_TARGETS) \ - SWIG_C_OUT=$(SWIG_C_OUT) - -# The real native library stripped of symbols -LIB = libs/armeabi-v7a/$(LIBNAME) libs/armeabi/$(LIBNAME) - - -all: $(LIB) - - -#calls the ndk-build script, passing it OPENCV_ROOT and OPENCV_LIBS_DIR -$(LIB): $(SWIG_C_OUT) $(SOURCES) $(HEADERS) $(ANDROID_MKS) - $(ANDROID_NDK_BASE)/ndk-build $(BUILD_DEFS) - - -#this creates the swig wrappers -$(SWIG_C_OUT): $(SWIG_IS) - make clean-swig &&\ - mkdir -p $(SWIG_C_DIR) &&\ - mkdir -p $(SWIG_JAVA_DIR) &&\ - swig -java -c++ -I$(android_jni) -package "$(SWIG_JAVA_PACKAGE)" \ - -outdir $(SWIG_JAVA_DIR) \ - -o $(SWIG_C_OUT) $(SWIG_MAIN) - - -#clean targets -.PHONY: clean clean-swig cleanall - -#this deletes the generated swig java and the generated c wrapper -clean-swig: - rm -f $(SWIG_JAVA_OUT) $(SWIG_C_OUT) - -#does clean-swig and then uses the ndk-build clean -clean: clean-swig - $(ANDROID_NDK_BASE)/ndk-build clean $(BUILD_DEFS) - - diff --git a/android/apps/camera_template/README.txt b/android/apps/camera_template/README.txt deleted file mode 100644 index 14d57b56f6..0000000000 --- a/android/apps/camera_template/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -see http://code.google.com/p/android-opencv/wiki/camera_template - diff --git a/android/apps/camera_template/build.sh b/android/apps/camera_template/build.sh deleted file mode 100644 index 92772c3a78..0000000000 --- a/android/apps/camera_template/build.sh +++ /dev/null @@ -1 +0,0 @@ -make OPENCV_ROOT=../../opencv V=0 diff --git a/android/apps/camera_template/clean.sh b/android/apps/camera_template/clean.sh deleted file mode 100644 index 121e391e4e..0000000000 --- a/android/apps/camera_template/clean.sh +++ /dev/null @@ -1 +0,0 @@ -make OPENCV_ROOT=../../opencv V=0 clean diff --git a/android/apps/camera_template/default.properties b/android/apps/camera_template/default.properties deleted file mode 100644 index 22f3e44f0e..0000000000 --- a/android/apps/camera_template/default.properties +++ /dev/null @@ -1,12 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -android.library.reference.1=../../android-jni/ -# Project target. -target=android-7 diff --git a/android/apps/camera_template/jni/Android.mk b/android/apps/camera_template/jni/Android.mk deleted file mode 100644 index a943255bd1..0000000000 --- a/android/apps/camera_template/jni/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# date: Summer, 2010 -# author: Ethan Rublee -# contact: ethan.rublee@gmail.com -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -#define OPENCV_INCLUDES and OPENCV_LIBS -include $(OPENCV_CONFIG) - -LOCAL_LDLIBS += $(OPENCV_LIBS) $(ANDROID_OPENCV_LIBS) -llog -lGLESv2 - -LOCAL_C_INCLUDES += $(OPENCV_INCLUDES) $(ANDROID_OPENCV_INCLUDES) - -LOCAL_MODULE := foobar - -#make sure to pass in SWIG_C_OUT=gen/foobar_swig.cpp -#done in the makefile -LOCAL_SRC_FILES := gen/foo_swig.cpp TestBar.cpp - -include $(BUILD_SHARED_LIBRARY) - diff --git a/android/apps/camera_template/jni/Application.mk b/android/apps/camera_template/jni/Application.mk deleted file mode 100644 index 0bbce43113..0000000000 --- a/android/apps/camera_template/jni/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -# The ARMv7 is significanly faster due to the use of the hardware FPU -APP_ABI := $(ARM_TARGETS) \ No newline at end of file diff --git a/android/apps/camera_template/jni/TestBar.cpp b/android/apps/camera_template/jni/TestBar.cpp deleted file mode 100644 index 869113a310..0000000000 --- a/android/apps/camera_template/jni/TestBar.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "TestBar.h" - -void BarBar::crazy(){ - -} diff --git a/android/apps/camera_template/jni/TestBar.h b/android/apps/camera_template/jni/TestBar.h deleted file mode 100644 index e919f8f324..0000000000 --- a/android/apps/camera_template/jni/TestBar.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * TestBar.h - * - * Created on: Jul 17, 2010 - * Author: ethan - */ - -#ifndef TESTBAR_H_ -#define TESTBAR_H_ - -#include "image_pool.h" - -struct FooBarStruct { - - int pool_image_count(image_pool* pool){ - return pool->getCount(); - } - -}; - -class BarBar{ -public: - void crazy(); -}; - -#endif /* TESTBAR_H_ */ diff --git a/android/apps/camera_template/jni/foobar.i b/android/apps/camera_template/jni/foobar.i deleted file mode 100644 index a66a059322..0000000000 --- a/android/apps/camera_template/jni/foobar.i +++ /dev/null @@ -1,68 +0,0 @@ -/* File : foobar.i */ -%module foobar - -/* - * the java import code muse be included for the opencv jni wrappers - * this means that the android project must reference opencv/android as a project - * see the default.properties for how this is done - */ -%pragma(java) jniclassimports=%{ -import com.opencv.jni.*; //import the android-opencv jni wrappers -%} - -%pragma(java) jniclasscode=%{ - static { - try { - //load the cvcamera library, make sure that libcvcamera.so is in your /libs/armeabi directory - //so that android sdk automatically installs it along with the app. - - //the android-opencv lib must be loaded first inorder for the cvcamera - //lib to be found - //check the apk generated, by opening it in an archive manager, to verify that - //both these libraries are present - System.loadLibrary("android-opencv"); - System.loadLibrary("foobar"); - } catch (UnsatisfiedLinkError e) { - //badness - throw e; - } - } - -%} - -%{ -#include "image_pool.h" -#include "TestBar.h" -using namespace cv; -%} - - -//import the android-cv.i file so that swig is aware of all that has been previous defined -//notice that it is not an include.... -%import "android-cv.i" - - -//make sure to import the image_pool as it is -//referenced by the Processor java generated -//class -%typemap(javaimports) FooBarStruct " -import com.opencv.jni.image_pool;// import the image_pool interface for playing nice with - // android-opencv - -/** FooBar - template -*/" - -//sample inline class that needs to include image_pool -struct FooBarStruct { - - int pool_image_count(image_pool* pool){ - return pool->getCount(); - } - -}; - -//sample jni class -class BarBar{ -public: - void crazy(); -}; diff --git a/android/apps/camera_template/res/drawable-ldpi/icon.png b/android/apps/camera_template/res/drawable-ldpi/icon.png deleted file mode 100644 index 5e11406cb2..0000000000 Binary files a/android/apps/camera_template/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/android/apps/camera_template/res/drawable-mdpi/icon.png b/android/apps/camera_template/res/drawable-mdpi/icon.png deleted file mode 100644 index a591eb892d..0000000000 Binary files a/android/apps/camera_template/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/android/apps/camera_template/res/values/strings.xml b/android/apps/camera_template/res/values/strings.xml deleted file mode 100644 index 5ff41dc254..0000000000 --- a/android/apps/camera_template/res/values/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - -FooBar -FooBar is a template app for the android-opencv project!\nVisit http://code.google.com/p/android-opencv for details. -About FooBar -About -O.K. - diff --git a/android/apps/camera_template/sample.local.env.mk b/android/apps/camera_template/sample.local.env.mk deleted file mode 100644 index b0cf78fd36..0000000000 --- a/android/apps/camera_template/sample.local.env.mk +++ /dev/null @@ -1,4 +0,0 @@ -#location of android-opencv port of OpenCV to android -OPENCV_CONFIG=../../build/android-opencv.mk -ANDROID_NDK_ROOT=$(HOME)/android-ndk-r4-crystax -ARM_TARGETS="armeabi armeabi-v7a" diff --git a/android/apps/camera_template/src/com/foo/bar/FooBar.java b/android/apps/camera_template/src/com/foo/bar/FooBar.java deleted file mode 100644 index 6bc31be5b0..0000000000 --- a/android/apps/camera_template/src/com/foo/bar/FooBar.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.foo.bar; - -import java.util.LinkedList; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.util.Log; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.Window; -import android.view.WindowManager; -import android.view.ViewGroup.LayoutParams; -import android.widget.FrameLayout; -import android.widget.LinearLayout; - -//make sure you have the OpenCV project open, so that the -//android-sdk can find it! -import com.foo.bar.jni.BarBar; -import com.foo.bar.jni.FooBarStruct; -import com.opencv.camera.NativePreviewer; -import com.opencv.camera.NativeProcessor; -import com.opencv.camera.NativeProcessor.PoolCallback; -import com.opencv.jni.image_pool; -import com.opencv.opengl.GL2CameraViewer; - -public class FooBar extends Activity { - - private final int FOOBARABOUT = 0; - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog; - switch (id) { - case FOOBARABOUT: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.about_title); - builder.setMessage(R.string.about_str); - builder.setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dismissDialog(FOOBARABOUT); - - } - }); - dialog = builder.create(); - default: - dialog = null; - } - return dialog; - } - - /* - * Handle the capture button as follows... - */ - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - - switch (keyCode) { - case KeyEvent.KEYCODE_CAMERA: - case KeyEvent.KEYCODE_SPACE: - case KeyEvent.KEYCODE_DPAD_CENTER: - // capture button pressed here - return true; - - default: - return super.onKeyUp(keyCode, event); - } - - } - - /* - * Handle the capture button as follows... On some phones there is no - * capture button, only trackball - */ - @Override - public boolean onTrackballEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - // capture button pressed - return true; - } - return super.onTrackballEvent(event); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(R.string.about_menu); - return true; - } - - private NativePreviewer mPreview; - private GL2CameraViewer glview; - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // example menu - if (item.getTitle().equals( - getResources().getString(R.string.about_menu))) { - showDialog(FOOBARABOUT); - } - return true; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - - FrameLayout frame = new FrameLayout(this); - - // Create our Preview view and set it as the content of our activity. - mPreview = new NativePreviewer(getApplication(), 300, 300); - - LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - params.height = getWindowManager().getDefaultDisplay().getHeight(); - params.width = (int) (params.height * 4.0 / 2.88); - - LinearLayout vidlay = new LinearLayout(getApplication()); - - vidlay.setGravity(Gravity.CENTER); - vidlay.addView(mPreview, params); - frame.addView(vidlay); - - // make the glview overlay ontop of video preview - mPreview.setZOrderMediaOverlay(false); - - glview = new GL2CameraViewer(getApplication(), false, 0, 0); - glview.setZOrderMediaOverlay(true); - glview.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.FILL_PARENT)); - frame.addView(glview); - - setContentView(frame); - - } - - @Override - protected void onPause() { - super.onPause(); - - // IMPORTANT - // must tell the NativePreviewer of a pause - // and the glview - so that they can release resources and start back up - // properly - // failing to do this will cause the application to crash with no - // warning - // on restart - // clears the callback stack - mPreview.onPause(); - - glview.onPause(); - - } - - @Override - protected void onResume() { - super.onResume(); - - // resume the opengl viewer first - glview.onResume(); - - // add an initial callback stack to the preview on resume... - // this one will just draw the frames to opengl - LinkedList cbstack = new LinkedList(); - - // SpamProcessor will be called first - cbstack.add(new SpamProcessor()); - - // then the same idx and pool will be passed to - // the glview callback - - // so operate on the image at idx, and modify, and then - // it will be drawn in the glview - // or remove this, and call glview manually in SpamProcessor - // cbstack.add(glview.getDrawCallback()); - - mPreview.addCallbackStack(cbstack); - mPreview.onResume(); - - } - - class SpamProcessor implements NativeProcessor.PoolCallback { - - FooBarStruct foo = new FooBarStruct(); - BarBar barbar = new BarBar(); - - @Override - public void process(int idx, image_pool pool, long timestamp, - NativeProcessor nativeProcessor) { - - // example of using the jni generated FoobarStruct; - int nImages = foo.pool_image_count(pool); - Log.i("foobar", "Number of images in pool: " + nImages); - - // call a function - this function does absolutely nothing! - barbar.crazy(); - - // sample processor - // this gets called every frame in the order of the list - // first add to the callback stack linked list will be the - // first called - // the idx and pool may be used to get the cv::Mat - // that is the latest frame being passed. - // pool.getClass(idx) - - // these are what the glview.getDrawCallback() calls - glview.drawMatToGL(idx, pool); - glview.requestRender(); - - } - - } - -} diff --git a/android/scripts/build.cmd b/android/scripts/build.cmd index be62d05689..97b9cd96b8 100644 --- a/android/scripts/build.cmd +++ b/android/scripts/build.cmd @@ -19,7 +19,6 @@ POPD IF NOT DEFINED BUILD_DIR SET BUILD_DIR=build IF NOT DEFINED ARM_TARGET SET ARM_TARGET=armeabi-v7a SET OPENCV_BUILD_DIR=%SCRIPTS_DIR%\..\%BUILD_DIR% -SET ANDROID_OPENCV_BUILD_DIR=%SCRIPTS_DIR%\..\android-opencv\%BUILD_DIR% :: check that all required variables defined PUSHD . @@ -34,9 +33,6 @@ IF NOT %BUILD_JAVA_PART%==1 GOTO required_variables_checked IF NOT DEFINED ANDROID_SDK (ECHO. & ECHO You should set an environment variable ANDROID_SDK to the full path to your copy of Android SDK & GOTO end) (CD "%ANDROID_SDK%" 2>NUL) || (ECHO. & ECHO Directory "%ANDROID_SDK%" specified by ANDROID_SDK variable does not exist & GOTO end) -IF NOT DEFINED SWIG_DIR (ECHO. & ECHO You should set an environment variable SWIG_DIR to the full path to SWIG root & GOTO end) -(CD "%SWIG_DIR%" 2>NUL) || (ECHO. & ECHO Directory "%SWIG_DIR%" specified by SWIG_DIR variable does not exist & GOTO end) - IF NOT DEFINED ANT_DIR (ECHO. & ECHO You should set an environment variable ANT_DIR to the full path to Apache Ant root & GOTO end) (CD "%ANT_DIR%" 2>NUL) || (ECHO. & ECHO Directory "%ANT_DIR%" specified by ANT_DIR variable does not exist & GOTO end) @@ -57,10 +53,10 @@ ECHO ARM_TARGET=%ARM_TARGET% ECHO. IF NOT %BUILD_OPENCV%==1 GOTO other-cmake :opencv-cmake -("%CMAKE_EXE%" -G"MinGW Makefiles" -DARM_TARGET="%ARM_TARGET%" -C "%SOURCE_DIR%\CMakeCache.android.initial.cmake" -DCMAKE_TOOLCHAIN_FILE="%SOURCE_DIR%"\android.toolchain.cmake -DCMAKE_MAKE_PROGRAM="%MAKE_EXE%" "%SOURCE_DIR%\..") && GOTO cmakefin +("%CMAKE_EXE%" -G"MinGW Makefiles" -DARM_TARGET="%ARM_TARGET%" -C "%SOURCE_DIR%\CMakeCache.android.initial.cmake" -DCMAKE_TOOLCHAIN_FILE="%SOURCE_DIR%"\android.toolchain.cmake -DCMAKE_MAKE_PROGRAM="%MAKE_EXE%" %* "%SOURCE_DIR%\..") && GOTO cmakefin ECHO. & ECHO cmake failed & GOTO end :other-cmake -("%CMAKE_EXE%" -G"MinGW Makefiles" -DARM_TARGET="%ARM_TARGET%" -DOpenCV_DIR="%OPENCV_BUILD_DIR%" -DAndroidOpenCV_DIR="%ANDROID_OPENCV_BUILD_DIR%" -DCMAKE_PROGRAM_PATH="%SWIG_DIR%" -DCMAKE_TOOLCHAIN_FILE="%OPENCV_BUILD_DIR%\..\android.toolchain.cmake" -DCMAKE_MAKE_PROGRAM="%MAKE_EXE%" "%SOURCE_DIR%") && GOTO cmakefin +("%CMAKE_EXE%" -G"MinGW Makefiles" -DARM_TARGET="%ARM_TARGET%" -DOpenCV_DIR="%OPENCV_BUILD_DIR%" -DCMAKE_TOOLCHAIN_FILE="%OPENCV_BUILD_DIR%\..\android.toolchain.cmake" -DCMAKE_MAKE_PROGRAM="%MAKE_EXE%" %* "%SOURCE_DIR%") && GOTO cmakefin ECHO. & ECHO cmake failed & GOTO end :cmakefin diff --git a/android/scripts/cmake_android.sh b/android/scripts/cmake_android.sh index e95d35f9b3..c17110e69b 100644 --- a/android/scripts/cmake_android.sh +++ b/android/scripts/cmake_android.sh @@ -4,5 +4,5 @@ cd `dirname $0`/.. mkdir -p build cd build -cmake -C ../CMakeCache.android.initial.cmake -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake ../.. +cmake -C ../CMakeCache.android.initial.cmake -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake $@ ../.. diff --git a/android/scripts/cmake_android_armeabi.sh b/android/scripts/cmake_android_armeabi.sh index 3e6ee1d68c..961c9d685f 100644 --- a/android/scripts/cmake_android_armeabi.sh +++ b/android/scripts/cmake_android_armeabi.sh @@ -4,5 +4,5 @@ cd `dirname $0`/.. mkdir -p build_armeabi cd build_armeabi -cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGET=armeabi -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake ../.. +cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGET=armeabi -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake $@ ../.. diff --git a/android/scripts/cmake_android_neon.sh b/android/scripts/cmake_android_neon.sh index 7b29b9f1f9..4212210491 100644 --- a/android/scripts/cmake_android_neon.sh +++ b/android/scripts/cmake_android_neon.sh @@ -4,5 +4,5 @@ cd `dirname $0`/.. mkdir -p build_neon cd build_neon -cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGET="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake ../.. +cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGET="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake $@ ../.. diff --git a/android/scripts/package.sh b/android/scripts/package.sh new file mode 100644 index 0000000000..c2593936e0 --- /dev/null +++ b/android/scripts/package.sh @@ -0,0 +1,114 @@ +#!/bin/sh +cd `dirname $0`/.. + +ANDROID_DIR=`pwd` + +rm -rf package +mkdir -p package +cd package + +PRG_DIR=`pwd` +mkdir opencv + +# neon-enabled build +#cd $PRG_DIR +#mkdir build-neon +#cd build-neon + +#cmake -C "$ANDROID_DIR/CMakeCache.android.initial.cmake" -DARM_TARGET="armeabi-v7a with NEON" -DBUILD_DOCS=OFF -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_ANDROID_EXAMPLES=OFF -DCMAKE_TOOLCHAIN_FILE="$ANDROID_DIR/android.toolchain.cmake" -DCMAKE_INSTALL_PREFIX="$PRG_DIR/opencv" "$ANDROID_DIR/.." || exit 1 +#make -j8 install/strip || exit 1 + +#cd "$PRG_DIR/opencv" +#rm -rf doc include src .classpath .project AndroidManifest.xml default.properties share/OpenCV/haarcascades share/OpenCV/lbpcascades share/OpenCV/*.cmake share/OpenCV/OpenCV.mk +#mv libs/armeabi-v7a libs/armeabi-v7a-neon +#mv share/OpenCV/3rdparty/libs/armeabi-v7a share/OpenCV/3rdparty/libs/armeabi-v7a-neon + + +# armeabi-v7a build +cd "$PRG_DIR" +mkdir build +cd build + +cmake -C "$ANDROID_DIR/CMakeCache.android.initial.cmake" -DARM_TARGET="armeabi-v7a" -DBUILD_DOCS=OFF -DBUILD_TESTS=ON -DBUILD_EXAMPLES=OFF -DBUILD_ANDROID_EXAMPLES=ON -DCMAKE_TOOLCHAIN_FILE="$ANDROID_DIR/android.toolchain.cmake" -DCMAKE_INSTALL_PREFIX="$PRG_DIR/opencv" "$ANDROID_DIR/.." || exit 1 +make -j8 install/strip || exit 1 + +cd "$PRG_DIR/opencv" +rm -rf doc include src .classpath .project AndroidManifest.xml default.properties share/OpenCV/haarcascades share/OpenCV/lbpcascades share/OpenCV/*.cmake share/OpenCV/OpenCV.mk + + +# armeabi build +cd "$PRG_DIR/build" +rm -rf CMakeCache.txt + +cmake -C "$ANDROID_DIR/CMakeCache.android.initial.cmake" -DARM_TARGET="armeabi" -DBUILD_DOCS=ON -DBUILD_TESTS=ON -DBUILD_EXAMPLES=OFF -DBUILD_ANDROID_EXAMPLES=ON -DINSTALL_ANDROID_EXAMPLES=ON -DCMAKE_TOOLCHAIN_FILE="$ANDROID_DIR/android.toolchain.cmake" -DCMAKE_INSTALL_PREFIX="$PRG_DIR/opencv" "$ANDROID_DIR/.." || exit 1 +make -j8 install/strip docs || exit 1 + +find doc -name "*.pdf" -exec cp {} $PRG_DIR/opencv/doc \; + +cd $PRG_DIR +rm -rf opencv/doc/CMakeLists.txt +cp "$ANDROID_DIR/README.android" opencv/ +cp "$ANDROID_DIR/../README" opencv/ + + +# get opencv version +CV_VERSION=`grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+" opencv/share/OpenCV/OpenCVConfig-version.cmake` +OPENCV_NAME=OpenCV-$CV_VERSION +mv opencv $OPENCV_NAME + +#samples +cp -r "$ANDROID_DIR/../samples/android" "$PRG_DIR/samples" +cd "$PRG_DIR/samples" + +#enable for loops over items with spaces in their name +IFS=" +" +for dir in `ls -1` +do + if [ -f "$dir/default.properties" ] + then + HAS_REFERENCE=`cat "$dir/default.properties" | grep -c android.library.reference.1` + if [ $HAS_REFERENCE = 1 ] + then + echo -n > "$dir/default.properties" + android update project --name "$dir" --target "android-8" --library "../../$OPENCV_NAME" --path "$dir" + #echo 'android update project --name "$dir" --target "android-8" --library "../opencv$CV_VERSION" --path "$dir"' + fi + else + rm -rf "$dir" + fi +done + +echo "OPENCV_MK_PATH:=../../$OPENCV_NAME/share/OpenCV/OpenCV.mk" > includeOpenCV.mk + + +#clean samples +cd "$PRG_DIR/samples" +#remove ignored files/folders +svn status --no-ignore | grep ^I | cut -c9- | xargs -d \\n rm -rf +#remove unversioned files/folders +svn status | grep ^\? | cut -c9- | xargs -d \\n rm -rf + + +#generate "gen" folders to eliminate eclipse warnings +cd "$PRG_DIR/samples" +for dir in `ls -1` +do + if [ -d "$dir" ] + then + mkdir "$dir/gen" + fi +done + + +#generate folders "gen" and "res" for opencv (dummy eclipse stiff) +cd $PRG_DIR +mkdir "$OPENCV_NAME/gen" +mkdir "$OPENCV_NAME/res" + +# pack all files +cd $PRG_DIR +PRG_NAME=OpenCV-$CV_VERSION-tp-android-bin.tar.bz2 +tar cjpf $PRG_NAME --exclude-vcs $OPENCV_NAME samples || exit -1 +echo +echo "Package $PRG_NAME is successfully created" diff --git a/android/scripts/wincfg.cmd.tmpl b/android/scripts/wincfg.cmd.tmpl index 3ba62a5bd7..f095927616 100644 --- a/android/scripts/wincfg.cmd.tmpl +++ b/android/scripts/wincfg.cmd.tmpl @@ -1,11 +1,10 @@ :: variables required for OpenCV build :: :: Note: all pathes should be specified without tailing slashes! -SET ANDROID_NDK=C:\full\path\to\your\copy\of\android\NDK\android-ndk-r5c +SET ANDROID_NDK=C:\full\path\to\your\copy\of\android\NDK\android-ndk-r6 SET CMAKE_EXE=C:\full\path\to\cmake\utility\cmake.exe SET MAKE_EXE=C:\full\path\to\native\port\of\make\utility\make.exe :: variables required for android-opencv build :: -SET SWIG_DIR=C:\full\path\to\SWIG\directory\swigwin-2.0.3 SET ANDROID_SDK=C:\full\path\to\your\copy\of\android\SDK\android-sdk-windows SET ANT_DIR=C:\full\path\to\ant\directory\apache-ant-1.8.2 SET JAVA_HOME=C:\full\path\to\JDK\jdk1.6.0_25 @@ -24,4 +23,4 @@ SET BUILD_DIR=build ::SET BUILD_DIR=build_neon :::: other options -::SET ANDROID_API_LEVEL=8 &:: android-3 is enough for OpenCV but android-8 is recommended +::SET ANDROID_API_LEVEL=8 &:: android-3 is enough for native part of OpenCV but android-8 is required for Java API and samples diff --git a/cvconfig.h.cmake b/cvconfig.h.cmake index e61a2261a7..4bd16dda90 100644 --- a/cvconfig.h.cmake +++ b/cvconfig.h.cmake @@ -184,3 +184,5 @@ /* VideoInput library */ #cmakedefine HAVE_VIDEOINPUT +/* XIMEA camera support */ +#cmakedefine HAVE_XIMEA diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 53a305811c..0eba875cb3 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -2,6 +2,6 @@ file(GLOB HAAR_CASCADES haarcascades/*.xml) file(GLOB LBP_CASCADES lbpcascades/*.xml) if(NOT WIN32) -install(FILES ${HAAR_CASCADES} DESTINATION share/opencv/haarcascades COMPONENT main) -install(FILES ${LBP_CASCADES} DESTINATION share/opencv/lbpcascades COMPONENT main) +install(FILES ${HAAR_CASCADES} DESTINATION share/OpenCV/haarcascades COMPONENT main) +install(FILES ${LBP_CASCADES} DESTINATION share/OpenCV/lbpcascades COMPONENT main) endif() diff --git a/data/haarcascades/haarcascade_mcs_leftear.xml b/data/haarcascades/haarcascade_mcs_leftear.xml new file mode 100644 index 0000000000..a5a0383563 --- /dev/null +++ b/data/haarcascades/haarcascade_mcs_leftear.xml @@ -0,0 +1,9322 @@ + + + + + + + 12 20 + + <_> + + + <_> + + <_> + + + + <_> + 1 6 8 12 -1. + <_> + 1 6 4 6 2. + <_> + 5 12 4 6 2. + 0 + 1.2798480689525604e-001 + -7.1108317375183105e-001 + 8.3952748775482178e-001 + <_> + + <_> + + + + <_> + 0 3 12 2 -1. + <_> + 0 4 12 1 2. + 0 + 5.0366270443191752e-005 + -7.7958387136459351e-001 + 4.1161769628524780e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 18 6 1 2. + <_> + 6 19 6 1 2. + 0 + -1.1398220434784889e-002 + 5.5991190671920776e-001 + -5.2993881702423096e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + 2.8897399082779884e-002 + -9.6023030579090118e-002 + 1.8446889519691467e-001 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + -5.7543441653251648e-003 + 3.9083909988403320e-001 + -7.0798218250274658e-001 + <_> + + <_> + + + + <_> + 0 0 12 16 -1. + <_> + 0 8 12 8 2. + 0 + 1.2758660130202770e-002 + -7.6031517982482910e-001 + 2.6452711224555969e-001 + <_> + + <_> + + + + <_> + 4 0 4 1 -1. + <_> + 6 0 2 1 2. + 0 + -4.1698651330079883e-005 + 3.2332289218902588e-001 + -5.7402020692825317e-001 + -1.6897829771041870e+000 + -1 + -1 + <_> + + + <_> + + <_> + + + + <_> + 1 6 8 12 -1. + <_> + 1 6 4 6 2. + <_> + 5 12 4 6 2. + 0 + 1.7598830163478851e-001 + -5.9234100580215454e-001 + 7.8493958711624146e-001 + <_> + + <_> + + + + <_> + 0 0 12 8 -1. + <_> + 0 4 12 4 2. + 0 + 3.8594089448451996e-002 + -6.8187582492828369e-001 + 3.8166061043739319e-001 + <_> + + <_> + + + + <_> + 6 8 6 6 -1. + <_> + 4 10 6 2 3. + 1 + 1.2052910029888153e-001 + -3.7438058853149414e-001 + 5.2112519741058350e-001 + <_> + + <_> + + + + <_> + 4 12 8 8 -1. + <_> + 4 12 4 8 2. + 0 + 2.1304990351200104e-001 + 9.7819166257977486e-003 + -6.5798282623291016e-001 + <_> + + <_> + + + + <_> + 0 12 8 8 -1. + <_> + 4 12 4 8 2. + 0 + -1.9179080426692963e-001 + 8.8993859291076660e-001 + -2.3742930591106415e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + 3.7649259902536869e-003 + -9.2071659862995148e-002 + 1.5995720028877258e-001 + <_> + + <_> + + + + <_> + 3 4 6 12 -1. + <_> + 3 7 6 6 2. + 0 + -7.4397800490260124e-003 + 3.5091850161552429e-001 + -5.2880358695983887e-001 + <_> + + <_> + + + + <_> + 8 0 4 18 -1. + <_> + 8 0 2 18 2. + 0 + 8.1300012767314911e-002 + 4.7027029097080231e-002 + -4.8141419887542725e-001 + <_> + + <_> + + + + <_> + 0 0 4 18 -1. + <_> + 2 0 2 18 2. + 0 + 7.9818956553936005e-002 + -3.0336898565292358e-001 + 5.7992082834243774e-001 + <_> + + <_> + + + + <_> + 1 0 10 16 -1. + <_> + 1 8 10 8 2. + 0 + 3.9260480552911758e-002 + -6.1189621686935425e-001 + 2.4700529873371124e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 18 6 1 2. + <_> + 6 19 6 1 2. + 0 + -8.6981123313307762e-003 + 3.0427950620651245e-001 + -4.3165320158004761e-001 + <_> + + <_> + + + + <_> + 3 0 6 1 -1. + <_> + 3 0 3 1 2. + 0 + 5.5766489822417498e-005 + -5.4995632171630859e-001 + 2.4196259677410126e-001 + -1.6203830242156982e+000 + 0 + -1 + <_> + + + <_> + + <_> + + + + <_> + 1 6 8 12 -1. + <_> + 1 6 4 6 2. + <_> + 5 12 4 6 2. + 0 + 1.9991339743137360e-001 + -5.1076048612594604e-001 + 7.2653311491012573e-001 + <_> + + <_> + + + + <_> + 8 3 2 4 -1. + <_> + 7 4 2 2 2. + 1 + -1.6032690473366529e-004 + 1.1732880026102066e-001 + -1.9851410388946533e-001 + <_> + + <_> + + + + <_> + 3 3 4 6 -1. + <_> + 3 5 4 2 3. + 0 + 6.2459441833198071e-003 + -6.2454998493194580e-001 + 4.1317841410636902e-001 + <_> + + <_> + + + + <_> + 0 0 12 12 -1. + <_> + 0 6 12 6 2. + 0 + 5.5343401618301868e-003 + -8.2238370180130005e-001 + 2.2600589692592621e-001 + <_> + + <_> + + + + <_> + 6 8 6 6 -1. + <_> + 4 10 6 2 3. + 1 + 1.0757610201835632e-001 + -5.5525738000869751e-001 + 4.3564280867576599e-001 + <_> + + <_> + + + + <_> + 8 3 1 8 -1. + <_> + 6 5 1 4 2. + 1 + -9.9556613713502884e-003 + 2.9808950424194336e-001 + -3.0220919847488403e-001 + <_> + + <_> + + + + <_> + 2 0 8 1 -1. + <_> + 6 0 4 1 2. + 0 + -4.8354369937442243e-005 + 4.4047379493713379e-001 + -6.6946560144424438e-001 + <_> + + <_> + + + + <_> + 11 0 1 8 -1. + <_> + 9 2 1 4 2. + 1 + 1.9743980374187231e-004 + -2.5094148516654968e-001 + 1.9814400374889374e-001 + <_> + + <_> + + + + <_> + 4 3 8 1 -1. + <_> + 6 5 4 1 2. + 1 + -4.4098760554334149e-005 + 3.0689230561256409e-001 + -6.6775608062744141e-001 + <_> + + <_> + + + + <_> + 8 4 4 13 -1. + <_> + 8 4 2 13 2. + 0 + -1.7941730096936226e-002 + 2.7399578690528870e-001 + -2.9671499133110046e-001 + <_> + + <_> + + + + <_> + 3 0 1 8 -1. + <_> + 3 4 1 4 2. + 0 + 5.3291041695047170e-005 + -6.7100298404693604e-001 + 2.4690890312194824e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 6 18 6 1 2. + <_> + 0 19 6 1 2. + 0 + 6.4407112076878548e-003 + -5.2723282575607300e-001 + 2.4782879650592804e-001 + <_> + + <_> + + + + <_> + 6 11 1 6 -1. + <_> + 6 11 1 3 2. + 1 + -4.9925990402698517e-002 + 8.2168322801589966e-001 + -2.4012729525566101e-001 + <_> + + <_> + + + + <_> + 8 0 4 17 -1. + <_> + 8 0 2 17 2. + 0 + 2.4148030206561089e-003 + -3.8689721375703812e-002 + 1.9318090379238129e-001 + <_> + + <_> + + + + <_> + 0 0 4 17 -1. + <_> + 2 0 2 17 2. + 0 + 6.2534123659133911e-002 + -4.1077169775962830e-001 + 6.0665780305862427e-001 + <_> + + <_> + + + + <_> + 0 12 12 8 -1. + <_> + 0 14 12 4 2. + 0 + 8.8917986431624740e-005 + -6.7601591348648071e-001 + 3.1252190470695496e-001 + <_> + + <_> + + + + <_> + 2 7 6 2 -1. + <_> + 5 7 3 2 2. + 0 + -2.2447909577749670e-004 + 1.8520550429821014e-001 + -7.7942901849746704e-001 + <_> + + <_> + + + + <_> + 3 0 7 16 -1. + <_> + 3 8 7 8 2. + 0 + 1.8156330042984337e-004 + -6.6956442594528198e-001 + 1.5837380290031433e-001 + <_> + + <_> + + + + <_> + 0 0 3 2 -1. + <_> + 0 1 3 1 2. + 0 + 5.0366270443191752e-005 + -4.6770051121711731e-001 + 2.4539180099964142e-001 + <_> + + <_> + + + + <_> + 3 8 6 8 -1. + <_> + 3 12 6 4 2. + 0 + 6.0776848840760067e-005 + -6.8354898691177368e-001 + 1.8664689362049103e-001 + -2.1234118938446045e+000 + 1 + -1 + <_> + + + <_> + + <_> + + + + <_> + 1 7 8 12 -1. + <_> + 1 7 4 6 2. + <_> + 5 13 4 6 2. + 0 + 1.5990820527076721e-001 + -6.2714368104934692e-001 + 7.2424608469009399e-001 + <_> + + <_> + + + + <_> + 6 5 2 2 -1. + <_> + 6 5 2 1 2. + 1 + 7.6372842304408550e-003 + 8.7740488350391388e-002 + -5.2430278062820435e-001 + <_> + + <_> + + + + <_> + 5 3 1 6 -1. + <_> + 5 5 1 2 3. + 0 + 6.0625150799751282e-003 + -4.3119868636131287e-001 + 4.6857520937919617e-001 + <_> + + <_> + + + + <_> + 10 11 2 7 -1. + <_> + 10 11 1 7 2. + 1 + 2.5897640734910965e-002 + 1.5866510570049286e-002 + -6.5979748964309692e-001 + <_> + + <_> + + + + <_> + 2 11 7 2 -1. + <_> + 2 11 7 1 2. + 1 + 5.8885440230369568e-002 + -2.1157009899616241e-001 + 6.7942970991134644e-001 + <_> + + <_> + + + + <_> + 2 16 10 4 -1. + <_> + 2 16 5 4 2. + 0 + 1.1850179731845856e-001 + -1.0366249829530716e-001 + 7.4645912647247314e-001 + <_> + + <_> + + + + <_> + 0 17 1 3 -1. + <_> + 0 18 1 1 3. + 0 + -1.6655250219628215e-003 + -6.7015552520751953e-001 + 2.2192029654979706e-001 + <_> + + <_> + + + + <_> + 11 18 1 2 -1. + <_> + 11 19 1 1 2. + 0 + -4.4783479097532108e-005 + 2.5404050946235657e-001 + -4.9562969803810120e-001 + <_> + + <_> + + + + <_> + 0 18 1 2 -1. + <_> + 0 19 1 1 2. + 0 + -8.3481962792575359e-004 + -7.3370438814163208e-001 + 2.0266470313072205e-001 + <_> + + <_> + + + + <_> + 9 7 3 3 -1. + <_> + 9 8 3 1 3. + 0 + -9.3157468363642693e-003 + -7.3412007093429565e-001 + 7.2000503540039063e-002 + <_> + + <_> + + + + <_> + 6 4 4 3 -1. + <_> + 7 5 2 3 2. + 1 + -2.9555149376392365e-002 + 5.1195901632308960e-001 + -2.5446298718452454e-001 + <_> + + <_> + + + + <_> + 8 4 4 3 -1. + <_> + 8 5 4 1 3. + 0 + -7.9029072076082230e-003 + -5.3299552202224731e-001 + 8.8295362889766693e-002 + -1.4351799488067627e+000 + 2 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 11 5 4 -1. + <_> + 4 11 5 2 2. + 1 + 9.8843306303024292e-002 + -5.0631648302078247e-001 + 6.3027667999267578e-001 + <_> + + <_> + + + + <_> + 7 4 2 4 -1. + <_> + 7 4 2 2 2. + 1 + -4.2210938408970833e-003 + 1.7837150394916534e-001 + -3.3268490433692932e-001 + <_> + + <_> + + + + <_> + 5 4 4 2 -1. + <_> + 5 4 2 2 2. + 1 + 2.9967099428176880e-002 + -4.5201331377029419e-001 + 4.6473979949951172e-001 + <_> + + <_> + + + + <_> + 8 9 2 8 -1. + <_> + 8 9 2 4 2. + 1 + -1.6702869534492493e-001 + 8.0514347553253174e-001 + -4.0616780519485474e-002 + <_> + + <_> + + + + <_> + 4 9 8 2 -1. + <_> + 4 9 4 2 2. + 1 + 1.9976759329438210e-002 + 2.0976160466670990e-001 + -7.3149591684341431e-001 + <_> + + <_> + + + + <_> + 0 0 12 8 -1. + <_> + 0 4 12 4 2. + 0 + 8.1860616803169250e-002 + -5.4268407821655273e-001 + 2.1634259819984436e-001 + <_> + + <_> + + + + <_> + 0 0 8 1 -1. + <_> + 2 0 4 1 2. + 0 + 1.2709829956293106e-002 + -2.4989350140094757e-001 + 4.7262668609619141e-001 + <_> + + <_> + + + + <_> + 0 7 12 4 -1. + <_> + 3 7 6 4 2. + 0 + -3.4979879856109619e-002 + 3.0420958995819092e-001 + -3.5224550962448120e-001 + <_> + + <_> + + + + <_> + 0 16 1 2 -1. + <_> + 0 17 1 1 2. + 0 + -1.3223739806562662e-003 + -6.9712251424789429e-001 + 1.6912660002708435e-001 + <_> + + <_> + + + + <_> + 3 16 6 4 -1. + <_> + 3 18 6 2 2. + 0 + -2.3282319307327271e-002 + 3.3972018957138062e-001 + -3.6639729142189026e-001 + <_> + + <_> + + + + <_> + 0 16 10 4 -1. + <_> + 5 16 5 4 2. + 0 + -1.5517599880695343e-001 + 7.3445862531661987e-001 + -1.8277870118618011e-001 + <_> + + <_> + + + + <_> + 8 6 4 12 -1. + <_> + 8 6 2 12 2. + 0 + -3.9222039282321930e-002 + 3.5923731327056885e-001 + -1.1233209818601608e-001 + -1.3800990581512451e+000 + 3 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 5 4 11 -1. + <_> + 2 5 2 11 2. + 0 + 6.2616936862468719e-002 + -4.8533481359481812e-001 + 6.1538851261138916e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 6 18 6 1 2. + <_> + 0 19 6 1 2. + 0 + 1.1619539931416512e-002 + -5.7667458057403564e-001 + 3.8557919859886169e-001 + <_> + + <_> + + + + <_> + 1 7 8 1 -1. + <_> + 5 7 4 1 2. + 0 + -5.7566948235034943e-003 + 2.6634719967842102e-001 + -8.2090580463409424e-001 + <_> + + <_> + + + + <_> + 0 0 12 10 -1. + <_> + 0 5 12 5 2. + 0 + 9.2315487563610077e-003 + -8.0720931291580200e-001 + 2.0323330163955688e-001 + <_> + + <_> + + + + <_> + 3 3 6 12 -1. + <_> + 3 7 6 4 3. + 0 + -3.3656319137662649e-003 + 2.0334909856319427e-001 + -7.4802142381668091e-001 + <_> + + <_> + + + + <_> + 1 0 10 1 -1. + <_> + 1 0 5 1 2. + 0 + 1.2655390310101211e-004 + -5.8880287408828735e-001 + 1.7631030082702637e-001 + <_> + + <_> + + + + <_> + 6 7 6 6 -1. + <_> + 4 9 6 2 3. + 1 + 1.0345769673585892e-001 + -4.2211589217185974e-001 + 3.3677190542221069e-001 + <_> + + <_> + + + + <_> + 7 2 1 8 -1. + <_> + 7 4 1 4 2. + 0 + -1.7050839960575104e-004 + 1.8885380029678345e-001 + -2.6626259088516235e-001 + <_> + + <_> + + + + <_> + 2 2 8 4 -1. + <_> + 2 4 8 2 2. + 0 + 1.1793050362030044e-004 + -7.1056002378463745e-001 + 2.2684849798679352e-001 + <_> + + <_> + + + + <_> + 0 7 12 7 -1. + <_> + 3 7 6 7 2. + 0 + -9.7460933029651642e-002 + 4.2451021075248718e-001 + -3.9501309394836426e-001 + <_> + + <_> + + + + <_> + 3 16 6 4 -1. + <_> + 3 18 6 2 2. + 0 + -1.7512679100036621e-002 + 3.6552980542182922e-001 + -3.5724669694900513e-001 + <_> + + <_> + + + + <_> + 10 2 1 18 -1. + <_> + 10 11 1 9 2. + 0 + 1.7156290414277464e-004 + -3.1259360909461975e-001 + 1.1446060240268707e-001 + <_> + + <_> + + + + <_> + 1 4 1 16 -1. + <_> + 1 12 1 8 2. + 0 + 8.5574887692928314e-002 + -2.0559160411357880e-001 + 8.9941620826721191e-001 + <_> + + <_> + + + + <_> + 4 0 4 18 -1. + <_> + 4 9 4 9 2. + 0 + 1.1759579647332430e-003 + -7.5939810276031494e-001 + 2.1389579772949219e-001 + <_> + + <_> + + + + <_> + 0 0 4 1 -1. + <_> + 2 0 2 1 2. + 0 + 8.8068292825482786e-005 + -6.0090541839599609e-001 + 2.5762718915939331e-001 + <_> + + <_> + + + + <_> + 7 2 1 8 -1. + <_> + 7 4 1 4 2. + 0 + 2.3003520618658513e-004 + -4.1466540098190308e-001 + 2.3084460198879242e-001 + <_> + + <_> + + + + <_> + 6 3 6 2 -1. + <_> + 8 5 2 2 3. + 1 + -3.4361891448497772e-004 + 3.2730078697204590e-001 + -7.4609941244125366e-001 + <_> + + <_> + + + + <_> + 7 11 2 6 -1. + <_> + 7 11 2 3 2. + 1 + 1.5595999546349049e-002 + -3.6050570011138916e-001 + 1.9414800405502319e-001 + <_> + + <_> + + + + <_> + 4 8 6 4 -1. + <_> + 6 10 2 4 3. + 1 + -6.5029867982957512e-005 + 3.4985640645027161e-001 + -5.5353438854217529e-001 + <_> + + <_> + + + + <_> + 2 0 8 2 -1. + <_> + 2 1 8 1 2. + 0 + 8.0799087299965322e-005 + -4.1298541426658630e-001 + 2.9194280505180359e-001 + <_> + + <_> + + + + <_> + 0 3 3 7 -1. + <_> + 1 3 1 7 3. + 0 + -1.7670560628175735e-002 + 5.6811487674713135e-001 + -3.0118390917778015e-001 + <_> + + <_> + + + + <_> + 8 1 4 8 -1. + <_> + 8 5 4 4 2. + 0 + 5.2467430941760540e-003 + -3.9970070123672485e-001 + 2.5405979156494141e-001 + <_> + + <_> + + + + <_> + 0 16 12 4 -1. + <_> + 0 17 12 2 2. + 0 + 2.7624730137176812e-004 + -4.6306419372558594e-001 + 2.7200910449028015e-001 + <_> + + <_> + + + + <_> + 8 1 3 8 -1. + <_> + 8 5 3 4 2. + 0 + -7.6283427188172936e-004 + 4.7710940241813660e-001 + -2.8456479310989380e-001 + <_> + + <_> + + + + <_> + 3 1 1 8 -1. + <_> + 3 5 1 4 2. + 0 + 5.4720909247407690e-005 + -5.9415602684020996e-001 + 2.8456559777259827e-001 + <_> + + <_> + + + + <_> + 8 0 1 8 -1. + <_> + 6 2 1 4 2. + 1 + -5.8523961342871189e-005 + 1.8699720501899719e-001 + -2.9498028755187988e-001 + <_> + + <_> + + + + <_> + 4 1 2 7 -1. + <_> + 5 1 1 7 2. + 0 + -2.3030990269035101e-004 + 3.1419369578361511e-001 + -5.2966248989105225e-001 + <_> + + <_> + + + + <_> + 9 6 3 5 -1. + <_> + 10 6 1 5 3. + 0 + 1.2743050465360284e-003 + -3.4386789798736572e-001 + 2.7126389741897583e-001 + <_> + + <_> + + + + <_> + 0 13 12 6 -1. + <_> + 0 15 12 2 3. + 0 + 1.1066290317103267e-003 + -4.5228588581085205e-001 + 2.4860590696334839e-001 + <_> + + <_> + + + + <_> + 0 0 12 10 -1. + <_> + 6 0 6 5 2. + <_> + 0 5 6 5 2. + 0 + -1.4225989580154419e-003 + 3.3848088979721069e-001 + -4.1214609146118164e-001 + <_> + + <_> + + + + <_> + 0 4 3 7 -1. + <_> + 1 4 1 7 3. + 0 + 1.8614599481225014e-002 + -1.9110870361328125e-001 + 6.4115452766418457e-001 + <_> + + <_> + + + + <_> + 2 2 8 2 -1. + <_> + 2 3 8 1 2. + 0 + 4.5832890464225784e-005 + -5.8493572473526001e-001 + 2.5314238667488098e-001 + <_> + + <_> + + + + <_> + 5 1 1 6 -1. + <_> + 5 3 1 2 3. + 0 + -9.9875287560280412e-005 + 3.6051398515701294e-001 + -5.3231191635131836e-001 + <_> + + <_> + + + + <_> + 7 5 4 7 -1. + <_> + 7 5 2 7 2. + 1 + -1.1277929879724979e-002 + 2.7766379714012146e-001 + -2.4176590144634247e-001 + <_> + + <_> + + + + <_> + 0 17 12 3 -1. + <_> + 6 17 6 3 2. + 0 + -1.5279600024223328e-001 + 8.3433318138122559e-001 + -1.8692030012607574e-001 + <_> + + <_> + + + + <_> + 2 10 8 10 -1. + <_> + 6 10 4 5 2. + <_> + 2 15 4 5 2. + 0 + -3.6294270306825638e-002 + 3.9919948577880859e-001 + -4.1119259595870972e-001 + <_> + + <_> + + + + <_> + 3 0 2 20 -1. + <_> + 3 5 2 10 2. + 0 + -4.5436818152666092e-002 + 6.8093067407608032e-001 + -1.4669400453567505e-001 + -2.0749111175537109e+000 + 4 + -1 + <_> + + + <_> + + <_> + + + + <_> + 1 6 8 12 -1. + <_> + 1 6 4 6 2. + <_> + 5 12 4 6 2. + 0 + 1.6328740119934082e-001 + -6.0435330867767334e-001 + 5.5052411556243896e-001 + <_> + + <_> + + + + <_> + 0 3 12 2 -1. + <_> + 0 4 12 1 2. + 0 + 9.7092619398608804e-005 + -9.0228801965713501e-001 + 2.6281669735908508e-001 + <_> + + <_> + + + + <_> + 1 5 7 6 -1. + <_> + 1 7 7 2 3. + 0 + -2.7205731021240354e-004 + 2.8341010212898254e-001 + -8.1372922658920288e-001 + <_> + + <_> + + + + <_> + 0 0 12 14 -1. + <_> + 0 7 12 7 2. + 0 + 1.8128680530935526e-003 + -8.3362382650375366e-001 + 2.1307690441608429e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 18 6 1 2. + <_> + 6 19 6 1 2. + 0 + -8.7052993476390839e-003 + 2.8303650021553040e-001 + -7.2392731904983521e-001 + <_> + + <_> + + + + <_> + 10 10 2 4 -1. + <_> + 10 10 2 2 2. + 1 + -5.6872398999985307e-005 + 1.3844889402389526e-001 + -5.0287842750549316e-001 + <_> + + <_> + + + + <_> + 3 4 2 1 -1. + <_> + 3 4 1 1 2. + 1 + 3.7435539066791534e-002 + -1.0564589872956276e-002 + -1.5556719970703125e+003 + <_> + + <_> + + + + <_> + 9 7 2 3 -1. + <_> + 9 8 2 1 3. + 0 + 1.5324270352721214e-002 + 1.3988590240478516e-001 + -6.1316817998886108e-001 + <_> + + <_> + + + + <_> + 0 0 10 2 -1. + <_> + 0 1 10 1 2. + 0 + 2.1410979330539703e-002 + -2.2393199801445007e-001 + 5.6233572959899902e-001 + <_> + + <_> + + + + <_> + 7 8 5 4 -1. + <_> + 7 9 5 2 2. + 0 + 1.9795040134340525e-004 + -2.3459529876708984e-001 + 1.3877849280834198e-001 + <_> + + <_> + + + + <_> + 1 7 2 3 -1. + <_> + 1 8 2 1 3. + 0 + -5.1461639814078808e-003 + -8.9666271209716797e-001 + 1.4354419708251953e-001 + <_> + + <_> + + + + <_> + 6 16 2 2 -1. + <_> + 6 16 2 1 2. + 1 + -3.3491749316453934e-002 + 8.1797057390213013e-001 + -8.1737898290157318e-002 + <_> + + <_> + + + + <_> + 6 16 2 2 -1. + <_> + 6 16 1 2 2. + 1 + -7.3674921877682209e-003 + -6.5259951353073120e-001 + 1.7211680114269257e-001 + -1.8404649496078491e+000 + 5 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 0 4 16 -1. + <_> + 2 0 2 16 2. + 0 + 7.3508180677890778e-002 + -4.6614921092987061e-001 + 5.0694358348846436e-001 + <_> + + <_> + + + + <_> + 5 0 2 3 -1. + <_> + 5 1 2 1 3. + 0 + 8.5386466234922409e-003 + -2.4482139945030212e-001 + 6.0921180248260498e-001 + <_> + + <_> + + + + <_> + 1 6 8 12 -1. + <_> + 1 6 4 6 2. + <_> + 5 12 4 6 2. + 0 + 2.2265550494194031e-001 + -2.3087610304355621e-001 + 4.4181710481643677e-001 + <_> + + <_> + + + + <_> + 6 11 6 9 -1. + <_> + 6 11 3 9 2. + 0 + 7.4994042515754700e-002 + 1.1506160348653793e-001 + -5.5417829751968384e-001 + <_> + + <_> + + + + <_> + 0 11 6 9 -1. + <_> + 3 11 3 9 2. + 0 + -1.6755120456218719e-001 + 7.4653017520904541e-001 + -1.3431079685688019e-001 + <_> + + <_> + + + + <_> + 9 11 3 5 -1. + <_> + 10 12 1 5 3. + 1 + -2.4138720706105232e-002 + -4.9592089653015137e-001 + 6.2578730285167694e-002 + <_> + + <_> + + + + <_> + 1 0 3 1 -1. + <_> + 2 1 1 1 3. + 1 + 1.1620320379734039e-002 + -1.7977459728717804e-001 + 5.6873577833175659e-001 + <_> + + <_> + + + + <_> + 9 11 3 5 -1. + <_> + 10 12 1 5 3. + 1 + 4.8821419477462769e-002 + 4.2774148285388947e-002 + -6.0440838336944580e-001 + <_> + + <_> + + + + <_> + 3 11 5 3 -1. + <_> + 2 12 5 1 3. + 1 + 3.5715501755475998e-002 + -2.0169410109519958e-001 + 5.1855558156967163e-001 + <_> + + <_> + + + + <_> + 6 6 1 3 -1. + <_> + 5 7 1 1 3. + 1 + -1.7011469230055809e-002 + -6.6163742542266846e-001 + 4.5137479901313782e-002 + <_> + + <_> + + + + <_> + 6 6 3 1 -1. + <_> + 7 7 1 1 3. + 1 + -1.6027579084038734e-002 + 5.4205197095870972e-001 + -1.8311430513858795e-001 + <_> + + <_> + + + + <_> + 7 9 3 2 -1. + <_> + 7 10 3 1 2. + 0 + 9.6712950617074966e-003 + 3.4085698425769806e-002 + -3.6544409394264221e-001 + <_> + + <_> + + + + <_> + 1 18 1 2 -1. + <_> + 1 19 1 1 2. + 0 + -1.0325650218874216e-003 + -7.0559221506118774e-001 + 1.2839829921722412e-001 + <_> + + <_> + + + + <_> + 10 18 1 2 -1. + <_> + 10 19 1 1 2. + 0 + -5.7438347721472383e-004 + 2.0413300395011902e-001 + -4.6021059155464172e-001 + <_> + + <_> + + + + <_> + 1 18 1 2 -1. + <_> + 1 19 1 1 2. + 0 + 1.2579349568113685e-003 + 1.9696569442749023e-001 + -4.9659618735313416e-001 + <_> + + <_> + + + + <_> + 7 9 3 2 -1. + <_> + 7 10 3 1 2. + 0 + -2.3272659629583359e-002 + -6.4083862304687500e-001 + -1.3145440258085728e-002 + <_> + + <_> + + + + <_> + 2 9 3 2 -1. + <_> + 2 10 3 1 2. + 0 + -4.8163738101720810e-003 + -7.4635922908782959e-001 + 1.1569319665431976e-001 + <_> + + <_> + + + + <_> + 8 8 4 3 -1. + <_> + 8 9 4 1 3. + 0 + 2.6880908990278840e-004 + -1.7020240426063538e-001 + 1.0989090055227280e-001 + <_> + + <_> + + + + <_> + 0 8 4 3 -1. + <_> + 0 9 4 1 3. + 0 + -9.1302618384361267e-003 + -8.6084252595901489e-001 + 1.0507579892873764e-001 + <_> + + <_> + + + + <_> + 0 0 12 8 -1. + <_> + 0 4 12 4 2. + 0 + 1.5290869772434235e-001 + -3.0442950129508972e-001 + 2.9691061377525330e-001 + -1.3563539981842041e+000 + 6 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 4 8 11 -1. + <_> + 2 4 4 11 2. + 0 + 1.0870260000228882e-001 + -3.9208391308784485e-001 + 4.2441639304161072e-001 + <_> + + <_> + + + + <_> + 9 0 1 3 -1. + <_> + 9 1 1 1 3. + 0 + -8.5436011431738734e-005 + 1.1648490279912949e-001 + -1.2261509895324707e-001 + <_> + + <_> + + + + <_> + 1 0 2 3 -1. + <_> + 1 1 2 1 3. + 0 + 8.7897274643182755e-003 + -2.2223709523677826e-001 + 5.8239942789077759e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 6 18 6 1 2. + <_> + 0 19 6 1 2. + 0 + 1.9092390313744545e-002 + -2.8222650289535522e-001 + 3.4780630469322205e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 8 5 2 6 3. + 1 + -1.4692190103232861e-002 + 2.4436180293560028e-001 + -4.4442260265350342e-001 + <_> + + <_> + + + + <_> + 10 12 2 6 -1. + <_> + 10 12 1 6 2. + 1 + 1.7424240708351135e-002 + 3.9642699062824249e-002 + -5.0866502523422241e-001 + <_> + + <_> + + + + <_> + 2 12 6 2 -1. + <_> + 2 12 6 1 2. + 1 + 6.9210886955261230e-002 + -1.5061080455780029e-001 + 5.4918211698532104e-001 + <_> + + <_> + + + + <_> + 4 14 8 5 -1. + <_> + 4 14 4 5 2. + 0 + 1.1516460031270981e-001 + 4.7058542259037495e-003 + -6.0872167348861694e-001 + <_> + + <_> + + + + <_> + 0 15 8 3 -1. + <_> + 4 15 4 3 2. + 0 + -9.0783968567848206e-002 + 7.6661890745162964e-001 + -1.1532770097255707e-001 + <_> + + <_> + + + + <_> + 6 7 6 6 -1. + <_> + 8 9 2 6 3. + 1 + 9.3459866940975189e-002 + 7.7324211597442627e-002 + -7.2869849205017090e-001 + <_> + + <_> + + + + <_> + 6 7 6 6 -1. + <_> + 4 9 6 2 3. + 1 + 1.4063410460948944e-001 + -3.0280780792236328e-001 + 2.9996991157531738e-001 + <_> + + <_> + + + + <_> + 5 4 2 4 -1. + <_> + 5 5 2 2 2. + 0 + 7.5702848844230175e-003 + -2.5590381026268005e-001 + 3.4416630864143372e-001 + <_> + + <_> + + + + <_> + 0 8 3 3 -1. + <_> + 0 9 3 1 3. + 0 + 8.1542655825614929e-003 + 1.2018810212612152e-001 + -8.5254168510437012e-001 + <_> + + <_> + + + + <_> + 8 15 2 3 -1. + <_> + 7 16 2 1 3. + 1 + 8.7357666343450546e-003 + -1.2177339941263199e-001 + 8.2226127386093140e-002 + <_> + + <_> + + + + <_> + 4 15 3 2 -1. + <_> + 5 16 1 2 3. + 1 + -6.9444780237972736e-003 + -6.1111962795257568e-001 + 1.3486449420452118e-001 + <_> + + <_> + + + + <_> + 9 14 3 3 -1. + <_> + 8 15 3 1 3. + 1 + -4.3000229634344578e-003 + -3.4730020165443420e-001 + 4.4554490596055984e-002 + <_> + + <_> + + + + <_> + 3 12 5 3 -1. + <_> + 2 13 5 1 3. + 1 + 4.0720161050558090e-002 + -1.2618629634380341e-001 + 6.0286152362823486e-001 + <_> + + <_> + + + + <_> + 0 0 12 2 -1. + <_> + 3 0 6 2 2. + 0 + -1.0009969584643841e-002 + -4.5014089345932007e-001 + 1.8092009425163269e-001 + <_> + + <_> + + + + <_> + 0 9 3 4 -1. + <_> + 0 10 3 2 2. + 0 + 1.1742020025849342e-002 + 8.1721372902393341e-002 + -8.0739098787307739e-001 + <_> + + <_> + + + + <_> + 8 10 4 6 -1. + <_> + 8 12 4 2 3. + 0 + -9.7789859864860773e-004 + 6.6041916608810425e-002 + -1.4142000675201416e-001 + <_> + + <_> + + + + <_> + 0 10 4 6 -1. + <_> + 0 12 4 2 3. + 0 + 3.4487970173358917e-002 + 1.0488150268793106e-001 + -7.1635431051254272e-001 + <_> + + <_> + + + + <_> + 6 5 2 3 -1. + <_> + 5 6 2 1 3. + 1 + -2.4215620011091232e-002 + -5.9454482793807983e-001 + 1.2400969862937927e-002 + <_> + + <_> + + + + <_> + 6 5 3 2 -1. + <_> + 7 6 1 2 3. + 1 + -3.7082370370626450e-002 + 6.5830427408218384e-001 + -1.2158200144767761e-001 + <_> + + <_> + + + + <_> + 2 0 8 1 -1. + <_> + 2 0 4 1 2. + 0 + -4.3632909655570984e-003 + -6.5290719270706177e-001 + 1.2228529900312424e-001 + <_> + + <_> + + + + <_> + 0 5 3 2 -1. + <_> + 0 6 3 1 2. + 0 + -4.1692638769745827e-003 + -7.3107779026031494e-001 + 7.7946297824382782e-002 + <_> + + <_> + + + + <_> + 8 14 2 3 -1. + <_> + 7 15 2 1 3. + 1 + 6.0636870563030243e-002 + -1.3061979785561562e-002 + -8.0408149957656860e-001 + <_> + + <_> + + + + <_> + 4 14 3 2 -1. + <_> + 5 15 1 2 3. + 1 + 1.5371589921414852e-002 + 7.9872779548168182e-002 + -8.5363340377807617e-001 + -1.4800649881362915e+000 + 7 + -1 + <_> + + + <_> + + <_> + + + + <_> + 3 2 3 8 -1. + <_> + 3 4 3 4 2. + 0 + 1.5033720061182976e-002 + -5.3333657979965210e-001 + 3.4096190333366394e-001 + <_> + + <_> + + + + <_> + 3 7 8 12 -1. + <_> + 7 7 4 6 2. + <_> + 3 13 4 6 2. + 0 + -8.9624240994453430e-002 + 1.8991500139236450e-001 + -2.1448349952697754e-001 + <_> + + <_> + + + + <_> + 4 6 4 3 -1. + <_> + 4 7 4 1 3. + 0 + -5.1495251245796680e-003 + 3.6764401197433472e-001 + -3.1621339917182922e-001 + <_> + + <_> + + + + <_> + 3 11 6 8 -1. + <_> + 3 13 6 4 2. + 0 + 5.6887358427047729e-002 + -2.7120190858840942e-001 + 3.4590399265289307e-001 + <_> + + <_> + + + + <_> + 6 12 2 6 -1. + <_> + 6 12 2 3 2. + 1 + -1.2673810124397278e-001 + 8.4647309780120850e-001 + -6.7630723118782043e-002 + <_> + + <_> + + + + <_> + 4 3 8 16 -1. + <_> + 8 3 4 8 2. + <_> + 4 11 4 8 2. + 0 + -1.0681120306253433e-001 + -2.8982621431350708e-001 + 8.3181828260421753e-002 + <_> + + <_> + + + + <_> + 0 2 8 16 -1. + <_> + 0 2 4 8 2. + <_> + 4 10 4 8 2. + 0 + 1.7475779354572296e-001 + -3.5948398709297180e-001 + 3.1073129177093506e-001 + <_> + + <_> + + + + <_> + 9 0 3 2 -1. + <_> + 9 1 3 1 2. + 0 + -2.4629090912640095e-003 + -6.7824071645736694e-001 + 1.1908339709043503e-001 + <_> + + <_> + + + + <_> + 0 0 3 2 -1. + <_> + 0 1 3 1 2. + 0 + 6.6053359769284725e-003 + -2.4560730159282684e-001 + 3.7791371345520020e-001 + <_> + + <_> + + + + <_> + 9 6 1 2 -1. + <_> + 9 6 1 1 2. + 1 + 1.0148379806196317e-004 + -1.0097169876098633e-001 + 8.2711093127727509e-002 + <_> + + <_> + + + + <_> + 0 1 12 2 -1. + <_> + 4 1 4 2 3. + 0 + -1.8523789942264557e-002 + -4.4592261314392090e-001 + 1.6946080327033997e-001 + <_> + + <_> + + + + <_> + 9 4 3 5 -1. + <_> + 10 4 1 5 3. + 0 + 3.6602010950446129e-003 + -1.0477670282125473e-001 + 9.4992779195308685e-002 + <_> + + <_> + + + + <_> + 0 3 4 6 -1. + <_> + 1 3 2 6 2. + 0 + -1.0257829912006855e-002 + 4.3351659178733826e-001 + -1.6978879272937775e-001 + <_> + + <_> + + + + <_> + 11 17 1 2 -1. + <_> + 11 18 1 1 2. + 0 + -9.8685777629725635e-005 + 1.7843760550022125e-001 + -2.6428279280662537e-001 + <_> + + <_> + + + + <_> + 0 17 1 2 -1. + <_> + 0 18 1 1 2. + 0 + -1.2446290347725153e-003 + -7.2253531217575073e-001 + 1.0615690052509308e-001 + <_> + + <_> + + + + <_> + 11 17 1 3 -1. + <_> + 11 18 1 1 3. + 0 + 1.1974680091952905e-004 + -3.0318620800971985e-001 + 1.4623160660266876e-001 + <_> + + <_> + + + + <_> + 0 17 1 3 -1. + <_> + 0 18 1 1 3. + 0 + 1.2079760199412704e-003 + 1.3531659543514252e-001 + -5.0457692146301270e-001 + <_> + + <_> + + + + <_> + 0 4 12 12 -1. + <_> + 0 8 12 4 3. + 0 + -1.9425910711288452e-001 + -7.1733701229095459e-001 + 8.0573573708534241e-002 + <_> + + <_> + + + + <_> + 1 5 3 6 -1. + <_> + 2 5 1 6 3. + 0 + 1.8599320203065872e-002 + -1.6972489655017853e-001 + 4.2669999599456787e-001 + <_> + + <_> + + + + <_> + 6 4 4 3 -1. + <_> + 5 5 4 1 3. + 1 + 3.0704800039529800e-002 + 3.2838109880685806e-002 + -7.2923952341079712e-001 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 7 5 1 4 3. + 1 + 2.1680949255824089e-002 + -1.6750890016555786e-001 + 4.4789049029350281e-001 + <_> + + <_> + + + + <_> + 10 4 2 3 -1. + <_> + 10 5 2 1 3. + 0 + 5.5604660883545876e-003 + 9.6391409635543823e-002 + -6.6830247640609741e-001 + <_> + + <_> + + + + <_> + 0 4 2 3 -1. + <_> + 0 5 2 1 3. + 0 + -5.6784078478813171e-003 + -8.2064878940582275e-001 + 6.2949016690254211e-002 + <_> + + <_> + + + + <_> + 9 10 3 3 -1. + <_> + 8 11 3 1 3. + 1 + -3.0219739302992821e-002 + 3.3288109302520752e-001 + -8.1444039940834045e-002 + <_> + + <_> + + + + <_> + 6 10 6 3 -1. + <_> + 6 10 3 3 2. + 1 + 2.4341929703950882e-002 + 9.3220241367816925e-002 + -6.9502758979797363e-001 + -1.3590339422225952e+000 + 8 + -1 + <_> + + + <_> + + <_> + + + + <_> + 3 2 4 2 -1. + <_> + 3 2 2 1 2. + <_> + 5 3 2 1 2. + 0 + -3.9169401861727238e-003 + 4.5325928926467896e-001 + -3.0284589529037476e-001 + <_> + + <_> + + + + <_> + 6 8 6 6 -1. + <_> + 8 10 2 6 3. + 1 + 1.0800900310277939e-001 + 3.6738589406013489e-002 + -7.2782218456268311e-001 + <_> + + <_> + + + + <_> + 6 8 6 6 -1. + <_> + 4 10 6 2 3. + 1 + 1.5356090664863586e-001 + -3.8900190591812134e-001 + 3.1287321448326111e-001 + <_> + + <_> + + + + <_> + 6 4 1 6 -1. + <_> + 4 6 1 2 3. + 1 + 8.7726805359125137e-003 + -1.5705280005931854e-001 + 8.2666940987110138e-002 + <_> + + <_> + + + + <_> + 6 4 6 1 -1. + <_> + 8 6 2 1 3. + 1 + -1.0571720078587532e-002 + 2.4971100687980652e-001 + -4.7014111280441284e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 5 6 3 1 3. + 1 + 2.7240550145506859e-002 + 6.0097638517618179e-002 + -6.6213667392730713e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 7 6 1 3 3. + 1 + -3.6633450537919998e-002 + 5.1044297218322754e-001 + -1.7766149342060089e-001 + <_> + + <_> + + + + <_> + 2 16 10 4 -1. + <_> + 2 16 5 4 2. + 0 + 1.3806289434432983e-001 + -4.0644191205501556e-002 + 7.8849452733993530e-001 + <_> + + <_> + + + + <_> + 0 0 12 10 -1. + <_> + 0 5 12 5 2. + 0 + 9.4720393419265747e-002 + -4.3654170632362366e-001 + 1.9054649770259857e-001 + <_> + + <_> + + + + <_> + 10 0 2 2 -1. + <_> + 10 0 1 2 2. + 0 + -3.3387150615453720e-003 + -6.8457669019699097e-001 + 9.6802540123462677e-002 + <_> + + <_> + + + + <_> + 0 0 2 2 -1. + <_> + 1 0 1 2 2. + 0 + 1.1899480159627274e-004 + -3.5843661427497864e-001 + 2.2279889881610870e-001 + <_> + + <_> + + + + <_> + 7 15 2 2 -1. + <_> + 7 15 2 1 2. + 1 + 2.9007149860262871e-003 + -1.5845039486885071e-001 + 6.6679857671260834e-002 + <_> + + <_> + + + + <_> + 0 8 2 6 -1. + <_> + 0 8 1 3 2. + <_> + 1 11 1 3 2. + 0 + 1.2376639991998672e-002 + -1.4206279814243317e-001 + 4.9320921301841736e-001 + <_> + + <_> + + + + <_> + 10 11 2 4 -1. + <_> + 9 12 2 2 2. + 1 + 6.0215988196432590e-003 + -1.4971609413623810e-001 + 2.1797719597816467e-001 + <_> + + <_> + + + + <_> + 0 16 10 4 -1. + <_> + 5 16 5 4 2. + 0 + -1.6887940466403961e-001 + 7.1833407878875732e-001 + -1.1091569811105728e-001 + <_> + + <_> + + + + <_> + 1 18 10 2 -1. + <_> + 1 19 10 1 2. + 0 + -7.4033271521329880e-003 + 2.2573550045490265e-001 + -3.2993030548095703e-001 + <_> + + <_> + + + + <_> + 0 9 2 4 -1. + <_> + 0 9 1 2 2. + <_> + 1 11 1 2 2. + 0 + -6.5029351972043514e-003 + 4.7018998861312866e-001 + -1.5201370418071747e-001 + <_> + + <_> + + + + <_> + 9 12 3 3 -1. + <_> + 8 13 3 1 3. + 1 + 1.7706790240481496e-003 + -1.4644999802112579e-001 + 9.4745017588138580e-002 + <_> + + <_> + + + + <_> + 3 12 3 3 -1. + <_> + 4 13 1 3 3. + 1 + 1.7085459083318710e-002 + 8.5357367992401123e-002 + -8.2599818706512451e-001 + <_> + + <_> + + + + <_> + 6 4 4 3 -1. + <_> + 5 5 4 1 3. + 1 + -5.3032718598842621e-002 + -6.5861982107162476e-001 + -1.3727230252698064e-003 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 7 5 1 4 3. + 1 + 2.7725089341402054e-002 + -1.4935420453548431e-001 + 4.4009518623352051e-001 + <_> + + <_> + + + + <_> + 9 12 3 3 -1. + <_> + 8 13 3 1 3. + 1 + 5.8685488998889923e-002 + 7.8679984435439110e-003 + -4.4109138846397400e-001 + <_> + + <_> + + + + <_> + 3 12 3 3 -1. + <_> + 4 13 1 3 3. + 1 + -1.0465820319950581e-002 + -5.8385229110717773e-001 + 1.0567150264978409e-001 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 5 5 3 2 2. + 1 + -4.4063638895750046e-002 + -5.9246909618377686e-001 + 5.7151052169501781e-003 + <_> + + <_> + + + + <_> + 6 4 4 3 -1. + <_> + 7 5 2 3 2. + 1 + -1.1932180263102055e-002 + 2.3818169534206390e-001 + -2.8293299674987793e-001 + <_> + + <_> + + + + <_> + 9 18 2 2 -1. + <_> + 9 19 2 1 2. + 0 + -1.2644910020753741e-003 + 1.0124749690294266e-001 + -3.3939999341964722e-001 + <_> + + <_> + + + + <_> + 1 18 2 2 -1. + <_> + 1 19 2 1 2. + 0 + -1.8404610455036163e-003 + -6.7492902278900146e-001 + 9.5524467527866364e-002 + <_> + + <_> + + + + <_> + 10 6 2 3 -1. + <_> + 10 7 2 1 3. + 0 + -7.9289656132459641e-003 + -6.7770427465438843e-001 + 3.4221731126308441e-002 + <_> + + <_> + + + + <_> + 0 1 2 4 -1. + <_> + 0 1 1 2 2. + <_> + 1 3 1 2 2. + 0 + 5.7004559785127640e-003 + -1.3198739290237427e-001 + 4.2710319161415100e-001 + <_> + + <_> + + + + <_> + 6 0 2 3 -1. + <_> + 6 0 1 3 2. + 0 + 1.8237680196762085e-002 + 3.0692299827933311e-002 + -8.6847299337387085e-001 + <_> + + <_> + + + + <_> + 2 13 2 2 -1. + <_> + 2 13 1 1 2. + <_> + 3 14 1 1 2. + 0 + 3.2086670398712158e-003 + -1.3335919380187988e-001 + 4.3883138895034790e-001 + <_> + + <_> + + + + <_> + 10 6 2 3 -1. + <_> + 10 7 2 1 3. + 0 + 1.2446580454707146e-002 + 2.9371360316872597e-002 + -7.8926819562911987e-001 + -1.4373550415039062e+000 + 9 + -1 + <_> + + + <_> + + <_> + + + + <_> + 2 1 4 3 -1. + <_> + 2 2 4 1 3. + 0 + -1.2674730271100998e-002 + 5.0484418869018555e-001 + -2.5669950246810913e-001 + <_> + + <_> + + + + <_> + 7 4 3 3 -1. + <_> + 6 5 3 1 3. + 1 + 1.1808129958808422e-002 + 6.3001699745655060e-002 + -4.0641498565673828e-001 + <_> + + <_> + + + + <_> + 5 4 2 2 -1. + <_> + 5 5 2 1 2. + 0 + 2.5127220433205366e-003 + -3.2253271341323853e-001 + 3.6614939570426941e-001 + <_> + + <_> + + + + <_> + 10 10 2 6 -1. + <_> + 10 10 1 6 2. + 0 + -3.5469220019876957e-003 + 1.9579920172691345e-001 + -1.5416850149631500e-001 + <_> + + <_> + + + + <_> + 0 12 4 4 -1. + <_> + 2 12 2 4 2. + 0 + 3.9148680865764618e-002 + -2.5791868567466736e-001 + 3.3852350711822510e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + 1.3151739537715912e-001 + 2.7472509071230888e-002 + -5.5891007184982300e-001 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + -1.6689460724592209e-002 + 1.4658740162849426e-001 + -5.2727991342544556e-001 + <_> + + <_> + + + + <_> + 9 12 2 3 -1. + <_> + 8 13 2 1 3. + 1 + 6.4351540058851242e-003 + -1.2016840279102325e-001 + 1.8379710614681244e-001 + <_> + + <_> + + + + <_> + 6 12 1 6 -1. + <_> + 6 12 1 3 2. + 1 + -6.3846178352832794e-002 + 7.5390338897705078e-001 + -1.0603629797697067e-001 + <_> + + <_> + + + + <_> + 5 16 3 2 -1. + <_> + 5 17 3 1 2. + 0 + -4.6943090856075287e-003 + 2.0730340480804443e-001 + -1.6408169269561768e-001 + <_> + + <_> + + + + <_> + 3 12 3 2 -1. + <_> + 4 13 1 2 3. + 1 + 1.1263520456850529e-002 + 1.0285060107707977e-001 + -7.2724348306655884e-001 + <_> + + <_> + + + + <_> + 11 0 1 2 -1. + <_> + 11 0 1 1 2. + 1 + 1.0440419428050518e-003 + 1.3197229802608490e-001 + -6.4476031064987183e-001 + <_> + + <_> + + + + <_> + 0 0 4 11 -1. + <_> + 2 0 2 11 2. + 0 + 2.9053710401058197e-002 + -3.2099440693855286e-001 + 1.9499249756336212e-001 + <_> + + <_> + + + + <_> + 10 11 2 3 -1. + <_> + 9 12 2 1 3. + 1 + 1.2985640205442905e-002 + -6.2498811632394791e-002 + 2.6551690697669983e-001 + <_> + + <_> + + + + <_> + 2 11 3 2 -1. + <_> + 3 12 1 2 3. + 1 + 1.4938330277800560e-002 + 8.0150052905082703e-002 + -7.6676148176193237e-001 + <_> + + <_> + + + + <_> + 9 11 3 5 -1. + <_> + 10 12 1 5 3. + 1 + -3.4180350601673126e-002 + -5.1320338249206543e-001 + -3.6074419040232897e-003 + <_> + + <_> + + + + <_> + 3 11 5 3 -1. + <_> + 2 12 5 1 3. + 1 + 4.3761111795902252e-002 + -1.4384460449218750e-001 + 4.2616510391235352e-001 + <_> + + <_> + + + + <_> + 8 12 4 2 -1. + <_> + 8 13 4 1 2. + 0 + -1.1876770295202732e-003 + 1.4837500452995300e-001 + -5.0197489559650421e-002 + <_> + + <_> + + + + <_> + 0 12 4 2 -1. + <_> + 0 13 4 1 2. + 0 + -1.3196719810366631e-002 + -7.6232409477233887e-001 + 7.9683482646942139e-002 + <_> + + <_> + + + + <_> + 8 13 2 2 -1. + <_> + 9 13 1 1 2. + <_> + 8 14 1 1 2. + 0 + -1.4940570108592510e-003 + 2.2585479915142059e-001 + -1.0884329676628113e-001 + <_> + + <_> + + + + <_> + 0 7 5 3 -1. + <_> + 0 8 5 1 3. + 0 + 9.9800303578376770e-003 + 7.7047176659107208e-002 + -8.1608718633651733e-001 + <_> + + <_> + + + + <_> + 8 13 2 2 -1. + <_> + 9 13 1 1 2. + <_> + 8 14 1 1 2. + 0 + 1.3630810426548123e-003 + -1.0334450006484985e-001 + 2.0994339883327484e-001 + <_> + + <_> + + + + <_> + 2 13 2 2 -1. + <_> + 2 13 1 1 2. + <_> + 3 14 1 1 2. + 0 + -2.6497698854655027e-003 + 4.8666700720787048e-001 + -1.2183590233325958e-001 + <_> + + <_> + + + + <_> + 7 8 5 4 -1. + <_> + 7 9 5 2 2. + 0 + 2.9017059132456779e-002 + 3.0331170186400414e-002 + -5.4417270421981812e-001 + <_> + + <_> + + + + <_> + 0 5 2 8 -1. + <_> + 0 5 1 4 2. + <_> + 1 9 1 4 2. + 0 + 1.7291629686951637e-002 + -1.3578090071678162e-001 + 4.4251319766044617e-001 + <_> + + <_> + + + + <_> + 8 8 3 4 -1. + <_> + 8 9 3 2 2. + 0 + 1.9144080579280853e-003 + -8.2041606307029724e-002 + 1.1203309893608093e-001 + <_> + + <_> + + + + <_> + 1 8 3 4 -1. + <_> + 1 9 3 2 2. + 0 + 9.2138089239597321e-003 + 9.5674678683280945e-002 + -7.1387839317321777e-001 + <_> + + <_> + + + + <_> + 0 0 12 16 -1. + <_> + 0 8 12 8 2. + 0 + 1.9401769340038300e-001 + -3.3527439832687378e-001 + 1.6470989584922791e-001 + <_> + + <_> + + + + <_> + 0 0 4 2 -1. + <_> + 0 0 2 1 2. + <_> + 2 1 2 1 2. + 0 + -8.9092198759317398e-003 + 4.5958560705184937e-001 + -1.3180640339851379e-001 + <_> + + <_> + + + + <_> + 7 0 3 3 -1. + <_> + 8 0 1 3 3. + 0 + -1.6158509999513626e-002 + -8.8425397872924805e-001 + 3.6370448768138885e-002 + <_> + + <_> + + + + <_> + 3 12 5 3 -1. + <_> + 2 13 5 1 3. + 1 + -4.3315120041370392e-002 + 3.5693758726119995e-001 + -1.4853119850158691e-001 + <_> + + <_> + + + + <_> + 0 8 12 4 -1. + <_> + 3 8 6 4 2. + 0 + -6.0759939253330231e-002 + 3.1768760085105896e-001 + -1.8056009709835052e-001 + <_> + + <_> + + + + <_> + 2 12 2 2 -1. + <_> + 2 12 1 1 2. + <_> + 3 13 1 1 2. + 0 + -2.8645009733736515e-003 + 5.3059607744216919e-001 + -1.1261919885873795e-001 + <_> + + <_> + + + + <_> + 10 15 2 3 -1. + <_> + 10 16 2 1 3. + 0 + 1.1360960081219673e-002 + 3.5099871456623077e-002 + -4.7815018892288208e-001 + -1.3898090124130249e+000 + 10 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 0 8 1 -1. + <_> + 2 0 4 1 2. + 0 + 1.3970459811389446e-002 + -3.0530300736427307e-001 + 4.1125300526618958e-001 + <_> + + <_> + + + + <_> + 3 6 8 12 -1. + <_> + 7 6 4 6 2. + <_> + 3 12 4 6 2. + 0 + -1.1679069697856903e-001 + 1.4812999963760376e-001 + -7.0709809660911560e-002 + <_> + + <_> + + + + <_> + 5 4 3 3 -1. + <_> + 6 5 1 3 3. + 1 + 1.6397690400481224e-002 + -3.0543169379234314e-001 + 3.0162781476974487e-001 + <_> + + <_> + + + + <_> + 4 6 8 12 -1. + <_> + 8 6 4 6 2. + <_> + 4 12 4 6 2. + 0 + -2.0286109298467636e-002 + -2.3618179559707642e-001 + 1.2187310308218002e-001 + <_> + + <_> + + + + <_> + 0 5 10 14 -1. + <_> + 0 5 5 7 2. + <_> + 5 12 5 7 2. + 0 + 3.3962181210517883e-001 + -2.3415289819240570e-001 + 3.7955328822135925e-001 + <_> + + <_> + + + + <_> + 1 2 10 4 -1. + <_> + 1 4 10 2 2. + 0 + 8.0632884055376053e-003 + -5.6521987915039063e-001 + 1.2719720602035522e-001 + <_> + + <_> + + + + <_> + 0 15 1 2 -1. + <_> + 0 16 1 1 2. + 0 + -1.4234139816835523e-003 + -5.8998572826385498e-001 + 1.1668500304222107e-001 + <_> + + <_> + + + + <_> + 6 0 4 3 -1. + <_> + 6 1 4 1 3. + 0 + 3.9983680471777916e-003 + -9.9398262798786163e-002 + 1.2795600295066833e-001 + <_> + + <_> + + + + <_> + 5 14 2 2 -1. + <_> + 5 14 1 2 2. + 1 + -9.4549506902694702e-003 + -5.6156420707702637e-001 + 9.9381953477859497e-002 + <_> + + <_> + + + + <_> + 0 9 12 1 -1. + <_> + 0 9 6 1 2. + 0 + 3.7270709872245789e-002 + 8.4691196680068970e-002 + -6.5302717685699463e-001 + <_> + + <_> + + + + <_> + 0 5 3 3 -1. + <_> + 0 6 3 1 3. + 0 + 8.1806071102619171e-003 + 6.4047202467918396e-002 + -7.3235487937927246e-001 + <_> + + <_> + + + + <_> + 8 12 4 3 -1. + <_> + 7 13 4 1 3. + 1 + 6.7418292164802551e-002 + 4.3028471991419792e-003 + -6.2574678659439087e-001 + <_> + + <_> + + + + <_> + 4 12 3 4 -1. + <_> + 5 13 1 4 3. + 1 + 1.8985599279403687e-002 + 7.0422857999801636e-002 + -7.7566891908645630e-001 + <_> + + <_> + + + + <_> + 7 0 2 3 -1. + <_> + 7 1 2 1 3. + 0 + -3.0685300589539111e-004 + 6.0799881815910339e-002 + -7.3534972965717316e-002 + <_> + + <_> + + + + <_> + 3 0 2 3 -1. + <_> + 3 1 2 1 3. + 0 + 1.0786009952425957e-002 + -1.2505950033664703e-001 + 4.8208248615264893e-001 + <_> + + <_> + + + + <_> + 10 0 2 2 -1. + <_> + 10 0 1 2 2. + 1 + 6.9674388505518436e-003 + 8.3264723420143127e-002 + -6.9356048107147217e-001 + <_> + + <_> + + + + <_> + 2 0 2 2 -1. + <_> + 2 0 2 1 2. + 1 + 1.2767270207405090e-002 + 6.4788013696670532e-002 + -7.0968890190124512e-001 + <_> + + <_> + + + + <_> + 10 0 2 1 -1. + <_> + 10 0 1 1 2. + 1 + -1.4131699688732624e-002 + -7.5622642040252686e-001 + 2.0618569105863571e-002 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 18 6 1 2. + <_> + 6 19 6 1 2. + 0 + -1.5918679535388947e-002 + 1.9603510200977325e-001 + -2.7034899592399597e-001 + <_> + + <_> + + + + <_> + 2 7 8 10 -1. + <_> + 2 12 8 5 2. + 0 + 9.9455211311578751e-003 + -4.3780571222305298e-001 + 1.1859329789876938e-001 + <_> + + <_> + + + + <_> + 0 9 2 10 -1. + <_> + 1 9 1 10 2. + 0 + 1.5286459587514400e-002 + -1.9513919949531555e-001 + 2.6915138959884644e-001 + <_> + + <_> + + + + <_> + 9 9 3 2 -1. + <_> + 10 9 1 2 3. + 0 + 5.9025101363658905e-003 + -1.6288129985332489e-001 + 3.6743709444999695e-001 + <_> + + <_> + + + + <_> + 0 9 3 2 -1. + <_> + 1 9 1 2 3. + 0 + -6.9729480892419815e-003 + 4.6202778816223145e-001 + -1.5376560389995575e-001 + <_> + + <_> + + + + <_> + 8 6 4 3 -1. + <_> + 8 7 4 1 3. + 0 + -1.9449390470981598e-002 + -5.3632599115371704e-001 + 3.1576488167047501e-002 + <_> + + <_> + + + + <_> + 0 5 2 3 -1. + <_> + 0 6 2 1 3. + 0 + -4.7259521670639515e-003 + -7.3517972230911255e-001 + 7.3678806424140930e-002 + <_> + + <_> + + + + <_> + 8 8 3 3 -1. + <_> + 9 8 1 3 3. + 0 + -8.5517195984721184e-003 + 3.5986369848251343e-001 + -1.2420760095119476e-001 + <_> + + <_> + + + + <_> + 0 8 4 12 -1. + <_> + 2 8 2 12 2. + 0 + -9.8964512348175049e-002 + 6.2507808208465576e-001 + -8.6647883057594299e-002 + <_> + + <_> + + + + <_> + 6 7 1 3 -1. + <_> + 5 8 1 1 3. + 1 + -1.7731260508298874e-002 + -5.7925891876220703e-001 + 2.5198649615049362e-002 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 7 5 1 3 3. + 1 + -2.9190430417656898e-002 + 5.7298821210861206e-001 + -1.0151000320911407e-001 + <_> + + <_> + + + + <_> + 10 0 2 1 -1. + <_> + 10 0 1 1 2. + 1 + 5.4621109738945961e-003 + 4.4515479356050491e-002 + -6.6922581195831299e-001 + <_> + + <_> + + + + <_> + 2 0 1 2 -1. + <_> + 2 0 1 1 2. + 1 + -6.8695018999278545e-003 + -5.8384990692138672e-001 + 8.7239846587181091e-002 + <_> + + <_> + + + + <_> + 9 10 3 1 -1. + <_> + 10 10 1 1 3. + 0 + -1.7049070447683334e-003 + 2.2694580256938934e-001 + -8.1620521843433380e-002 + <_> + + <_> + + + + <_> + 0 10 3 1 -1. + <_> + 1 10 1 1 3. + 0 + 5.8957659639418125e-003 + -1.1778759956359863e-001 + 4.2724978923797607e-001 + <_> + + <_> + + + + <_> + 10 12 2 3 -1. + <_> + 9 13 2 1 3. + 1 + 8.5842777043581009e-003 + -5.4629139602184296e-002 + 1.0813979804515839e-001 + <_> + + <_> + + + + <_> + 2 12 3 2 -1. + <_> + 3 13 1 2 3. + 1 + 1.2934260070323944e-002 + 7.0849359035491943e-002 + -7.3857682943344116e-001 + <_> + + <_> + + + + <_> + 9 10 3 3 -1. + <_> + 9 11 3 1 3. + 0 + 1.9973270595073700e-002 + 1.6626559663563967e-003 + -7.6631492376327515e-001 + <_> + + <_> + + + + <_> + 0 10 3 3 -1. + <_> + 0 11 3 1 3. + 0 + 5.5011189542710781e-003 + 8.9468717575073242e-002 + -5.3985279798507690e-001 + -1.3544019460678101e+000 + 11 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 0 3 2 -1. + <_> + 0 1 3 1 2. + 0 + 7.9501233994960785e-003 + -2.7952459454536438e-001 + 4.3506631255149841e-001 + <_> + + <_> + + + + <_> + 3 0 6 2 -1. + <_> + 6 0 3 1 2. + <_> + 3 1 3 1 2. + 0 + -1.5085919760167599e-002 + 5.9209001064300537e-001 + -1.6481369733810425e-001 + <_> + + <_> + + + + <_> + 1 7 8 12 -1. + <_> + 1 7 4 6 2. + <_> + 5 13 4 6 2. + 0 + 1.9475109875202179e-001 + -3.1889539957046509e-001 + 2.8196701407432556e-001 + <_> + + <_> + + + + <_> + 7 6 4 1 -1. + <_> + 7 6 2 1 2. + 0 + -2.4689928977750242e-004 + 9.6763692796230316e-002 + -1.8406489491462708e-001 + <_> + + <_> + + + + <_> + 1 0 10 2 -1. + <_> + 6 0 5 2 2. + 0 + 5.2499058656394482e-003 + 1.5704880654811859e-001 + -5.2710950374603271e-001 + <_> + + <_> + + + + <_> + 10 2 1 4 -1. + <_> + 10 2 1 2 2. + 1 + -1.2732569302897900e-004 + 5.3218118846416473e-002 + -1.6152860224246979e-001 + <_> + + <_> + + + + <_> + 2 2 4 1 -1. + <_> + 2 2 2 1 2. + 1 + -6.5984549000859261e-003 + 2.1844869852066040e-001 + -3.7529769539833069e-001 + <_> + + <_> + + + + <_> + 4 15 8 4 -1. + <_> + 4 15 4 4 2. + 0 + -1.2836559675633907e-002 + 6.1008229851722717e-002 + -1.1862020194530487e-001 + <_> + + <_> + + + + <_> + 0 14 8 5 -1. + <_> + 4 14 4 5 2. + 0 + -1.4707820117473602e-001 + 7.9065358638763428e-001 + -9.4447426497936249e-002 + <_> + + <_> + + + + <_> + 8 12 4 5 -1. + <_> + 8 12 2 5 2. + 0 + 4.8533070832490921e-002 + 4.9431171268224716e-002 + -5.9807902574539185e-001 + <_> + + <_> + + + + <_> + 0 10 4 7 -1. + <_> + 2 10 2 7 2. + 0 + 4.1398849338293076e-002 + -3.1118649244308472e-001 + 2.4850000441074371e-001 + <_> + + <_> + + + + <_> + 5 0 3 3 -1. + <_> + 5 1 3 1 3. + 0 + 5.9322831220924854e-003 + -1.9105120003223419e-001 + 2.6189088821411133e-001 + <_> + + <_> + + + + <_> + 6 8 3 1 -1. + <_> + 7 9 1 1 3. + 1 + 6.1201062053442001e-003 + -1.4400300383567810e-001 + 3.8592028617858887e-001 + <_> + + <_> + + + + <_> + 9 6 3 3 -1. + <_> + 9 7 3 1 3. + 0 + -1.2118129990994930e-002 + -5.7840502262115479e-001 + 3.1328909099102020e-002 + <_> + + <_> + + + + <_> + 0 6 3 3 -1. + <_> + 0 7 3 1 3. + 0 + 7.5321048498153687e-003 + 7.6200783252716064e-002 + -7.1263229846954346e-001 + <_> + + <_> + + + + <_> + 8 13 4 2 -1. + <_> + 8 14 4 1 2. + 0 + 9.4633679836988449e-003 + -8.1573672592639923e-002 + 1.5981380641460419e-001 + <_> + + <_> + + + + <_> + 0 6 2 3 -1. + <_> + 0 7 2 1 3. + 0 + -6.4435349777340889e-003 + -8.9533412456512451e-001 + 6.0908339917659760e-002 + <_> + + <_> + + + + <_> + 8 8 3 3 -1. + <_> + 9 8 1 3 3. + 0 + -1.3353319838643074e-002 + 5.0735729932785034e-001 + -1.4220820367336273e-001 + <_> + + <_> + + + + <_> + 0 12 5 4 -1. + <_> + 0 14 5 2 2. + 0 + -4.8206631094217300e-002 + -7.0776158571243286e-001 + 8.7017923593521118e-002 + <_> + + <_> + + + + <_> + 6 16 4 2 -1. + <_> + 8 16 2 1 2. + <_> + 6 17 2 1 2. + 0 + -8.6862186435610056e-005 + 9.2491082847118378e-002 + -1.9064180552959442e-001 + <_> + + <_> + + + + <_> + 1 12 2 2 -1. + <_> + 1 12 1 1 2. + <_> + 2 13 1 1 2. + 0 + 3.5890119615942240e-003 + -1.1369240283966064e-001 + 4.5717659592628479e-001 + <_> + + <_> + + + + <_> + 8 12 2 2 -1. + <_> + 9 12 1 1 2. + <_> + 8 13 1 1 2. + 0 + 2.5103650987148285e-003 + -9.6626877784729004e-002 + 2.8315341472625732e-001 + <_> + + <_> + + + + <_> + 0 16 1 2 -1. + <_> + 0 17 1 1 2. + 0 + -1.6438219463452697e-003 + -6.8512988090515137e-001 + 8.4855683147907257e-002 + <_> + + <_> + + + + <_> + 8 12 2 2 -1. + <_> + 9 12 1 1 2. + <_> + 8 13 1 1 2. + 0 + -1.1147640179842710e-003 + 2.0340760052204132e-001 + -9.5162183046340942e-002 + <_> + + <_> + + + + <_> + 2 12 2 2 -1. + <_> + 2 12 1 1 2. + <_> + 3 13 1 1 2. + 0 + 3.3129220828413963e-003 + -1.2348870187997818e-001 + 4.5109578967094421e-001 + <_> + + <_> + + + + <_> + 8 13 2 3 -1. + <_> + 7 14 2 1 3. + 1 + 1.2473019771277905e-002 + 8.5647627711296082e-002 + -1.7752259969711304e-001 + <_> + + <_> + + + + <_> + 4 13 3 2 -1. + <_> + 5 14 1 2 3. + 1 + 1.1887500062584877e-002 + 7.9497292637825012e-002 + -7.1333557367324829e-001 + <_> + + <_> + + + + <_> + 9 10 2 4 -1. + <_> + 10 10 1 2 2. + <_> + 9 12 1 2 2. + 0 + 4.6640802174806595e-003 + -1.1890850216150284e-001 + 1.6375760734081268e-001 + <_> + + <_> + + + + <_> + 1 10 2 4 -1. + <_> + 1 10 1 2 2. + <_> + 2 12 1 2 2. + 0 + -7.5049358420073986e-003 + 4.5544099807739258e-001 + -1.2412810325622559e-001 + <_> + + <_> + + + + <_> + 7 16 2 2 -1. + <_> + 7 16 2 1 2. + 1 + 1.7780659720301628e-002 + -1.0757599771022797e-001 + 1.6240009665489197e-001 + <_> + + <_> + + + + <_> + 1 8 3 3 -1. + <_> + 2 8 1 3 3. + 0 + -6.5337750129401684e-003 + 4.3141070008277893e-001 + -1.2603540718555450e-001 + <_> + + <_> + + + + <_> + 8 10 3 3 -1. + <_> + 8 11 3 1 3. + 0 + -2.4446230381727219e-002 + -6.6479730606079102e-001 + 1.9722750410437584e-002 + <_> + + <_> + + + + <_> + 4 0 3 3 -1. + <_> + 5 0 1 3 3. + 0 + 6.8284119479358196e-003 + 8.7926700711250305e-002 + -5.4765981435775757e-001 + <_> + + <_> + + + + <_> + 5 8 4 6 -1. + <_> + 5 11 4 3 2. + 0 + -1.7527850344777107e-002 + -4.7350269556045532e-001 + 1.8452549353241920e-002 + <_> + + <_> + + + + <_> + 6 5 6 1 -1. + <_> + 6 5 3 1 2. + 1 + -5.6044701486825943e-003 + 1.6700869798660278e-001 + -2.8558060526847839e-001 + <_> + + <_> + + + + <_> + 7 15 2 2 -1. + <_> + 7 15 2 1 2. + 1 + 5.6587088853120804e-002 + 9.8792626522481441e-004 + -9.0761202573776245e-001 + <_> + + <_> + + + + <_> + 5 15 2 2 -1. + <_> + 5 15 1 2 2. + 1 + -9.1678956523537636e-003 + -5.7369470596313477e-001 + 8.6971327662467957e-002 + <_> + + <_> + + + + <_> + 9 3 3 3 -1. + <_> + 9 4 3 1 3. + 0 + -7.9324431717395782e-003 + -7.1619319915771484e-001 + 4.7531701624393463e-002 + -1.3085269927978516e+000 + 12 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 4 3 4 -1. + <_> + 4 5 3 2 2. + 0 + 1.1259860359132290e-002 + -3.2671540975570679e-001 + 3.7448620796203613e-001 + <_> + + <_> + + + + <_> + 11 0 1 2 -1. + <_> + 11 0 1 1 2. + 1 + -8.0411562521476299e-005 + 1.3456510007381439e-001 + -3.5597088932991028e-001 + <_> + + <_> + + + + <_> + 1 0 2 1 -1. + <_> + 1 0 1 1 2. + 1 + -1.0097360238432884e-002 + 4.2515400052070618e-001 + -2.0356260240077972e-001 + <_> + + <_> + + + + <_> + 4 6 8 12 -1. + <_> + 8 6 4 6 2. + <_> + 4 12 4 6 2. + 0 + -9.5205657184123993e-002 + -2.6214841008186340e-001 + 4.4497821480035782e-002 + <_> + + <_> + + + + <_> + 1 6 8 12 -1. + <_> + 1 6 4 6 2. + <_> + 5 12 4 6 2. + 0 + 2.1976239979267120e-001 + -2.6376900076866150e-001 + 2.7963450551033020e-001 + <_> + + <_> + + + + <_> + 10 0 2 3 -1. + <_> + 9 1 2 1 3. + 1 + -1.4373429585248232e-003 + 1.9384309649467468e-001 + -6.6377736628055573e-002 + <_> + + <_> + + + + <_> + 2 0 3 2 -1. + <_> + 3 1 1 2 3. + 1 + -2.1600460633635521e-002 + 5.2735280990600586e-001 + -1.1125139892101288e-001 + <_> + + <_> + + + + <_> + 8 10 4 3 -1. + <_> + 7 11 4 1 3. + 1 + 8.8454764336347580e-003 + -1.6414600610733032e-001 + 1.7835170030593872e-001 + <_> + + <_> + + + + <_> + 0 0 12 14 -1. + <_> + 0 7 12 7 2. + 0 + 3.5627551376819611e-002 + -5.0226557254791260e-001 + 1.2036989629268646e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 6 18 6 1 2. + <_> + 0 19 6 1 2. + 0 + 1.9948599860072136e-002 + -2.4443860352039337e-001 + 2.0503400266170502e-001 + <_> + + <_> + + + + <_> + 0 17 2 3 -1. + <_> + 0 18 2 1 3. + 0 + -3.0674149747937918e-003 + -5.3477287292480469e-001 + 1.1543580144643784e-001 + <_> + + <_> + + + + <_> + 10 8 2 6 -1. + <_> + 11 8 1 3 2. + <_> + 10 11 1 3 2. + 0 + -1.2012269580736756e-003 + 1.2676300108432770e-001 + -1.3938720524311066e-001 + <_> + + <_> + + + + <_> + 0 8 2 6 -1. + <_> + 0 8 1 3 2. + <_> + 1 11 1 3 2. + 0 + 1.7143359407782555e-002 + -1.0488930344581604e-001 + 4.8458871245384216e-001 + <_> + + <_> + + + + <_> + 10 17 2 3 -1. + <_> + 10 18 2 1 3. + 0 + 7.7037338633090258e-004 + -2.6416009664535522e-001 + 1.3753029704093933e-001 + <_> + + <_> + + + + <_> + 0 17 2 3 -1. + <_> + 0 18 2 1 3. + 0 + 1.9928140100091696e-003 + 1.0820219665765762e-001 + -4.6027541160583496e-001 + <_> + + <_> + + + + <_> + 9 8 3 3 -1. + <_> + 10 8 1 3 3. + 0 + 8.1858411431312561e-003 + -1.1870039999485016e-001 + 1.8429510295391083e-001 + <_> + + <_> + + + + <_> + 0 6 3 14 -1. + <_> + 0 13 3 7 2. + 0 + 2.0016850531101227e-001 + -7.7433213591575623e-002 + 6.7445492744445801e-001 + <_> + + <_> + + + + <_> + 9 8 3 3 -1. + <_> + 10 8 1 3 3. + 0 + -1.2134050019085407e-002 + 4.5361760258674622e-001 + -3.2230481505393982e-002 + <_> + + <_> + + + + <_> + 0 8 3 3 -1. + <_> + 1 8 1 3 3. + 0 + 1.1809550225734711e-002 + -1.5140220522880554e-001 + 4.1091579198837280e-001 + <_> + + <_> + + + + <_> + 9 9 3 3 -1. + <_> + 8 10 3 1 3. + 1 + -5.3903311491012573e-002 + 2.4644249677658081e-001 + -1.6336809843778610e-002 + <_> + + <_> + + + + <_> + 3 9 3 3 -1. + <_> + 4 10 1 3 3. + 1 + 2.5369100272655487e-002 + 5.7606618851423264e-002 + -8.1810200214385986e-001 + <_> + + <_> + + + + <_> + 8 7 4 1 -1. + <_> + 8 7 2 1 2. + 0 + 4.0477071888744831e-003 + 3.4279700368642807e-002 + -3.8912689685821533e-001 + <_> + + <_> + + + + <_> + 0 7 4 1 -1. + <_> + 2 7 2 1 2. + 0 + 2.3273769766092300e-003 + -2.6318120956420898e-001 + 2.0111019909381866e-001 + <_> + + <_> + + + + <_> + 0 0 12 7 -1. + <_> + 0 0 6 7 2. + 0 + -1.4055520296096802e-002 + -4.5798641443252563e-001 + 1.0322000086307526e-001 + <_> + + <_> + + + + <_> + 3 12 4 3 -1. + <_> + 2 13 4 1 3. + 1 + 4.1040539741516113e-002 + -1.0665339976549149e-001 + 4.9921628832817078e-001 + <_> + + <_> + + + + <_> + 8 10 3 3 -1. + <_> + 8 11 3 1 3. + 0 + 1.7403350211679935e-003 + -3.0963689088821411e-002 + 9.0507246553897858e-002 + <_> + + <_> + + + + <_> + 1 10 3 3 -1. + <_> + 1 11 3 1 3. + 0 + -5.9111667796969414e-003 + -6.9301342964172363e-001 + 7.1324340999126434e-002 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 4 15 1 2 3. + 1 + -8.4086872637271881e-002 + 4.6972590684890747e-001 + -4.9859449267387390e-002 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 8 15 2 1 3. + 1 + 1.2733220355585217e-003 + -3.5704851150512695e-001 + 1.3806779682636261e-001 + <_> + + <_> + + + + <_> + 5 0 2 3 -1. + <_> + 5 1 2 1 3. + 0 + 5.9486827813088894e-003 + -1.5816900134086609e-001 + 2.8468400239944458e-001 + <_> + + <_> + + + + <_> + 1 8 3 4 -1. + <_> + 1 9 3 2 2. + 0 + -8.6815077811479568e-003 + -7.6587718725204468e-001 + 6.2390629202127457e-002 + <_> + + <_> + + + + <_> + 9 0 3 2 -1. + <_> + 10 1 1 2 3. + 1 + -1.0674200020730495e-002 + -5.5144512653350830e-001 + 5.6196320801973343e-002 + <_> + + <_> + + + + <_> + 3 0 2 3 -1. + <_> + 2 1 2 1 3. + 1 + 1.7951499670743942e-002 + 6.1362300068140030e-002 + -6.4841997623443604e-001 + <_> + + <_> + + + + <_> + 10 17 2 1 -1. + <_> + 10 17 1 1 2. + 0 + 1.9660689576994628e-004 + -1.4563970267772675e-001 + 9.5173902809619904e-002 + <_> + + <_> + + + + <_> + 0 17 2 1 -1. + <_> + 1 17 1 1 2. + 0 + -1.3475000159814954e-003 + -3.9846318960189819e-001 + 1.0717230290174484e-001 + <_> + + <_> + + + + <_> + 8 13 2 2 -1. + <_> + 9 13 1 1 2. + <_> + 8 14 1 1 2. + 0 + 1.3271289644762874e-003 + -7.6305247843265533e-002 + 1.5964789688587189e-001 + <_> + + <_> + + + + <_> + 2 13 2 2 -1. + <_> + 2 13 1 1 2. + <_> + 3 14 1 1 2. + 0 + 3.9857891388237476e-003 + -1.0918959975242615e-001 + 3.6956569552421570e-001 + <_> + + <_> + + + + <_> + 9 10 3 2 -1. + <_> + 10 10 1 2 3. + 0 + 1.7747710226103663e-003 + -5.8550398796796799e-002 + 7.1181796491146088e-002 + <_> + + <_> + + + + <_> + 0 10 3 2 -1. + <_> + 1 10 1 2 3. + 0 + -6.9627179764211178e-003 + 3.6977839469909668e-001 + -1.1677960306406021e-001 + <_> + + <_> + + + + <_> + 9 7 3 3 -1. + <_> + 9 8 3 1 3. + 0 + -9.0530123561620712e-003 + -5.3131139278411865e-001 + 4.2773369699716568e-002 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 7 5 1 4 3. + 1 + -5.0673801451921463e-002 + 6.5122097730636597e-001 + -6.6222466528415680e-002 + <_> + + <_> + + + + <_> + 8 4 3 7 -1. + <_> + 9 4 1 7 3. + 0 + -9.9803637713193893e-003 + 1.7810410261154175e-001 + -4.8675179481506348e-002 + <_> + + <_> + + + + <_> + 2 9 3 4 -1. + <_> + 2 10 3 2 2. + 0 + 1.0967300273478031e-002 + 6.3715361058712006e-002 + -7.0216029882431030e-001 + <_> + + <_> + + + + <_> + 8 4 3 7 -1. + <_> + 9 4 1 7 3. + 0 + 7.1746408939361572e-003 + -9.5948472619056702e-002 + 1.5818059444427490e-001 + -1.3564130067825317e+000 + 13 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 6 3 1 -1. + <_> + 7 7 1 1 3. + 1 + -1.4637179672718048e-002 + 4.5756229758262634e-001 + -2.5793579220771790e-001 + <_> + + <_> + + + + <_> + 9 0 1 3 -1. + <_> + 9 1 1 1 3. + 0 + -1.1372080189175904e-004 + 1.4856390655040741e-001 + -1.3528409600257874e-001 + <_> + + <_> + + + + <_> + 2 0 1 3 -1. + <_> + 2 1 1 1 3. + 0 + 6.3527049496769905e-003 + -1.8282939493656158e-001 + 5.0529718399047852e-001 + <_> + + <_> + + + + <_> + 9 11 1 8 -1. + <_> + 9 15 1 4 2. + 0 + 2.4946528719738126e-004 + -3.5463958978652954e-001 + 1.1956059932708740e-001 + <_> + + <_> + + + + <_> + 0 3 12 2 -1. + <_> + 0 4 12 1 2. + 0 + 8.5882786661386490e-003 + -3.6795818805694580e-001 + 1.9289310276508331e-001 + <_> + + <_> + + + + <_> + 10 11 2 5 -1. + <_> + 10 11 1 5 2. + 1 + -5.3795471787452698e-002 + -9.2534601688385010e-001 + -3.0407099984586239e-003 + <_> + + <_> + + + + <_> + 2 11 1 8 -1. + <_> + 2 15 1 4 2. + 0 + -1.2914909981191158e-002 + 2.0769760012626648e-001 + -2.8073310852050781e-001 + <_> + + <_> + + + + <_> + 6 12 6 7 -1. + <_> + 6 12 3 7 2. + 0 + 6.5217018127441406e-002 + 9.1229602694511414e-002 + -3.9509040117263794e-001 + <_> + + <_> + + + + <_> + 0 0 4 2 -1. + <_> + 0 0 2 1 2. + <_> + 2 1 2 1 2. + 0 + -1.5482950024306774e-002 + 5.5492401123046875e-001 + -1.0178919881582260e-001 + <_> + + <_> + + + + <_> + 6 12 6 7 -1. + <_> + 6 12 3 7 2. + 0 + -7.0964470505714417e-002 + -6.0590541362762451e-001 + 3.3235780894756317e-002 + <_> + + <_> + + + + <_> + 0 12 6 7 -1. + <_> + 3 12 3 7 2. + 0 + -1.4792110025882721e-001 + 6.8140488862991333e-001 + -9.2882059514522552e-002 + <_> + + <_> + + + + <_> + 8 2 1 8 -1. + <_> + 6 4 1 4 2. + 1 + 3.2156299799680710e-002 + -1.3000990450382233e-001 + 1.6143409907817841e-001 + <_> + + <_> + + + + <_> + 4 2 8 1 -1. + <_> + 6 4 4 1 2. + 1 + -5.5202730000019073e-003 + 1.8147900700569153e-001 + -3.2928371429443359e-001 + <_> + + <_> + + + + <_> + 9 10 3 3 -1. + <_> + 8 11 3 1 3. + 1 + 1.7749259248375893e-002 + -6.7472197115421295e-002 + 2.4095970392227173e-001 + <_> + + <_> + + + + <_> + 3 10 3 3 -1. + <_> + 4 11 1 3 3. + 1 + -1.4773460105061531e-002 + -7.1976912021636963e-001 + 7.0244252681732178e-002 + <_> + + <_> + + + + <_> + 2 0 8 2 -1. + <_> + 4 0 4 2 2. + 0 + -2.1384380757808685e-002 + -6.6300392150878906e-001 + 6.1542339622974396e-002 + <_> + + <_> + + + + <_> + 6 7 3 2 -1. + <_> + 7 8 1 2 3. + 1 + 1.1285319924354553e-002 + -1.1147149652242661e-001 + 4.2070099711418152e-001 + <_> + + <_> + + + + <_> + 3 4 6 12 -1. + <_> + 3 8 6 4 3. + 0 + 5.3818488959223032e-004 + 1.3580459356307983e-001 + -3.6389431357383728e-001 + <_> + + <_> + + + + <_> + 0 7 3 3 -1. + <_> + 0 8 3 1 3. + 0 + -4.5372340828180313e-003 + -6.2848389148712158e-001 + 7.5644947588443756e-002 + <_> + + <_> + + + + <_> + 8 11 4 6 -1. + <_> + 8 13 4 2 3. + 0 + -5.8880869299173355e-002 + -4.4123521447181702e-001 + 5.2693258039653301e-003 + <_> + + <_> + + + + <_> + 0 11 4 6 -1. + <_> + 0 13 4 2 3. + 0 + 3.7623539566993713e-002 + 6.0741778463125229e-002 + -7.3273491859436035e-001 + <_> + + <_> + + + + <_> + 3 17 8 2 -1. + <_> + 7 17 4 1 2. + <_> + 3 18 4 1 2. + 0 + 4.9864239990711212e-003 + -9.5100089907646179e-002 + 1.3218070566654205e-001 + <_> + + <_> + + + + <_> + 0 14 10 5 -1. + <_> + 5 14 5 5 2. + 0 + 1.5848229825496674e-001 + -2.3477560281753540e-001 + 2.0766119658946991e-001 + <_> + + <_> + + + + <_> + 8 11 3 1 -1. + <_> + 9 11 1 1 3. + 0 + -2.2148280404508114e-003 + 1.3150349259376526e-001 + -7.2531886398792267e-002 + <_> + + <_> + + + + <_> + 1 11 3 1 -1. + <_> + 2 11 1 1 3. + 0 + -2.4197169113904238e-003 + 3.4369221329689026e-001 + -1.3603129982948303e-001 + <_> + + <_> + + + + <_> + 9 1 3 6 -1. + <_> + 10 2 1 6 3. + 1 + 1.3667210005223751e-002 + -1.1352819949388504e-001 + 1.8905560672283173e-001 + <_> + + <_> + + + + <_> + 0 0 12 18 -1. + <_> + 0 9 12 9 2. + 0 + 3.4907150268554688e-001 + -2.0564649999141693e-001 + 2.0814339816570282e-001 + <_> + + <_> + + + + <_> + 8 6 1 2 -1. + <_> + 8 6 1 1 2. + 1 + -2.3180799558758736e-002 + -7.0410561561584473e-001 + 6.5354611724615097e-003 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 7 5 1 3 3. + 1 + -2.4704890325665474e-002 + 4.3212160468101501e-001 + -1.0485579818487167e-001 + <_> + + <_> + + + + <_> + 9 1 3 6 -1. + <_> + 10 2 1 6 3. + 1 + 3.5061739385128021e-002 + -5.6936308741569519e-002 + 2.4053120613098145e-001 + <_> + + <_> + + + + <_> + 3 1 6 3 -1. + <_> + 2 2 6 1 3. + 1 + -2.8482209891080856e-002 + -6.4425909519195557e-001 + 6.7065469920635223e-002 + <_> + + <_> + + + + <_> + 9 11 2 3 -1. + <_> + 8 12 2 1 3. + 1 + 9.4022173434495926e-003 + -8.7327830493450165e-002 + 1.0236190259456635e-001 + <_> + + <_> + + + + <_> + 3 11 3 2 -1. + <_> + 4 12 1 2 3. + 1 + 1.2662390246987343e-002 + 6.4649492502212524e-002 + -6.6464841365814209e-001 + <_> + + <_> + + + + <_> + 8 5 4 4 -1. + <_> + 8 6 4 2 2. + 0 + -1.8630980048328638e-004 + 8.8812537491321564e-002 + -1.4801080524921417e-001 + <_> + + <_> + + + + <_> + 0 5 4 4 -1. + <_> + 0 6 4 2 2. + 0 + -6.3631217926740646e-003 + -6.1257928609848022e-001 + 7.0822767913341522e-002 + <_> + + <_> + + + + <_> + 5 17 3 3 -1. + <_> + 5 18 3 1 3. + 0 + -3.2741650938987732e-003 + 1.6412730515003204e-001 + -1.3364849984645844e-001 + <_> + + <_> + + + + <_> + 4 15 1 3 -1. + <_> + 4 16 1 1 3. + 0 + 3.4096399322152138e-003 + -1.2046200037002563e-001 + 3.2251781225204468e-001 + <_> + + <_> + + + + <_> + 10 10 2 4 -1. + <_> + 11 10 1 2 2. + <_> + 10 12 1 2 2. + 0 + -2.0664960611611605e-003 + 8.0544687807559967e-002 + -3.9290331304073334e-002 + <_> + + <_> + + + + <_> + 0 10 2 4 -1. + <_> + 0 10 1 2 2. + <_> + 1 12 1 2 2. + 0 + -7.1488898247480392e-003 + 3.5944211483001709e-001 + -1.1370600014925003e-001 + <_> + + <_> + + + + <_> + 9 4 3 6 -1. + <_> + 10 4 1 6 3. + 0 + 1.4608979690819979e-003 + -1.4393359422683716e-001 + 1.0468409955501556e-001 + <_> + + <_> + + + + <_> + 0 4 3 6 -1. + <_> + 1 4 1 6 3. + 0 + -1.2510320171713829e-002 + 3.0024001002311707e-001 + -1.3041430711746216e-001 + <_> + + <_> + + + + <_> + 10 7 2 6 -1. + <_> + 11 7 1 3 2. + <_> + 10 10 1 3 2. + 0 + -1.6470119357109070e-002 + -3.4044870734214783e-001 + 2.2476559504866600e-002 + <_> + + <_> + + + + <_> + 0 7 2 6 -1. + <_> + 0 7 1 3 2. + <_> + 1 10 1 3 2. + 0 + -1.3765309937298298e-002 + 4.4677600264549255e-001 + -9.7284018993377686e-002 + <_> + + <_> + + + + <_> + 10 8 2 3 -1. + <_> + 10 9 2 1 3. + 0 + 1.0946969996439293e-004 + -2.0872430503368378e-001 + 1.5401780605316162e-001 + <_> + + <_> + + + + <_> + 0 8 3 3 -1. + <_> + 0 9 3 1 3. + 0 + -6.9605209864675999e-003 + -8.2299548387527466e-001 + 4.8897851258516312e-002 + -1.2748670578002930e+000 + 14 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 0 4 1 -1. + <_> + 2 0 2 1 2. + 0 + 4.9184081144630909e-003 + -3.2976099848747253e-001 + 3.1599700450897217e-001 + <_> + + <_> + + + + <_> + 4 6 4 3 -1. + <_> + 4 7 4 1 3. + 0 + -8.4240734577178955e-003 + 3.2350379228591919e-001 + -2.4553489685058594e-001 + <_> + + <_> + + + + <_> + 0 8 10 10 -1. + <_> + 0 8 5 5 2. + <_> + 5 13 5 5 2. + 0 + 2.0760910212993622e-001 + -2.7401238679885864e-001 + 2.4197450280189514e-001 + <_> + + <_> + + + + <_> + 8 0 1 8 -1. + <_> + 8 0 1 4 2. + 1 + -1.5002899803221226e-002 + 8.3533883094787598e-002 + -2.5596448779106140e-001 + <_> + + <_> + + + + <_> + 1 6 4 1 -1. + <_> + 3 6 2 1 2. + 0 + 2.2144610993564129e-003 + -2.2534610331058502e-001 + 2.2740550339221954e-001 + <_> + + <_> + + + + <_> + 8 0 1 8 -1. + <_> + 8 0 1 4 2. + 1 + -6.0699690133333206e-002 + 1.8549209833145142e-001 + -1.9505530595779419e-002 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 6 13 1 3 2. + 1 + -5.6538339704275131e-002 + 6.1330437660217285e-001 + -8.7735809385776520e-002 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 19 12 1 2. + 0 + -1.4412499964237213e-002 + 2.4093009531497955e-001 + -2.7344560623168945e-001 + <_> + + <_> + + + + <_> + 3 18 1 2 -1. + <_> + 3 19 1 1 2. + 0 + -1.4219420263543725e-003 + -6.0177552700042725e-001 + 1.0058429837226868e-001 + <_> + + <_> + + + + <_> + 10 10 2 6 -1. + <_> + 10 10 1 6 2. + 0 + 1.6331190243363380e-002 + 2.1288860589265823e-002 + -5.0142019987106323e-001 + <_> + + <_> + + + + <_> + 0 10 2 6 -1. + <_> + 1 10 1 6 2. + 0 + 1.4106729999184608e-002 + -1.8390950560569763e-001 + 2.6597890257835388e-001 + <_> + + <_> + + + + <_> + 8 0 1 8 -1. + <_> + 8 0 1 4 2. + 1 + -4.9360690172761679e-004 + 3.0524199828505516e-002 + -2.0498749613761902e-001 + <_> + + <_> + + + + <_> + 4 2 4 2 -1. + <_> + 4 2 2 1 2. + <_> + 6 3 2 1 2. + 0 + -7.0101441815495491e-003 + 4.0488889813423157e-001 + -1.1826159805059433e-001 + <_> + + <_> + + + + <_> + 0 8 12 2 -1. + <_> + 0 8 6 2 2. + 0 + 6.4736358821392059e-002 + 9.0163238346576691e-002 + -4.8485979437828064e-001 + <_> + + <_> + + + + <_> + 4 0 4 2 -1. + <_> + 5 0 2 2 2. + 0 + -6.7224488593637943e-003 + -5.4630178213119507e-001 + 7.3308691382408142e-002 + <_> + + <_> + + + + <_> + 6 0 3 3 -1. + <_> + 7 0 1 3 3. + 0 + -1.2748160399496555e-002 + -6.7641848325729370e-001 + 3.2798580825328827e-002 + <_> + + <_> + + + + <_> + 3 0 3 3 -1. + <_> + 4 0 1 3 3. + 0 + -7.3234830051660538e-003 + -6.3869500160217285e-001 + 5.4413169622421265e-002 + <_> + + <_> + + + + <_> + 6 5 1 3 -1. + <_> + 5 6 1 1 3. + 1 + -1.7713790759444237e-002 + -7.4989777803421021e-001 + 6.3041099347174168e-003 + <_> + + <_> + + + + <_> + 0 1 2 4 -1. + <_> + 0 1 1 2 2. + <_> + 1 3 1 2 2. + 0 + -1.1022159829735756e-002 + 4.7562441229820251e-001 + -8.7812356650829315e-002 + <_> + + <_> + + + + <_> + 10 1 2 4 -1. + <_> + 11 1 1 2 2. + <_> + 10 3 1 2 2. + 0 + -7.2062062099575996e-003 + -5.1175302267074585e-001 + 3.8222119212150574e-002 + <_> + + <_> + + + + <_> + 0 1 2 4 -1. + <_> + 0 1 1 2 2. + <_> + 1 3 1 2 2. + 0 + 7.8669954091310501e-003 + -1.0822050273418427e-001 + 4.3007129430770874e-001 + <_> + + <_> + + + + <_> + 9 8 3 3 -1. + <_> + 9 9 3 1 3. + 0 + 1.4753219671547413e-002 + 3.0923029407858849e-002 + -5.8399969339370728e-001 + <_> + + <_> + + + + <_> + 6 16 2 2 -1. + <_> + 6 16 1 2 2. + 1 + -8.7396129965782166e-003 + -5.5709302425384521e-001 + 6.5057590603828430e-002 + <_> + + <_> + + + + <_> + 6 8 2 1 -1. + <_> + 6 8 1 1 2. + 0 + -1.8765570130199194e-003 + 2.0753450691699982e-001 + -1.0404630005359650e-001 + <_> + + <_> + + + + <_> + 6 5 3 1 -1. + <_> + 7 6 1 1 3. + 1 + 6.1403261497616768e-003 + -8.8196322321891785e-002 + 5.0393581390380859e-001 + <_> + + <_> + + + + <_> + 5 5 2 3 -1. + <_> + 5 6 2 1 3. + 0 + -6.2455530278384686e-003 + 4.5692878961563110e-001 + -8.8871538639068604e-002 + <_> + + <_> + + + + <_> + 1 6 3 3 -1. + <_> + 1 7 3 1 3. + 0 + -6.5213078632950783e-003 + -7.3358172178268433e-001 + 6.1022911220788956e-002 + <_> + + <_> + + + + <_> + 8 1 1 8 -1. + <_> + 6 3 1 4 2. + 1 + 8.4276527166366577e-002 + -5.1953801885247231e-003 + -7.2847050428390503e-001 + <_> + + <_> + + + + <_> + 4 1 8 1 -1. + <_> + 6 3 4 1 2. + 1 + 1.2186209671199322e-002 + 8.0246433615684509e-002 + -4.9406829476356506e-001 + <_> + + <_> + + + + <_> + 8 13 3 4 -1. + <_> + 7 14 3 2 2. + 1 + -5.2070740610361099e-002 + 5.3785991668701172e-001 + -2.6184149086475372e-002 + <_> + + <_> + + + + <_> + 5 5 1 8 -1. + <_> + 5 7 1 4 2. + 0 + -1.8056540284305811e-003 + 1.2499610334634781e-001 + -3.1014269590377808e-001 + <_> + + <_> + + + + <_> + 9 11 3 3 -1. + <_> + 8 12 3 1 3. + 1 + 3.5525551065802574e-003 + -1.4355179667472839e-001 + 9.3508958816528320e-002 + <_> + + <_> + + + + <_> + 4 13 4 3 -1. + <_> + 5 14 2 3 2. + 1 + 2.1722750738263130e-002 + 5.4289009422063828e-002 + -6.9004470109939575e-001 + <_> + + <_> + + + + <_> + 8 4 3 4 -1. + <_> + 9 5 1 4 3. + 1 + 1.5696860849857330e-002 + -6.2646992504596710e-002 + 5.2328252792358398e-001 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 7 5 1 4 3. + 1 + 1.1486239731311798e-002 + -1.7067709565162659e-001 + 2.5379261374473572e-001 + <_> + + <_> + + + + <_> + 8 4 3 4 -1. + <_> + 9 5 1 4 3. + 1 + -7.0110350847244263e-002 + 2.1845239400863647e-001 + -3.2540921121835709e-002 + <_> + + <_> + + + + <_> + 4 4 4 3 -1. + <_> + 3 5 4 1 3. + 1 + -2.3832129314541817e-002 + -7.2852367162704468e-001 + 5.6103359907865524e-002 + <_> + + <_> + + + + <_> + 6 8 4 2 -1. + <_> + 6 9 4 1 2. + 0 + 1.8152900040149689e-002 + 7.9692779108881950e-003 + -5.0108677148818970e-001 + <_> + + <_> + + + + <_> + 2 8 5 2 -1. + <_> + 2 9 5 1 2. + 0 + -4.9337781965732574e-003 + -5.4861277341842651e-001 + 7.4599482119083405e-002 + <_> + + <_> + + + + <_> + 6 13 6 4 -1. + <_> + 6 15 6 2 2. + 0 + -2.8721539303660393e-002 + -5.0967568159103394e-001 + 1.3899230398237705e-002 + <_> + + <_> + + + + <_> + 0 0 12 1 -1. + <_> + 6 0 6 1 2. + 0 + 6.0404408723115921e-003 + 8.0196216702461243e-002 + -4.5811289548873901e-001 + <_> + + <_> + + + + <_> + 11 1 1 3 -1. + <_> + 10 2 1 1 3. + 1 + -1.7407380044460297e-002 + -6.7178148031234741e-001 + 7.8524583950638771e-003 + <_> + + <_> + + + + <_> + 1 1 3 1 -1. + <_> + 2 2 1 1 3. + 1 + 1.8755920231342316e-002 + -7.0715762674808502e-002 + 5.2900022268295288e-001 + <_> + + <_> + + + + <_> + 8 4 3 7 -1. + <_> + 9 4 1 7 3. + 0 + 7.5297430157661438e-003 + -5.4971348494291306e-002 + 1.2586890161037445e-001 + <_> + + <_> + + + + <_> + 1 4 3 7 -1. + <_> + 2 4 1 7 3. + 0 + 2.7714699506759644e-002 + -9.4051122665405273e-002 + 3.9269289374351501e-001 + <_> + + <_> + + + + <_> + 10 0 2 2 -1. + <_> + 10 0 1 2 2. + 1 + -1.9136169925332069e-002 + -6.1292767524719238e-001 + 4.3676119297742844e-002 + <_> + + <_> + + + + <_> + 1 6 3 4 -1. + <_> + 2 6 1 4 3. + 0 + -1.1729629710316658e-002 + 4.0649351477622986e-001 + -1.0054980218410492e-001 + <_> + + <_> + + + + <_> + 10 0 2 3 -1. + <_> + 10 0 1 3 2. + 1 + 2.6842709630727768e-003 + 6.1806179583072662e-002 + -2.6040008664131165e-001 + <_> + + <_> + + + + <_> + 2 0 3 2 -1. + <_> + 2 0 3 1 2. + 1 + 1.3504150323569775e-002 + 6.3247829675674438e-002 + -6.1916601657867432e-001 + <_> + + <_> + + + + <_> + 10 5 1 3 -1. + <_> + 10 6 1 1 3. + 0 + -4.8922952264547348e-003 + -7.3288178443908691e-001 + 4.1912440210580826e-002 + -1.2878630161285400e+000 + 15 + -1 + <_> + + + <_> + + <_> + + + + <_> + 5 0 2 3 -1. + <_> + 5 1 2 1 3. + 0 + 1.0124780237674713e-002 + -2.2478839755058289e-001 + 4.9562188982963562e-001 + <_> + + <_> + + + + <_> + 6 1 6 9 -1. + <_> + 6 4 6 3 3. + 0 + 2.0572949945926666e-001 + 2.6126179844141006e-002 + -7.9092139005661011e-001 + <_> + + <_> + + + + <_> + 4 1 2 9 -1. + <_> + 4 4 2 3 3. + 0 + 1.7348840832710266e-002 + -3.8796889781951904e-001 + 2.0708920061588287e-001 + <_> + + <_> + + + + <_> + 4 1 8 18 -1. + <_> + 8 1 4 9 2. + <_> + 4 10 4 9 2. + 0 + -2.5478509068489075e-001 + -5.7850080728530884e-001 + 1.2234980240464211e-002 + <_> + + <_> + + + + <_> + 4 14 4 6 -1. + <_> + 4 17 4 3 2. + 0 + -2.8602819889783859e-002 + 1.7568160593509674e-001 + -3.7877011299133301e-001 + <_> + + <_> + + + + <_> + 10 1 2 4 -1. + <_> + 11 1 1 2 2. + <_> + 10 3 1 2 2. + 0 + 9.1557251289486885e-003 + 5.8734539896249771e-002 + -5.3387188911437988e-001 + <_> + + <_> + + + + <_> + 0 1 2 4 -1. + <_> + 0 1 1 2 2. + <_> + 1 3 1 2 2. + 0 + -6.7997328005731106e-003 + 4.2286089062690735e-001 + -1.5031290054321289e-001 + <_> + + <_> + + + + <_> + 5 0 4 17 -1. + <_> + 5 0 2 17 2. + 0 + -9.0167991816997528e-002 + -4.7068008780479431e-001 + 1.9146749749779701e-002 + <_> + + <_> + + + + <_> + 3 0 4 17 -1. + <_> + 5 0 2 17 2. + 0 + -2.0075060427188873e-002 + 1.5215730667114258e-001 + -3.0286580324172974e-001 + <_> + + <_> + + + + <_> + 8 9 2 8 -1. + <_> + 8 9 2 4 2. + 1 + -1.5905030071735382e-001 + 4.8262810707092285e-001 + -5.5345159024000168e-002 + <_> + + <_> + + + + <_> + 0 8 12 12 -1. + <_> + 6 8 6 12 2. + 0 + 1.0053060203790665e-001 + -3.1768739223480225e-001 + 1.8654659390449524e-001 + <_> + + <_> + + + + <_> + 7 12 2 2 -1. + <_> + 8 12 1 1 2. + <_> + 7 13 1 1 2. + 0 + 2.9778450261801481e-003 + -4.3355960398912430e-002 + 3.0445128679275513e-001 + <_> + + <_> + + + + <_> + 0 9 4 3 -1. + <_> + 0 10 4 1 3. + 0 + -6.8455971777439117e-003 + -6.5422862768173218e-001 + 5.7101141661405563e-002 + <_> + + <_> + + + + <_> + 6 4 2 3 -1. + <_> + 5 5 2 1 3. + 1 + -2.3462900891900063e-002 + -7.4357628822326660e-001 + 1.1618070304393768e-002 + <_> + + <_> + + + + <_> + 4 0 4 2 -1. + <_> + 4 0 2 1 2. + <_> + 6 1 2 1 2. + 0 + 8.4667708724737167e-003 + -1.1318150162696838e-001 + 3.4910741448402405e-001 + <_> + + <_> + + + + <_> + 11 0 1 12 -1. + <_> + 11 6 1 6 2. + 0 + 2.9225839301943779e-002 + -3.8572481274604797e-001 + 2.5479009747505188e-001 + <_> + + <_> + + + + <_> + 1 2 1 18 -1. + <_> + 1 11 1 9 2. + 0 + 1.1265130341053009e-001 + -9.8677836358547211e-002 + 7.0809727907180786e-001 + <_> + + <_> + + + + <_> + 6 5 4 5 -1. + <_> + 6 5 2 5 2. + 1 + 1.0059010237455368e-001 + 3.9431888610124588e-002 + -2.0872689783573151e-001 + <_> + + <_> + + + + <_> + 1 7 8 2 -1. + <_> + 5 7 4 2 2. + 0 + -1.4622969552874565e-002 + 1.0739020258188248e-001 + -4.4337108731269836e-001 + <_> + + <_> + + + + <_> + 10 0 2 2 -1. + <_> + 10 0 1 2 2. + 1 + 5.9183081611990929e-003 + 2.2479789331555367e-002 + -4.7095221281051636e-001 + <_> + + <_> + + + + <_> + 2 0 2 2 -1. + <_> + 2 0 2 1 2. + 1 + -1.1137289926409721e-002 + -5.3821432590484619e-001 + 7.1250103414058685e-002 + <_> + + <_> + + + + <_> + 8 9 2 8 -1. + <_> + 8 9 2 4 2. + 1 + 2.0612619817256927e-001 + 2.5029089301824570e-003 + -5.5134499073028564e-001 + <_> + + <_> + + + + <_> + 4 9 8 2 -1. + <_> + 4 9 4 2 2. + 1 + 1.9606389105319977e-002 + 6.8830899894237518e-002 + -5.8748298883438110e-001 + <_> + + <_> + + + + <_> + 9 11 2 3 -1. + <_> + 8 12 2 1 3. + 1 + 1.4237780123949051e-002 + -1.0993599891662598e-001 + 2.2019009292125702e-001 + <_> + + <_> + + + + <_> + 3 11 3 2 -1. + <_> + 4 12 1 2 3. + 1 + -1.1579900048673153e-002 + -6.0401040315628052e-001 + 6.1112940311431885e-002 + <_> + + <_> + + + + <_> + 8 12 2 2 -1. + <_> + 9 12 1 1 2. + <_> + 8 13 1 1 2. + 0 + 2.7201389893889427e-003 + -8.6882777512073517e-002 + 2.1160760521888733e-001 + <_> + + <_> + + + + <_> + 2 12 2 2 -1. + <_> + 2 12 1 1 2. + <_> + 3 13 1 1 2. + 0 + 4.3311892077326775e-003 + -8.5722766816616058e-002 + 4.3251448869705200e-001 + <_> + + <_> + + + + <_> + 7 13 2 2 -1. + <_> + 8 13 1 1 2. + <_> + 7 14 1 1 2. + 0 + 1.4856910565868020e-003 + -3.5430859774351120e-002 + 1.4321969449520111e-001 + <_> + + <_> + + + + <_> + 3 13 2 2 -1. + <_> + 3 13 1 1 2. + <_> + 4 14 1 1 2. + 0 + -2.4972909595817327e-003 + 4.2610010504722595e-001 + -1.0974500328302383e-001 + <_> + + <_> + + + + <_> + 9 10 3 3 -1. + <_> + 9 11 3 1 3. + 0 + 1.3857520185410976e-002 + 2.1762149408459663e-002 + -4.7706019878387451e-001 + <_> + + <_> + + + + <_> + 3 2 7 3 -1. + <_> + 2 3 7 1 3. + 1 + -2.3594869300723076e-002 + -4.6244761347770691e-001 + 7.9718932509422302e-002 + <_> + + <_> + + + + <_> + 10 18 2 2 -1. + <_> + 10 19 2 1 2. + 0 + -3.0481400899589062e-003 + 1.7503540217876434e-001 + -2.9865878820419312e-001 + <_> + + <_> + + + + <_> + 0 18 2 2 -1. + <_> + 0 19 2 1 2. + 0 + -1.3127359561622143e-003 + -5.5913221836090088e-001 + 7.1896396577358246e-002 + <_> + + <_> + + + + <_> + 10 2 2 1 -1. + <_> + 10 2 1 1 2. + 0 + -4.3319691903889179e-003 + -8.0651438236236572e-001 + 1.5199059620499611e-002 + <_> + + <_> + + + + <_> + 0 2 2 1 -1. + <_> + 1 2 1 1 2. + 0 + -3.6742340307682753e-003 + 4.2407768964767456e-001 + -9.2443756759166718e-002 + <_> + + <_> + + + + <_> + 9 3 3 6 -1. + <_> + 10 3 1 6 3. + 0 + 2.5564959272742271e-002 + 2.9059829190373421e-002 + -4.8274171352386475e-001 + <_> + + <_> + + + + <_> + 0 3 3 6 -1. + <_> + 1 3 1 6 3. + 0 + 2.8129860758781433e-002 + -8.0184653401374817e-002 + 5.2279758453369141e-001 + <_> + + <_> + + + + <_> + 9 10 3 3 -1. + <_> + 9 11 3 1 3. + 0 + 8.8039072579704225e-005 + -7.4344098567962646e-002 + 9.4045989215373993e-002 + <_> + + <_> + + + + <_> + 0 10 3 3 -1. + <_> + 0 11 3 1 3. + 0 + -4.6100970357656479e-003 + -5.1046329736709595e-001 + 7.0259310305118561e-002 + <_> + + <_> + + + + <_> + 9 11 2 2 -1. + <_> + 10 11 1 1 2. + <_> + 9 12 1 1 2. + 0 + 2.4607360828667879e-003 + -7.3687382042407990e-002 + 1.7185910046100616e-001 + <_> + + <_> + + + + <_> + 1 11 2 2 -1. + <_> + 1 11 1 1 2. + <_> + 2 12 1 1 2. + 0 + -1.8461809959262609e-003 + 3.2514411211013794e-001 + -1.2517750263214111e-001 + <_> + + <_> + + + + <_> + 9 12 1 3 -1. + <_> + 8 13 1 1 3. + 1 + 2.6498539955355227e-004 + -1.0129640251398087e-001 + 5.4491110146045685e-002 + <_> + + <_> + + + + <_> + 6 12 4 2 -1. + <_> + 6 12 4 1 2. + 1 + 1.3974959962069988e-002 + 1.0203190147876740e-001 + -3.9044409990310669e-001 + <_> + + <_> + + + + <_> + 9 12 1 3 -1. + <_> + 8 13 1 1 3. + 1 + 3.3575310371816158e-003 + -6.4226530492305756e-002 + 5.4202359169721603e-002 + <_> + + <_> + + + + <_> + 3 12 3 1 -1. + <_> + 4 13 1 1 3. + 1 + 7.3201949708163738e-003 + 5.9934031218290329e-002 + -6.0588258504867554e-001 + <_> + + <_> + + + + <_> + 7 12 2 2 -1. + <_> + 8 12 1 1 2. + <_> + 7 13 1 1 2. + 0 + -1.2428000336512923e-003 + 1.1665280163288116e-001 + -7.2288237512111664e-002 + <_> + + <_> + + + + <_> + 3 12 2 2 -1. + <_> + 3 12 1 1 2. + <_> + 4 13 1 1 2. + 0 + -1.8044740427285433e-003 + 3.4149900078773499e-001 + -9.8468907177448273e-002 + <_> + + <_> + + + + <_> + 10 6 1 3 -1. + <_> + 10 7 1 1 3. + 0 + -4.8408531583845615e-003 + -5.3094178438186646e-001 + 3.1446449458599091e-002 + <_> + + <_> + + + + <_> + 0 0 3 2 -1. + <_> + 0 1 3 1 2. + 0 + 4.5861881226301193e-003 + -1.6896879673004150e-001 + 1.9897870719432831e-001 + <_> + + <_> + + + + <_> + 11 16 1 4 -1. + <_> + 11 17 1 2 2. + 0 + 1.3223010115325451e-002 + 2.6502050459384918e-002 + -6.1782538890838623e-001 + <_> + + <_> + + + + <_> + 0 16 1 4 -1. + <_> + 0 17 1 2 2. + 0 + -1.3310019858181477e-003 + -3.7018761038780212e-001 + 8.9922286570072174e-002 + <_> + + <_> + + + + <_> + 11 16 1 3 -1. + <_> + 11 17 1 1 3. + 0 + -1.4923400012776256e-003 + -3.2771658897399902e-001 + 6.3753470778465271e-002 + <_> + + <_> + + + + <_> + 0 16 1 3 -1. + <_> + 0 17 1 1 3. + 0 + 2.3128539323806763e-003 + 5.8098889887332916e-002 + -5.7217907905578613e-001 + <_> + + <_> + + + + <_> + 6 8 2 3 -1. + <_> + 5 9 2 1 3. + 1 + -3.9470911026000977e-002 + -5.9376251697540283e-001 + 2.4938920978456736e-003 + <_> + + <_> + + + + <_> + 6 8 3 2 -1. + <_> + 7 9 1 2 3. + 1 + 1.1061299592256546e-002 + -9.7631797194480896e-002 + 3.4335118532180786e-001 + <_> + + <_> + + + + <_> + 8 14 2 2 -1. + <_> + 9 14 1 1 2. + <_> + 8 15 1 1 2. + 0 + 1.7588209593668580e-003 + -3.3723760396242142e-002 + 1.8667000532150269e-001 + -1.3936669826507568e+000 + 16 + -1 + <_> + + + <_> + + <_> + + + + <_> + 3 6 5 3 -1. + <_> + 3 7 5 1 3. + 0 + -4.3175318278372288e-003 + 2.6701891422271729e-001 + -3.5374870896339417e-001 + <_> + + <_> + + + + <_> + 9 0 1 3 -1. + <_> + 9 1 1 1 3. + 0 + 1.3007350265979767e-002 + 8.7024876847863197e-003 + -7.5992470979690552e-001 + <_> + + <_> + + + + <_> + 2 0 1 3 -1. + <_> + 2 1 1 1 3. + 0 + 4.8762829974293709e-003 + -2.0284099876880646e-001 + 4.1433459520339966e-001 + <_> + + <_> + + + + <_> + 8 5 4 11 -1. + <_> + 8 5 2 11 2. + 0 + -1.0705440305173397e-002 + 2.0144259929656982e-001 + -2.9292601346969604e-001 + <_> + + <_> + + + + <_> + 1 15 4 2 -1. + <_> + 1 15 2 1 2. + <_> + 3 16 2 1 2. + 0 + -4.4717481359839439e-003 + 2.9785239696502686e-001 + -2.1515479683876038e-001 + <_> + + <_> + + + + <_> + 7 3 3 10 -1. + <_> + 8 3 1 10 3. + 0 + -1.0971710085868835e-001 + -9.0043932199478149e-001 + 4.1688669472932816e-002 + <_> + + <_> + + + + <_> + 2 3 3 10 -1. + <_> + 3 3 1 10 3. + 0 + 2.4193130433559418e-002 + -1.7109879851341248e-001 + 3.1211599707603455e-001 + <_> + + <_> + + + + <_> + 8 13 3 2 -1. + <_> + 9 14 1 2 3. + 1 + 2.4174679070711136e-002 + 2.8407519683241844e-002 + -5.3422790765762329e-001 + <_> + + <_> + + + + <_> + 4 13 2 3 -1. + <_> + 3 14 2 1 3. + 1 + 2.1222220733761787e-002 + -1.1979670077562332e-001 + 4.4222798943519592e-001 + <_> + + <_> + + + + <_> + 0 1 12 6 -1. + <_> + 0 4 12 3 2. + 0 + 2.6180870831012726e-002 + -5.3708368539810181e-001 + 8.5554197430610657e-002 + <_> + + <_> + + + + <_> + 1 6 2 4 -1. + <_> + 1 7 2 2 2. + 0 + -4.6309800818562508e-003 + -6.3450610637664795e-001 + 7.8415229916572571e-002 + <_> + + <_> + + + + <_> + 10 4 2 3 -1. + <_> + 10 5 2 1 3. + 0 + -6.1208908446133137e-003 + -5.8184450864791870e-001 + 5.6262150406837463e-002 + <_> + + <_> + + + + <_> + 3 0 6 2 -1. + <_> + 3 0 3 1 2. + <_> + 6 1 3 1 2. + 0 + 2.4345550686120987e-002 + -8.2362763583660126e-002 + 5.2085632085800171e-001 + <_> + + <_> + + + + <_> + 7 0 3 3 -1. + <_> + 8 0 1 3 3. + 0 + -1.0590479709208012e-002 + -5.8450412750244141e-001 + 3.7550948560237885e-002 + <_> + + <_> + + + + <_> + 2 0 3 3 -1. + <_> + 3 0 1 3 3. + 0 + -8.4336008876562119e-003 + -7.2815698385238647e-001 + 4.3281048536300659e-002 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 5 5 3 1 3. + 1 + 2.5999199599027634e-002 + 2.3103030398488045e-002 + -4.7821858525276184e-001 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 7 5 1 3 3. + 1 + 2.5073610246181488e-002 + -1.0790230333805084e-001 + 3.5499471426010132e-001 + <_> + + <_> + + + + <_> + 4 2 8 16 -1. + <_> + 8 2 4 8 2. + <_> + 4 10 4 8 2. + 0 + 2.9070028662681580e-001 + 6.3703400082886219e-003 + -8.6412417888641357e-001 + <_> + + <_> + + + + <_> + 0 2 8 16 -1. + <_> + 0 2 4 8 2. + <_> + 4 10 4 8 2. + 0 + 1.7590269446372986e-001 + -2.5589939951896667e-001 + 1.6987270116806030e-001 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 6 13 3 1 2. + 1 + -3.2584410160779953e-002 + -6.2721168994903564e-001 + 1.8344789743423462e-002 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 6 13 1 3 2. + 1 + -4.1382450610399246e-002 + 5.4475349187850952e-001 + -1.0436189919710159e-001 + <_> + + <_> + + + + <_> + 10 9 2 7 -1. + <_> + 10 9 1 7 2. + 0 + -8.6197769269347191e-003 + 1.4069239795207977e-001 + -4.0490731596946716e-002 + <_> + + <_> + + + + <_> + 3 18 1 2 -1. + <_> + 3 19 1 1 2. + 0 + 2.0080020185559988e-003 + 9.3814283609390259e-002 + -4.5978298783302307e-001 + <_> + + <_> + + + + <_> + 2 18 8 2 -1. + <_> + 6 18 4 1 2. + <_> + 2 19 4 1 2. + 0 + 1.1478760279715061e-002 + -2.3005740344524384e-001 + 1.8548269569873810e-001 + <_> + + <_> + + + + <_> + 4 5 4 3 -1. + <_> + 4 6 4 1 3. + 0 + -9.1993194073438644e-003 + 4.3196168541908264e-001 + -8.4990806877613068e-002 + <_> + + <_> + + + + <_> + 4 4 4 2 -1. + <_> + 4 5 4 1 2. + 0 + 3.2873731106519699e-004 + -3.2470309734344482e-001 + 1.2502589821815491e-001 + <_> + + <_> + + + + <_> + 0 9 2 9 -1. + <_> + 1 9 1 9 2. + 0 + 1.6286820173263550e-002 + -1.6808439791202545e-001 + 2.0208799839019775e-001 + <_> + + <_> + + + + <_> + 8 13 2 2 -1. + <_> + 9 13 1 1 2. + <_> + 8 14 1 1 2. + 0 + -8.8326708646491170e-004 + 1.3341540098190308e-001 + -8.0567203462123871e-002 + <_> + + <_> + + + + <_> + 2 13 2 2 -1. + <_> + 2 13 1 1 2. + <_> + 3 14 1 1 2. + 0 + -2.2098519839346409e-003 + 3.2481029629707336e-001 + -1.1913210153579712e-001 + <_> + + <_> + + + + <_> + 11 0 1 12 -1. + <_> + 11 6 1 6 2. + 0 + 3.3911340869963169e-003 + -6.4360022544860840e-001 + 9.3070819973945618e-002 + <_> + + <_> + + + + <_> + 4 5 8 4 -1. + <_> + 6 7 4 4 2. + 1 + -2.1501209586858749e-002 + 1.2166000157594681e-001 + -2.8132438659667969e-001 + <_> + + <_> + + + + <_> + 8 10 3 3 -1. + <_> + 7 11 3 1 3. + 1 + 1.3594830408692360e-002 + -7.4954092502593994e-002 + 1.1320699751377106e-001 + <_> + + <_> + + + + <_> + 4 0 3 2 -1. + <_> + 5 0 1 2 3. + 0 + -5.9626200236380100e-003 + -6.0876357555389404e-001 + 5.5802300572395325e-002 + <_> + + <_> + + + + <_> + 9 11 3 3 -1. + <_> + 9 12 3 1 3. + 0 + -7.1367057971656322e-003 + 1.3753290474414825e-001 + -5.4944049566984177e-002 + <_> + + <_> + + + + <_> + 3 14 2 2 -1. + <_> + 3 14 1 1 2. + <_> + 4 15 1 1 2. + 0 + 3.7937159650027752e-003 + -9.7331270575523376e-002 + 3.5290411114692688e-001 + <_> + + <_> + + + + <_> + 0 13 12 7 -1. + <_> + 0 13 6 7 2. + 0 + 4.2037001252174377e-001 + -6.0830309987068176e-002 + 6.2353998422622681e-001 + <_> + + <_> + + + + <_> + 0 0 2 1 -1. + <_> + 1 0 1 1 2. + 0 + -1.3953109737485647e-003 + -4.5005550980567932e-001 + 8.5933342576026917e-002 + <_> + + <_> + + + + <_> + 10 1 2 2 -1. + <_> + 11 1 1 1 2. + <_> + 10 2 1 1 2. + 0 + -9.1760727809742093e-004 + -2.7361738681793213e-001 + 4.9933131784200668e-002 + <_> + + <_> + + + + <_> + 0 1 2 2 -1. + <_> + 0 1 1 1 2. + <_> + 1 2 1 1 2. + 0 + 2.6983609423041344e-003 + -9.6326000988483429e-002 + 4.4493889808654785e-001 + <_> + + <_> + + + + <_> + 10 1 2 2 -1. + <_> + 11 1 1 1 2. + <_> + 10 2 1 1 2. + 0 + 1.8104390474036336e-003 + 5.8886051177978516e-002 + -2.8511041402816772e-001 + <_> + + <_> + + + + <_> + 0 1 2 2 -1. + <_> + 0 1 1 1 2. + <_> + 1 2 1 1 2. + 0 + -5.2683739922940731e-003 + 5.0250577926635742e-001 + -1.0216759890317917e-001 + <_> + + <_> + + + + <_> + 10 5 1 3 -1. + <_> + 10 6 1 1 3. + 0 + 3.4583848901093006e-003 + 5.8127861469984055e-002 + -5.9851872920989990e-001 + <_> + + <_> + + + + <_> + 1 5 1 3 -1. + <_> + 1 6 1 1 3. + 0 + -3.5791560076177120e-003 + -7.3496657609939575e-001 + 4.1422609239816666e-002 + <_> + + <_> + + + + <_> + 6 0 2 3 -1. + <_> + 6 1 2 1 3. + 0 + 5.1315352320671082e-003 + -9.3608200550079346e-002 + 1.7093980312347412e-001 + <_> + + <_> + + + + <_> + 4 2 8 1 -1. + <_> + 4 2 4 1 2. + 1 + -4.2571019381284714e-002 + 4.8374500870704651e-001 + -7.8032270073890686e-002 + <_> + + <_> + + + + <_> + 8 8 4 3 -1. + <_> + 8 9 4 1 3. + 0 + -1.4648390002548695e-002 + -4.8706358671188354e-001 + 2.5201629847288132e-002 + <_> + + <_> + + + + <_> + 0 8 4 3 -1. + <_> + 0 9 4 1 3. + 0 + 9.3548959121108055e-003 + 3.9141140878200531e-002 + -8.5132300853729248e-001 + <_> + + <_> + + + + <_> + 8 9 3 2 -1. + <_> + 9 9 1 2 3. + 0 + -7.7046807855367661e-003 + 2.7295690774917603e-001 + -1.0840819776058197e-001 + <_> + + <_> + + + + <_> + 4 9 3 9 -1. + <_> + 5 12 1 3 9. + 0 + -6.4468376338481903e-002 + -8.0510532855987549e-001 + 4.7053340822458267e-002 + <_> + + <_> + + + + <_> + 7 9 3 2 -1. + <_> + 8 9 1 2 3. + 0 + -7.9486463218927383e-003 + 3.0840569734573364e-001 + -1.3387249410152435e-001 + <_> + + <_> + + + + <_> + 2 9 3 2 -1. + <_> + 3 9 1 2 3. + 0 + -3.9265598170459270e-003 + 3.6305388808250427e-001 + -1.0540190339088440e-001 + <_> + + <_> + + + + <_> + 9 6 3 1 -1. + <_> + 10 7 1 1 3. + 1 + -3.6044888198375702e-002 + 5.8140981197357178e-001 + -2.9684588662348688e-004 + <_> + + <_> + + + + <_> + 3 6 1 3 -1. + <_> + 2 7 1 1 3. + 1 + -7.6920147985219955e-003 + 3.3190870285034180e-001 + -1.0925249755382538e-001 + -1.3580759763717651e+000 + 17 + -1 + <_> + + + <_> + + <_> + + + + <_> + 3 2 4 2 -1. + <_> + 3 2 2 1 2. + <_> + 5 3 2 1 2. + 0 + -4.9766711890697479e-003 + 3.7934410572052002e-001 + -2.4959290027618408e-001 + <_> + + <_> + + + + <_> + 6 3 4 3 -1. + <_> + 5 4 4 1 3. + 1 + -3.4589890390634537e-002 + -4.4946050643920898e-001 + 3.9635330438613892e-002 + <_> + + <_> + + + + <_> + 6 3 3 4 -1. + <_> + 7 4 1 4 3. + 1 + 1.9461639225482941e-002 + -2.6357260346412659e-001 + 2.7247101068496704e-001 + <_> + + <_> + + + + <_> + 8 0 4 16 -1. + <_> + 8 0 2 16 2. + 0 + 4.2663760483264923e-002 + 2.9581360518932343e-002 + -3.4751391410827637e-001 + <_> + + <_> + + + + <_> + 0 13 12 4 -1. + <_> + 3 13 6 4 2. + 0 + 5.8530770242214203e-002 + -3.0708679556846619e-001 + 2.0082889497280121e-001 + <_> + + <_> + + + + <_> + 9 0 3 2 -1. + <_> + 9 1 3 1 2. + 0 + -2.9736598953604698e-003 + -5.4576981067657471e-001 + 2.3220159113407135e-002 + <_> + + <_> + + + + <_> + 2 0 2 3 -1. + <_> + 2 1 2 1 3. + 0 + 7.7464492060244083e-003 + -1.4597670733928680e-001 + 3.5159158706665039e-001 + <_> + + <_> + + + + <_> + 3 0 6 1 -1. + <_> + 3 0 3 1 2. + 0 + 7.0320582017302513e-004 + -3.5477969050407410e-001 + 1.4947199821472168e-001 + <_> + + <_> + + + + <_> + 3 0 2 3 -1. + <_> + 3 1 2 1 3. + 0 + -1.3183569535613060e-002 + 4.9795240163803101e-001 + -9.5576412975788116e-002 + <_> + + <_> + + + + <_> + 9 4 3 3 -1. + <_> + 9 5 3 1 3. + 0 + 1.1360269971191883e-002 + 4.4859439134597778e-002 + -7.7702391147613525e-001 + <_> + + <_> + + + + <_> + 0 4 3 3 -1. + <_> + 0 5 3 1 3. + 0 + -5.3752749226987362e-003 + -6.0436600446701050e-001 + 6.3452452421188354e-002 + <_> + + <_> + + + + <_> + 8 11 2 2 -1. + <_> + 9 11 1 1 2. + <_> + 8 12 1 1 2. + 0 + 2.6277059223502874e-003 + -5.9781100600957870e-002 + 1.6431820392608643e-001 + <_> + + <_> + + + + <_> + 2 11 2 2 -1. + <_> + 2 11 1 1 2. + <_> + 3 12 1 1 2. + 0 + -1.9063310464844108e-003 + 3.4500768780708313e-001 + -1.1078260093927383e-001 + <_> + + <_> + + + + <_> + 9 10 1 8 -1. + <_> + 7 12 1 4 2. + 1 + -5.5438909679651260e-002 + 5.3140318393707275e-001 + -3.9117269217967987e-002 + <_> + + <_> + + + + <_> + 1 3 3 8 -1. + <_> + 2 3 1 8 3. + 0 + 2.2990850731730461e-002 + -1.1105979979038239e-001 + 3.4139779210090637e-001 + <_> + + <_> + + + + <_> + 8 8 2 4 -1. + <_> + 8 10 2 2 2. + 0 + 2.3013869300484657e-002 + 1.9403599202632904e-002 + -3.0652850866317749e-001 + <_> + + <_> + + + + <_> + 2 15 3 4 -1. + <_> + 2 16 3 2 2. + 0 + -3.2346909865736961e-003 + 1.8446859717369080e-001 + -2.1846550703048706e-001 + <_> + + <_> + + + + <_> + 8 4 3 6 -1. + <_> + 9 4 1 6 3. + 0 + 1.9735300447791815e-003 + -6.4886763691902161e-002 + 6.2509037554264069e-002 + <_> + + <_> + + + + <_> + 1 4 3 6 -1. + <_> + 2 4 1 6 3. + 0 + -1.0755480267107487e-002 + 3.5955241322517395e-001 + -1.1030949652194977e-001 + <_> + + <_> + + + + <_> + 8 12 2 3 -1. + <_> + 7 13 2 1 3. + 1 + -2.6936439797282219e-002 + -7.0569419860839844e-001 + 1.5028079971671104e-002 + <_> + + <_> + + + + <_> + 3 10 8 1 -1. + <_> + 5 12 4 1 2. + 1 + 2.8886420652270317e-002 + 5.0576541572809219e-002 + -7.2815430164337158e-001 + <_> + + <_> + + + + <_> + 8 15 1 3 -1. + <_> + 7 16 1 1 3. + 1 + 5.7200351729989052e-003 + -1.0274200141429901e-001 + 8.0553196370601654e-002 + <_> + + <_> + + + + <_> + 0 16 6 3 -1. + <_> + 0 17 6 1 3. + 0 + -1.7981380224227905e-002 + -7.0609301328659058e-001 + 5.8095961809158325e-002 + <_> + + <_> + + + + <_> + 8 12 2 2 -1. + <_> + 9 12 1 1 2. + <_> + 8 13 1 1 2. + 0 + 1.6353320097550750e-003 + -9.0820826590061188e-002 + 1.2195230275392532e-001 + <_> + + <_> + + + + <_> + 2 12 2 2 -1. + <_> + 2 12 1 1 2. + <_> + 3 13 1 1 2. + 0 + -1.8810540204867721e-003 + 3.1368181109428406e-001 + -1.1835079640150070e-001 + <_> + + <_> + + + + <_> + 9 12 1 3 -1. + <_> + 8 13 1 1 3. + 1 + -1.6305189579725266e-002 + -3.4470620751380920e-001 + 1.0644529946148396e-002 + <_> + + <_> + + + + <_> + 3 11 2 2 -1. + <_> + 3 11 1 1 2. + <_> + 4 12 1 1 2. + 0 + -1.6981370281428099e-003 + 3.6481419205665588e-001 + -1.0638120025396347e-001 + <_> + + <_> + + + + <_> + 8 15 1 3 -1. + <_> + 7 16 1 1 3. + 1 + 2.1174369379878044e-002 + 3.1025370582938194e-002 + -2.7620419859886169e-001 + <_> + + <_> + + + + <_> + 3 12 3 1 -1. + <_> + 4 13 1 1 3. + 1 + -8.8443253189325333e-003 + -6.9870138168334961e-001 + 5.1486968994140625e-002 + <_> + + <_> + + + + <_> + 9 12 2 3 -1. + <_> + 8 13 2 1 3. + 1 + 3.6929589696228504e-003 + -6.5479710698127747e-002 + 2.2728489711880684e-002 + <_> + + <_> + + + + <_> + 3 12 3 2 -1. + <_> + 4 13 1 2 3. + 1 + 1.0892639867961407e-002 + 6.1733219772577286e-002 + -6.7477071285247803e-001 + <_> + + <_> + + + + <_> + 6 9 2 6 -1. + <_> + 6 9 2 3 2. + 1 + -1.2833529710769653e-001 + 2.1409809589385986e-001 + -3.3962771296501160e-002 + <_> + + <_> + + + + <_> + 0 14 12 6 -1. + <_> + 0 17 12 3 2. + 0 + -5.1236700266599655e-002 + 1.5942020714282990e-001 + -2.4341639876365662e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + 1.2321960180997849e-001 + 2.5586610659956932e-002 + -4.7473230957984924e-001 + <_> + + <_> + + + + <_> + 4 5 2 3 -1. + <_> + 5 5 1 3 2. + 0 + -1.9274000078439713e-003 + 1.0943879932165146e-001 + -3.3568400144577026e-001 + <_> + + <_> + + + + <_> + 6 5 2 3 -1. + <_> + 5 6 2 1 3. + 1 + -2.0102979615330696e-002 + -5.1650160551071167e-001 + 2.9315050691366196e-002 + <_> + + <_> + + + + <_> + 6 5 3 2 -1. + <_> + 7 6 1 2 3. + 1 + 1.8281549215316772e-002 + -6.4036741852760315e-002 + 6.2557631731033325e-001 + <_> + + <_> + + + + <_> + 4 8 5 2 -1. + <_> + 4 9 5 1 2. + 0 + 1.4739660546183586e-003 + -1.6827440261840820e-001 + 1.0941269993782043e-001 + <_> + + <_> + + + + <_> + 0 4 3 5 -1. + <_> + 1 4 1 5 3. + 0 + -9.0881707146763802e-003 + 2.4175269901752472e-001 + -1.4523309469223022e-001 + <_> + + <_> + + + + <_> + 9 2 3 8 -1. + <_> + 10 2 1 8 3. + 0 + -4.5073218643665314e-002 + -7.3592007160186768e-001 + 5.9004039503633976e-003 + <_> + + <_> + + + + <_> + 0 2 3 8 -1. + <_> + 1 2 1 8 3. + 0 + 1.9067279994487762e-002 + -1.0756839811801910e-001 + 3.3758550882339478e-001 + <_> + + <_> + + + + <_> + 6 9 2 6 -1. + <_> + 6 9 2 3 2. + 1 + -9.0190932154655457e-002 + 3.0061250925064087e-001 + -4.3286528438329697e-002 + <_> + + <_> + + + + <_> + 6 9 6 5 -1. + <_> + 6 9 3 5 2. + 1 + -2.4107230827212334e-002 + 1.4867919683456421e-001 + -2.2179369628429413e-001 + <_> + + <_> + + + + <_> + 11 0 1 12 -1. + <_> + 11 6 1 6 2. + 0 + 4.2285379022359848e-002 + -2.0657710731029510e-001 + 2.4372029304504395e-001 + <_> + + <_> + + + + <_> + 6 1 6 1 -1. + <_> + 8 3 2 1 3. + 1 + -1.9224429503083229e-002 + -4.1109448671340942e-001 + 8.8076941668987274e-002 + <_> + + <_> + + + + <_> + 8 12 1 3 -1. + <_> + 7 13 1 1 3. + 1 + -1.8713049590587616e-002 + -5.5512428283691406e-001 + -3.5010900319321081e-005 + <_> + + <_> + + + + <_> + 4 12 3 1 -1. + <_> + 5 13 1 1 3. + 1 + -1.1740639805793762e-002 + -7.4573528766632080e-001 + 4.6473011374473572e-002 + <_> + + <_> + + + + <_> + 7 2 2 18 -1. + <_> + 7 2 1 18 2. + 0 + 3.5142578184604645e-002 + 2.7216039597988129e-003 + -4.9953749775886536e-001 + <_> + + <_> + + + + <_> + 3 2 2 18 -1. + <_> + 4 2 1 18 2. + 0 + -6.6481479443609715e-003 + 1.9559350609779358e-001 + -1.6296459734439850e-001 + <_> + + <_> + + + + <_> + 8 15 1 3 -1. + <_> + 7 16 1 1 3. + 1 + 7.3291230946779251e-003 + -5.7543341070413589e-002 + 8.1424511969089508e-002 + <_> + + <_> + + + + <_> + 4 15 3 1 -1. + <_> + 5 16 1 1 3. + 1 + -5.4579051211476326e-003 + -5.4347038269042969e-001 + 5.7771220803260803e-002 + <_> + + <_> + + + + <_> + 7 14 2 2 -1. + <_> + 8 14 1 1 2. + <_> + 7 15 1 1 2. + 0 + 1.0465289960848168e-004 + -1.1724419891834259e-001 + 1.3367609679698944e-001 + <_> + + <_> + + + + <_> + 3 14 2 2 -1. + <_> + 3 14 1 1 2. + <_> + 4 15 1 1 2. + 0 + -1.7040430102497339e-003 + 3.2203149795532227e-001 + -1.0900110006332397e-001 + <_> + + <_> + + + + <_> + 5 5 2 3 -1. + <_> + 5 6 2 1 3. + 0 + -7.5647421181201935e-003 + 4.4239428639411926e-001 + -6.8382248282432556e-002 + <_> + + <_> + + + + <_> + 6 4 3 2 -1. + <_> + 7 5 1 2 3. + 1 + 8.0183129757642746e-003 + -1.5239569544792175e-001 + 2.4483230710029602e-001 + <_> + + <_> + + + + <_> + 6 0 3 2 -1. + <_> + 7 0 1 2 3. + 0 + -1.0649990290403366e-002 + -6.2405461072921753e-001 + 2.1711019799113274e-002 + <_> + + <_> + + + + <_> + 6 7 2 2 -1. + <_> + 6 7 2 1 2. + 1 + -1.4240309828892350e-003 + 8.9519590139389038e-002 + -3.5850891470909119e-001 + <_> + + <_> + + + + <_> + 11 0 1 12 -1. + <_> + 11 6 1 6 2. + 0 + 5.9712692163884640e-003 + -4.6914869546890259e-001 + 5.2607439458370209e-002 + <_> + + <_> + + + + <_> + 6 6 4 2 -1. + <_> + 7 7 2 2 2. + 1 + 1.6963120549917221e-002 + -6.1023771762847900e-002 + 5.7392549514770508e-001 + <_> + + <_> + + + + <_> + 6 0 3 2 -1. + <_> + 7 0 1 2 3. + 0 + 7.1414969861507416e-003 + 2.8966020792722702e-002 + -3.2176148891448975e-001 + <_> + + <_> + + + + <_> + 3 0 3 3 -1. + <_> + 4 0 1 3 3. + 0 + -9.5924977213144302e-003 + -7.2410070896148682e-001 + 4.0414128452539444e-002 + <_> + + <_> + + + + <_> + 11 4 1 3 -1. + <_> + 11 5 1 1 3. + 0 + -4.1343858465552330e-003 + -6.6965389251708984e-001 + 3.3574569970369339e-002 + <_> + + <_> + + + + <_> + 1 7 2 2 -1. + <_> + 1 8 2 1 2. + 0 + -4.4302479363977909e-003 + -6.3991087675094604e-001 + 3.9288960397243500e-002 + <_> + + <_> + + + + <_> + 9 1 1 6 -1. + <_> + 9 1 1 3 2. + 1 + -2.6460499502718449e-003 + 1.0181919671595097e-002 + -1.8428249657154083e-001 + <_> + + <_> + + + + <_> + 3 1 6 1 -1. + <_> + 3 1 3 1 2. + 1 + -3.3010810613632202e-002 + -6.4822387695312500e-001 + 4.6115010976791382e-002 + -1.3411600589752197e+000 + 18 + -1 + diff --git a/data/haarcascades/haarcascade_mcs_rightear.xml b/data/haarcascades/haarcascade_mcs_rightear.xml new file mode 100644 index 0000000000..eaf17b0d22 --- /dev/null +++ b/data/haarcascades/haarcascade_mcs_rightear.xml @@ -0,0 +1,9671 @@ + + + + + + 12 20 + + <_> + + + <_> + + <_> + + + + <_> + 2 7 8 12 -1. + <_> + 2 7 4 6 2. + <_> + 6 13 4 6 2. + 0 + -1.2393590062856674e-001 + 8.2578802108764648e-001 + -6.7602032423019409e-001 + <_> + + <_> + + + + <_> + 3 7 8 2 -1. + <_> + 5 7 4 2 2. + 0 + 9.4228880479931831e-003 + -1.2722210586071014e-001 + 3.3211699128150940e-001 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 5 5 3 2 2. + 1 + -1.1084940284490585e-002 + 5.6749510765075684e-001 + -5.6716197729110718e-001 + <_> + + <_> + + + + <_> + 4 0 8 18 -1. + <_> + 4 9 8 9 2. + 0 + -2.0189690589904785e-001 + -7.6717972755432129e-001 + 1.9637049734592438e-001 + <_> + + <_> + + + + <_> + 0 18 3 2 -1. + <_> + 0 19 3 1 2. + 0 + -4.7402849304489791e-005 + 3.8455748558044434e-001 + -6.7010718584060669e-001 + <_> + + <_> + + + + <_> + 11 0 1 10 -1. + <_> + 11 5 1 5 2. + 0 + -8.6445426568388939e-003 + -6.9345837831497192e-001 + 1.0593380033969879e-001 + <_> + + <_> + + + + <_> + 0 0 10 1 -1. + <_> + 5 0 5 1 2. + 0 + 5.0770420784829184e-005 + -6.8352818489074707e-001 + 3.5795739293098450e-001 + -1.3802499771118164e+000 + -1 + -1 + <_> + + + <_> + + <_> + + + + <_> + 2 5 8 14 -1. + <_> + 2 5 4 7 2. + <_> + 6 12 4 7 2. + 0 + -1.8316349387168884e-001 + 7.8830862045288086e-001 + -5.8876812458038330e-001 + <_> + + <_> + + + + <_> + 0 0 12 8 -1. + <_> + 0 4 12 4 2. + 0 + 2.5380790233612061e-002 + -7.4764448404312134e-001 + 4.1486009955406189e-001 + <_> + + <_> + + + + <_> + 2 7 6 10 -1. + <_> + 2 12 6 5 2. + 0 + 1.4207419939339161e-002 + -7.8411531448364258e-001 + 2.7354270219802856e-001 + <_> + + <_> + + + + <_> + 8 2 4 8 -1. + <_> + 10 2 2 4 2. + <_> + 8 6 2 4 2. + 0 + 8.6809601634740829e-003 + -1.0974329710006714e-001 + 9.4718709588050842e-002 + <_> + + <_> + + + + <_> + 0 2 4 8 -1. + <_> + 0 2 2 4 2. + <_> + 2 6 2 4 2. + 0 + -4.1219559498131275e-003 + 3.1739580631256104e-001 + -5.4334312677383423e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 6 18 6 1 2. + <_> + 0 19 6 1 2. + 0 + -1.1700070463120937e-002 + 3.9653539657592773e-001 + -3.7434050440788269e-001 + <_> + + <_> + + + + <_> + 0 14 12 6 -1. + <_> + 6 14 6 6 2. + 0 + 2.8762829303741455e-001 + -1.7733460664749146e-001 + 8.8516682386398315e-001 + <_> + + <_> + + + + <_> + 6 12 2 6 -1. + <_> + 6 12 2 3 2. + 1 + -4.8463501036167145e-002 + -6.0947227478027344e-001 + 1.3633400201797485e-001 + <_> + + <_> + + + + <_> + 6 12 6 2 -1. + <_> + 6 12 3 2 2. + 1 + 7.6523773372173309e-002 + -2.9950559139251709e-001 + 6.1522072553634644e-001 + -1.4652169942855835e+000 + 0 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 8 6 6 -1. + <_> + 8 10 2 6 3. + 1 + 1.1777380108833313e-001 + -5.8754861354827881e-001 + 6.1994218826293945e-001 + <_> + + <_> + + + + <_> + 3 6 9 3 -1. + <_> + 6 7 3 1 9. + 0 + 2.9533330351114273e-002 + -4.2420691251754761e-001 + 3.6524820327758789e-001 + <_> + + <_> + + + + <_> + 0 0 1 12 -1. + <_> + 0 6 1 6 2. + 0 + 6.1603458598256111e-003 + -7.9607379436492920e-001 + 3.2861700654029846e-001 + <_> + + <_> + + + + <_> + 6 2 4 5 -1. + <_> + 6 2 2 5 2. + 1 + -5.9753831010311842e-005 + 1.0398519784212112e-001 + -4.5819509029388428e-001 + <_> + + <_> + + + + <_> + 4 5 4 4 -1. + <_> + 4 7 4 2 2. + 0 + -3.6190438549965620e-004 + 5.3506380319595337e-001 + -6.4719748497009277e-001 + <_> + + <_> + + + + <_> + 8 0 4 4 -1. + <_> + 8 2 4 2 2. + 0 + 2.0906500518321991e-002 + -1.6793949902057648e-001 + 2.4539050459861755e-001 + <_> + + <_> + + + + <_> + 3 0 3 20 -1. + <_> + 3 10 3 10 2. + 0 + 8.2527771592140198e-003 + -8.5986042022705078e-001 + 2.2863869369029999e-001 + <_> + + <_> + + + + <_> + 9 16 3 4 -1. + <_> + 9 17 3 2 2. + 0 + 5.9341029264032841e-003 + -4.6319939196109772e-002 + -6.0758531093597412e-001 + <_> + + <_> + + + + <_> + 0 0 4 4 -1. + <_> + 0 2 4 2 2. + 0 + 1.8554080452304333e-004 + -5.7996147871017456e-001 + 3.7694430351257324e-001 + <_> + + <_> + + + + <_> + 9 16 3 4 -1. + <_> + 9 17 3 2 2. + 0 + -7.2531788609921932e-003 + -5.6681227684020996e-001 + -1.9910290837287903e-002 + <_> + + <_> + + + + <_> + 0 16 3 4 -1. + <_> + 0 17 3 2 2. + 0 + 4.0826769691193476e-005 + -6.2813758850097656e-001 + 4.0546119213104248e-001 + <_> + + <_> + + + + <_> + 3 7 8 1 -1. + <_> + 5 7 4 1 2. + 0 + -1.0268500074744225e-002 + 4.5032399892807007e-001 + -2.7399060130119324e-001 + <_> + + <_> + + + + <_> + 0 4 9 6 -1. + <_> + 3 6 3 2 9. + 0 + -3.5408639814704657e-003 + 3.4393149614334106e-001 + -6.7639619112014771e-001 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 8 15 2 1 3. + 1 + -6.9421626627445221e-002 + 6.5173202753067017e-001 + -7.4326410889625549e-002 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 4 15 1 2 3. + 1 + 7.1986039984039962e-005 + -4.5737218856811523e-001 + 3.0109271407127380e-001 + <_> + + <_> + + + + <_> + 2 3 9 2 -1. + <_> + 2 4 9 1 2. + 0 + 6.3741732446942478e-005 + -5.5820369720458984e-001 + 1.9148319959640503e-001 + <_> + + <_> + + + + <_> + 0 6 1 4 -1. + <_> + 0 8 1 2 2. + 0 + 4.4920871005160734e-005 + -5.7379388809204102e-001 + 2.1276189386844635e-001 + <_> + + <_> + + + + <_> + 4 8 7 10 -1. + <_> + 4 13 7 5 2. + 0 + 1.3159319758415222e-001 + -2.2754240036010742e-001 + 2.8766331076622009e-001 + -2.0372869968414307e+000 + 1 + -1 + <_> + + + <_> + + <_> + + + + <_> + 2 7 8 12 -1. + <_> + 2 7 4 6 2. + <_> + 6 13 4 6 2. + 0 + -1.5496319532394409e-001 + 7.2985649108886719e-001 + -5.9489607810974121e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 7 6 1 3 3. + 1 + 8.4833214059472084e-003 + 1.3606220483779907e-001 + -4.3773031234741211e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 5 6 3 1 3. + 1 + -3.2831680029630661e-002 + 6.7158091068267822e-001 + -2.8739199042320251e-001 + <_> + + <_> + + + + <_> + 5 16 4 4 -1. + <_> + 5 18 4 2 2. + 0 + -2.8853790834546089e-002 + 4.5923650264739990e-001 + -4.9327030777931213e-002 + <_> + + <_> + + + + <_> + 0 17 12 3 -1. + <_> + 6 17 6 3 2. + 0 + 1.7052419483661652e-001 + -1.6527549922466278e-001 + 8.4507262706756592e-001 + <_> + + <_> + + + + <_> + 0 15 12 3 -1. + <_> + 0 15 6 3 2. + 0 + 1.0879129916429520e-001 + -2.8913050889968872e-001 + 5.3111201524734497e-001 + <_> + + <_> + + + + <_> + 0 0 2 16 -1. + <_> + 0 4 2 8 2. + 0 + 3.0960019212216139e-003 + -5.5323868989944458e-001 + 2.6134639978408813e-001 + <_> + + <_> + + + + <_> + 2 0 8 13 -1. + <_> + 2 0 4 13 2. + 0 + -3.3618099987506866e-002 + 2.2911429405212402e-001 + -5.5924427509307861e-001 + <_> + + <_> + + + + <_> + 0 0 6 2 -1. + <_> + 0 1 6 1 2. + 0 + -1.1074040085077286e-003 + -6.3096380233764648e-001 + 1.5855440497398376e-001 + <_> + + <_> + + + + <_> + 7 18 5 2 -1. + <_> + 7 19 5 1 2. + 0 + -4.4385627843439579e-003 + -6.3817399740219116e-001 + 1.2779480218887329e-001 + <_> + + <_> + + + + <_> + 0 18 5 2 -1. + <_> + 0 19 5 1 2. + 0 + -9.4127003103494644e-003 + 3.5108420252799988e-001 + -3.4738400578498840e-001 + <_> + + <_> + + + + <_> + 6 15 2 3 -1. + <_> + 6 15 1 3 2. + 1 + -3.2499480992555618e-002 + 6.7672997713088989e-001 + -5.5984470993280411e-002 + <_> + + <_> + + + + <_> + 6 15 3 2 -1. + <_> + 6 15 3 1 2. + 1 + -1.3464169576764107e-002 + -7.5412607192993164e-001 + 1.5986099839210510e-001 + -1.5061739683151245e+000 + 2 + -1 + <_> + + + <_> + + <_> + + + + <_> + 2 7 8 12 -1. + <_> + 2 7 4 6 2. + <_> + 6 13 4 6 2. + 0 + -1.8050560355186462e-001 + 7.1835839748382568e-001 + -5.2469527721405029e-001 + <_> + + <_> + + + + <_> + 5 16 4 4 -1. + <_> + 5 18 4 2 2. + 0 + -1.5271560288965702e-002 + 3.2215949892997742e-001 + -1.5855640172958374e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 4 5 6 2 3. + 1 + -3.4879799932241440e-002 + 3.2105189561843872e-001 + -5.3338629007339478e-001 + <_> + + <_> + + + + <_> + 0 16 12 4 -1. + <_> + 6 16 6 2 2. + <_> + 0 18 6 2 2. + 0 + -3.1743600964546204e-002 + 4.1040870547294617e-001 + -3.7935909628868103e-001 + <_> + + <_> + + + + <_> + 0 2 10 4 -1. + <_> + 0 4 10 2 2. + 0 + 4.8427619040012360e-003 + -6.9584208726882935e-001 + 2.4080069363117218e-001 + <_> + + <_> + + + + <_> + 8 9 2 8 -1. + <_> + 6 11 2 4 2. + 1 + 4.9639631062746048e-002 + 8.0581977963447571e-003 + -5.4770648479461670e-001 + <_> + + <_> + + + + <_> + 4 9 8 3 -1. + <_> + 6 11 4 3 2. + 1 + 1.1154930293560028e-001 + -2.4036459624767303e-001 + 5.6387817859649658e-001 + <_> + + <_> + + + + <_> + 6 12 1 6 -1. + <_> + 6 12 1 3 2. + 1 + -2.6947790756821632e-002 + -4.5162969827651978e-001 + 6.0060828924179077e-002 + <_> + + <_> + + + + <_> + 6 12 6 1 -1. + <_> + 6 12 3 1 2. + 1 + -4.9296129494905472e-002 + 8.3912831544876099e-001 + -1.8871270120143890e-001 + <_> + + <_> + + + + <_> + 8 1 4 10 -1. + <_> + 10 1 2 5 2. + <_> + 8 6 2 5 2. + 0 + 2.8315439820289612e-002 + 6.9766468368470669e-003 + 1.8534269928932190e-001 + <_> + + <_> + + + + <_> + 0 0 1 12 -1. + <_> + 0 6 1 6 2. + 0 + 3.3421538770198822e-002 + -3.1101679801940918e-001 + 4.0044930577278137e-001 + <_> + + <_> + + + + <_> + 9 0 2 1 -1. + <_> + 9 0 1 1 2. + 1 + -6.2644667923450470e-003 + -4.4615790247917175e-001 + 6.6276572644710541e-002 + <_> + + <_> + + + + <_> + 3 0 1 2 -1. + <_> + 3 0 1 1 2. + 1 + 2.5548560079187155e-003 + 1.3413320481777191e-001 + -7.4927258491516113e-001 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 7 5 1 3 3. + 1 + 2.9710179194808006e-002 + 6.1377300880849361e-004 + -7.7615362405776978e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 5 6 3 1 3. + 1 + -4.1485700756311417e-002 + 5.9405767917633057e-001 + -1.6889290511608124e-001 + <_> + + <_> + + + + <_> + 10 2 2 3 -1. + <_> + 10 3 2 1 3. + 0 + 1.2231590226292610e-002 + 5.1312480121850967e-002 + -7.5303572416305542e-001 + <_> + + <_> + + + + <_> + 0 2 2 3 -1. + <_> + 0 3 2 1 3. + 0 + -4.3153190053999424e-003 + -6.4812111854553223e-001 + 1.3281610608100891e-001 + -1.5266020298004150e+000 + 3 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 8 8 4 -1. + <_> + 6 10 4 4 2. + 1 + 1.1714699864387512e-001 + -5.1155489683151245e-001 + 5.4587250947952271e-001 + <_> + + <_> + + + + <_> + 3 6 9 3 -1. + <_> + 6 7 3 1 9. + 0 + 5.2537951618432999e-002 + -2.6988661289215088e-001 + 3.4098041057586670e-001 + <_> + + <_> + + + + <_> + 0 1 4 10 -1. + <_> + 0 1 2 5 2. + <_> + 2 6 2 5 2. + 0 + -1.9980749115347862e-002 + 3.5662230849266052e-001 + -4.4640049338340759e-001 + <_> + + <_> + + + + <_> + 3 3 8 17 -1. + <_> + 5 3 4 17 2. + 0 + -1.2166350334882736e-001 + 4.5662569999694824e-001 + -6.7647598683834076e-002 + <_> + + <_> + + + + <_> + 4 0 4 8 -1. + <_> + 6 0 2 8 2. + 0 + 1.6176940873265266e-002 + -4.8407769203186035e-001 + 2.5647491216659546e-001 + <_> + + <_> + + + + <_> + 6 10 6 3 -1. + <_> + 6 10 3 3 2. + 1 + -1.2731030583381653e-001 + 7.8568279743194580e-001 + -7.6182372868061066e-002 + <_> + + <_> + + + + <_> + 0 18 4 2 -1. + <_> + 0 19 4 1 2. + 0 + -3.7296859081834555e-003 + 2.7144059538841248e-001 + -4.8822438716888428e-001 + <_> + + <_> + + + + <_> + 6 10 6 3 -1. + <_> + 6 10 3 3 2. + 1 + -1.7392159998416901e-001 + 7.3156762123107910e-001 + -4.0217950940132141e-002 + <_> + + <_> + + + + <_> + 1 6 9 3 -1. + <_> + 4 7 3 1 9. + 0 + -9.4516716897487640e-002 + 4.9297851324081421e-001 + -2.1850970387458801e-001 + <_> + + <_> + + + + <_> + 6 10 6 3 -1. + <_> + 6 10 3 3 2. + 1 + 7.9759500920772552e-002 + -1.0667549818754196e-001 + 2.1722890436649323e-001 + <_> + + <_> + + + + <_> + 6 10 3 6 -1. + <_> + 6 10 3 3 2. + 1 + 2.9159070923924446e-002 + 1.5513190627098083e-001 + -7.9432719945907593e-001 + <_> + + <_> + + + + <_> + 0 0 12 10 -1. + <_> + 0 5 12 5 2. + 0 + 6.8567609414458275e-003 + -7.7142190933227539e-001 + 1.0970850288867950e-001 + <_> + + <_> + + + + <_> + 2 0 1 2 -1. + <_> + 2 0 1 1 2. + 1 + 2.6352910790592432e-003 + 9.6235923469066620e-002 + -7.4925291538238525e-001 + <_> + + <_> + + + + <_> + 4 5 4 8 -1. + <_> + 4 7 4 4 2. + 0 + -4.1161300614476204e-003 + 1.7448060214519501e-001 + -4.6480000019073486e-001 + <_> + + <_> + + + + <_> + 0 0 2 3 -1. + <_> + 1 0 1 3 2. + 0 + -2.7307260315865278e-003 + -5.8561611175537109e-001 + 1.1779639869928360e-001 + <_> + + <_> + + + + <_> + 0 8 12 4 -1. + <_> + 0 9 12 2 2. + 0 + -1.9059289246797562e-002 + -6.8809962272644043e-001 + 1.0283970087766647e-001 + <_> + + <_> + + + + <_> + 1 3 1 3 -1. + <_> + 1 4 1 1 3. + 0 + -2.9182219877839088e-003 + -6.6901868581771851e-001 + 8.3721928298473358e-002 + -1.4295140504837036e+000 + 4 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 9 8 2 -1. + <_> + 6 11 4 2 2. + 1 + 8.1108748912811279e-002 + -3.9180481433868408e-001 + 5.3625607490539551e-001 + <_> + + <_> + + + + <_> + 5 3 2 6 -1. + <_> + 5 5 2 2 3. + 0 + 9.1598061844706535e-003 + -4.6528929471969604e-001 + 3.3383831381797791e-001 + <_> + + <_> + + + + <_> + 0 0 1 8 -1. + <_> + 0 4 1 4 2. + 0 + 8.0795027315616608e-004 + -7.5230997800827026e-001 + 1.4381100237369537e-001 + <_> + + <_> + + + + <_> + 2 5 8 14 -1. + <_> + 6 5 4 7 2. + <_> + 2 12 4 7 2. + 0 + 2.4406640231609344e-001 + -2.2846619784832001e-001 + 5.0088721513748169e-001 + <_> + + <_> + + + + <_> + 0 6 1 8 -1. + <_> + 0 8 1 4 2. + 0 + 9.9084907560609281e-005 + -4.9552011489868164e-001 + 2.3163549602031708e-001 + <_> + + <_> + + + + <_> + 0 17 12 3 -1. + <_> + 0 17 6 3 2. + 0 + -1.6304260492324829e-001 + 8.0807077884674072e-001 + -1.4503139257431030e-001 + <_> + + <_> + + + + <_> + 4 0 2 3 -1. + <_> + 4 1 2 1 3. + 0 + 9.9489316344261169e-003 + -1.3804569840431213e-001 + 6.0897988080978394e-001 + <_> + + <_> + + + + <_> + 5 12 6 8 -1. + <_> + 5 14 6 4 2. + 0 + 7.6701432466506958e-002 + 3.7772629410028458e-002 + -5.3447282314300537e-001 + <_> + + <_> + + + + <_> + 3 11 4 9 -1. + <_> + 3 14 4 3 3. + 0 + 4.7309949994087219e-002 + -3.6191630363464355e-001 + 2.8269779682159424e-001 + <_> + + <_> + + + + <_> + 2 0 10 16 -1. + <_> + 2 8 10 8 2. + 0 + -2.2022439166903496e-002 + -5.2068692445755005e-001 + 9.4968706369400024e-002 + <_> + + <_> + + + + <_> + 5 15 3 2 -1. + <_> + 5 15 3 1 2. + 1 + 1.3980070129036903e-002 + 1.1217589676380157e-001 + -6.8278092145919800e-001 + <_> + + <_> + + + + <_> + 8 15 4 1 -1. + <_> + 9 16 2 1 2. + 1 + -6.6961131989955902e-002 + 8.7730789184570313e-001 + -2.7844179421663284e-002 + <_> + + <_> + + + + <_> + 4 15 1 4 -1. + <_> + 3 16 1 2 2. + 1 + 1.1592600494623184e-003 + -3.4661638736724854e-001 + 2.0498119294643402e-001 + <_> + + <_> + + + + <_> + 6 14 3 3 -1. + <_> + 7 15 1 3 3. + 1 + 1.9640380516648293e-002 + -1.2608189880847931e-001 + 2.8791791200637817e-001 + <_> + + <_> + + + + <_> + 6 14 3 3 -1. + <_> + 5 15 3 1 3. + 1 + -1.0507949627935886e-002 + -6.1253058910369873e-001 + 1.2488999962806702e-001 + <_> + + <_> + + + + <_> + 3 6 8 2 -1. + <_> + 5 6 4 2 2. + 0 + 1.7976740375161171e-002 + -1.2991739809513092e-001 + 1.4235779643058777e-001 + <_> + + <_> + + + + <_> + 3 2 6 17 -1. + <_> + 5 2 2 17 3. + 0 + -3.1597379595041275e-002 + 3.3326789736747742e-001 + -2.4774129688739777e-001 + <_> + + <_> + + + + <_> + 11 0 1 2 -1. + <_> + 11 1 1 1 2. + 0 + -1.8917859997600317e-003 + -5.3087908029556274e-001 + 8.8928163051605225e-002 + <_> + + <_> + + + + <_> + 6 14 4 2 -1. + <_> + 6 14 4 1 2. + 1 + -1.7453400418162346e-002 + -6.4604520797729492e-001 + 1.1086379736661911e-001 + <_> + + <_> + + + + <_> + 3 0 8 1 -1. + <_> + 3 0 4 1 2. + 0 + 1.0619490407407284e-002 + 1.4190349727869034e-002 + -2.1650099754333496e-001 + <_> + + <_> + + + + <_> + 0 0 1 2 -1. + <_> + 0 1 1 1 2. + 0 + -1.1998750269412994e-003 + -6.4023351669311523e-001 + 1.0543160140514374e-001 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 7 5 1 3 3. + 1 + 9.0056620538234711e-003 + 6.6442847251892090e-002 + -3.8506388664245605e-001 + <_> + + <_> + + + + <_> + 6 4 3 3 -1. + <_> + 5 5 3 1 3. + 1 + -3.1365811824798584e-002 + 4.9019768834114075e-001 + -1.3340839743614197e-001 + <_> + + <_> + + + + <_> + 8 0 4 2 -1. + <_> + 10 0 2 1 2. + <_> + 8 1 2 1 2. + 0 + 8.8146664202213287e-003 + -7.5805522501468658e-002 + 5.1142227649688721e-001 + <_> + + <_> + + + + <_> + 0 0 4 2 -1. + <_> + 0 0 2 1 2. + <_> + 2 1 2 1 2. + 0 + -2.4432060308754444e-003 + -5.3494578599929810e-001 + 1.3186639547348022e-001 + <_> + + <_> + + + + <_> + 7 5 3 3 -1. + <_> + 8 6 1 3 3. + 1 + 3.3595509827136993e-002 + 1.8829340115189552e-002 + -8.7616902589797974e-001 + -1.5588049888610840e+000 + 5 + -1 + <_> + + + <_> + + <_> + + + + <_> + 2 5 8 14 -1. + <_> + 2 5 4 7 2. + <_> + 6 12 4 7 2. + 0 + -1.9901029765605927e-001 + 4.1589239239692688e-001 + -4.6403810381889343e-001 + <_> + + <_> + + + + <_> + 7 7 4 1 -1. + <_> + 7 7 2 1 2. + 0 + 1.0957729537039995e-003 + -2.7428150177001953e-001 + 2.1992009878158569e-001 + <_> + + <_> + + + + <_> + 5 0 1 3 -1. + <_> + 5 1 1 1 3. + 0 + 3.5783050116151571e-003 + -2.5449270009994507e-001 + 5.4316788911819458e-001 + <_> + + <_> + + + + <_> + 8 6 4 1 -1. + <_> + 8 6 2 1 2. + 1 + 3.5569820553064346e-002 + 4.2951688170433044e-002 + -6.6588342189788818e-001 + <_> + + <_> + + + + <_> + 4 6 1 4 -1. + <_> + 4 6 1 2 2. + 1 + -3.8403531070798635e-003 + 1.9703429937362671e-001 + -5.4586201906204224e-001 + <_> + + <_> + + + + <_> + 3 1 7 9 -1. + <_> + 3 4 7 3 3. + 0 + 3.9690821431577206e-003 + -5.1554411649703979e-001 + 2.2360439598560333e-001 + <_> + + <_> + + + + <_> + 3 9 6 3 -1. + <_> + 3 9 3 3 2. + 1 + 7.4965478852391243e-003 + 1.5371499955654144e-001 + -6.1535251140594482e-001 + <_> + + <_> + + + + <_> + 2 18 10 2 -1. + <_> + 7 18 5 1 2. + <_> + 2 19 5 1 2. + 0 + -8.9704096317291260e-003 + 1.8355900049209595e-001 + -2.8429880738258362e-001 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 6 13 3 1 2. + 1 + -5.6080069392919540e-002 + 7.7755087614059448e-001 + -9.8359443247318268e-002 + <_> + + <_> + + + + <_> + 8 5 2 3 -1. + <_> + 8 5 1 3 2. + 1 + 1.0908209718763828e-002 + 6.3484668731689453e-002 + -6.9791257381439209e-001 + <_> + + <_> + + + + <_> + 4 5 3 2 -1. + <_> + 4 5 3 1 2. + 1 + -9.8930671811103821e-003 + 4.0726318955421448e-001 + -2.5781801342964172e-001 + <_> + + <_> + + + + <_> + 0 14 12 5 -1. + <_> + 0 14 6 5 2. + 0 + 1.8678830564022064e-001 + -2.7086579799652100e-001 + 3.6147558689117432e-001 + <_> + + <_> + + + + <_> + 1 0 8 2 -1. + <_> + 5 0 4 2 2. + 0 + -9.4373157480731606e-004 + -5.8118808269500732e-001 + 1.5266190469264984e-001 + <_> + + <_> + + + + <_> + 6 16 2 2 -1. + <_> + 6 16 1 2 2. + 1 + -2.6823019608855247e-002 + 7.3039489984512329e-001 + -5.7183459401130676e-002 + <_> + + <_> + + + + <_> + 6 16 2 2 -1. + <_> + 6 16 2 1 2. + 1 + -8.4266774356365204e-003 + -6.9740217924118042e-001 + 1.1783199757337570e-001 + <_> + + <_> + + + + <_> + 6 9 1 6 -1. + <_> + 4 11 1 2 3. + 1 + 4.4732030481100082e-002 + -6.6901608370244503e-003 + -3.9551690220832825e-001 + <_> + + <_> + + + + <_> + 6 9 6 1 -1. + <_> + 8 11 2 1 3. + 1 + 1.9846759736537933e-002 + -2.5491309165954590e-001 + 2.6959219574928284e-001 + <_> + + <_> + + + + <_> + 10 17 1 3 -1. + <_> + 10 18 1 1 3. + 0 + -1.1466080322861671e-003 + -4.7784709930419922e-001 + 1.4147639274597168e-001 + <_> + + <_> + + + + <_> + 1 17 1 3 -1. + <_> + 1 18 1 1 3. + 0 + 9.8631740547716618e-004 + -2.9782509803771973e-001 + 2.1989880502223969e-001 + <_> + + <_> + + + + <_> + 11 2 1 18 -1. + <_> + 11 8 1 6 3. + 0 + -1.3526080548763275e-001 + 7.3641002178192139e-001 + -3.6679711192846298e-002 + <_> + + <_> + + + + <_> + 0 0 1 20 -1. + <_> + 0 5 1 10 2. + 0 + -1.4555889647454023e-003 + -4.9741968512535095e-001 + 1.4351129531860352e-001 + <_> + + <_> + + + + <_> + 4 0 6 2 -1. + <_> + 7 0 3 1 2. + <_> + 4 1 3 1 2. + 0 + -1.3439180329442024e-002 + 4.4307011365890503e-001 + -6.1504751443862915e-002 + <_> + + <_> + + + + <_> + 0 5 2 3 -1. + <_> + 0 6 2 1 3. + 0 + 5.8535612188279629e-003 + 8.6272820830345154e-002 + -6.9572478532791138e-001 + <_> + + <_> + + + + <_> + 8 0 2 1 -1. + <_> + 8 0 1 1 2. + 1 + -3.6728219129145145e-003 + -2.4009980261325836e-001 + 7.2359912097454071e-002 + <_> + + <_> + + + + <_> + 2 3 4 2 -1. + <_> + 3 4 2 2 2. + 1 + 2.8104060329496861e-003 + -2.8405401110649109e-001 + 2.0643989741802216e-001 + -1.5198639631271362e+000 + 6 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 5 2 2 -1. + <_> + 6 5 2 1 2. + 1 + 1.6374010592699051e-002 + -3.7089619040489197e-001 + 5.0737190246582031e-001 + <_> + + <_> + + + + <_> + 0 12 12 5 -1. + <_> + 3 12 6 5 2. + 0 + 9.4187058508396149e-002 + -3.1576469540596008e-001 + 4.0862488746643066e-001 + <_> + + <_> + + + + <_> + 0 18 10 2 -1. + <_> + 0 18 5 1 2. + <_> + 5 19 5 1 2. + 0 + 1.1773589998483658e-002 + -3.5064500570297241e-001 + 3.1217798590660095e-001 + <_> + + <_> + + + + <_> + 3 3 8 13 -1. + <_> + 5 3 4 13 2. + 0 + 1.0922340303659439e-001 + -1.2247060239315033e-001 + 2.5683128833770752e-001 + <_> + + <_> + + + + <_> + 1 3 8 13 -1. + <_> + 3 3 4 13 2. + 0 + -6.6653150133788586e-003 + 2.3083719611167908e-001 + -4.8135739564895630e-001 + <_> + + <_> + + + + <_> + 11 0 1 4 -1. + <_> + 11 0 1 2 2. + 1 + -4.5095751993358135e-003 + 1.6601459681987762e-001 + -1.2917369604110718e-001 + <_> + + <_> + + + + <_> + 0 1 10 2 -1. + <_> + 0 1 5 1 2. + <_> + 5 2 5 1 2. + 0 + -1.1136589571833611e-002 + 3.8687920570373535e-001 + -2.2618110477924347e-001 + <_> + + <_> + + + + <_> + 4 11 8 5 -1. + <_> + 4 11 4 5 2. + 0 + -1.5101970732212067e-001 + 7.8407418727874756e-001 + -5.6705389171838760e-002 + <_> + + <_> + + + + <_> + 0 0 1 14 -1. + <_> + 0 7 1 7 2. + 0 + 3.5842441022396088e-002 + -3.3353409171104431e-001 + 2.6884201169013977e-001 + <_> + + <_> + + + + <_> + 8 10 4 6 -1. + <_> + 6 12 4 2 3. + 1 + 6.0237798839807510e-002 + 6.6777043044567108e-002 + -5.8397102355957031e-001 + <_> + + <_> + + + + <_> + 4 10 6 4 -1. + <_> + 6 12 2 4 3. + 1 + 6.8902626633644104e-002 + -3.2930138707160950e-001 + 2.3172050714492798e-001 + <_> + + <_> + + + + <_> + 0 17 12 2 -1. + <_> + 0 17 6 2 2. + 0 + -1.1977110058069229e-001 + 7.2716677188873291e-001 + -1.0525380074977875e-001 + <_> + + <_> + + + + <_> + 5 6 3 3 -1. + <_> + 4 7 3 1 3. + 1 + 1.8936740234494209e-002 + -1.3431450724601746e-001 + 5.6203877925872803e-001 + <_> + + <_> + + + + <_> + 6 9 6 4 -1. + <_> + 6 9 3 4 2. + 1 + 8.3808198571205139e-002 + -4.9557849764823914e-002 + 1.0450640320777893e-001 + <_> + + <_> + + + + <_> + 6 9 4 6 -1. + <_> + 6 9 4 3 2. + 1 + 3.3902268856763840e-002 + 9.9094279110431671e-002 + -7.6239812374114990e-001 + <_> + + <_> + + + + <_> + 10 0 2 1 -1. + <_> + 10 0 1 1 2. + 1 + -8.1007126718759537e-003 + -4.3555849790573120e-001 + 2.2304659709334373e-002 + <_> + + <_> + + + + <_> + 2 0 1 2 -1. + <_> + 2 0 1 1 2. + 1 + 2.4974169209599495e-003 + 9.3714617192745209e-002 + -6.8376600742340088e-001 + <_> + + <_> + + + + <_> + 8 9 3 2 -1. + <_> + 9 9 1 2 3. + 0 + 1.0426550172269344e-002 + -1.1307760328054428e-001 + 4.3951630592346191e-001 + <_> + + <_> + + + + <_> + 0 0 2 4 -1. + <_> + 1 0 1 4 2. + 0 + -2.4919810239225626e-003 + -4.9109318852424622e-001 + 1.2399309873580933e-001 + <_> + + <_> + + + + <_> + 8 9 3 2 -1. + <_> + 9 9 1 2 3. + 0 + -4.4614528305828571e-003 + 3.4285509586334229e-001 + -1.3288980722427368e-001 + <_> + + <_> + + + + <_> + 1 9 3 2 -1. + <_> + 2 9 1 2 3. + 0 + -6.9255861453711987e-003 + 4.0674179792404175e-001 + -1.4747169613838196e-001 + <_> + + <_> + + + + <_> + 8 1 4 1 -1. + <_> + 9 2 2 1 2. + 1 + 1.4747819863259792e-002 + -1.7921010032296181e-002 + 1.5927059948444366e-001 + <_> + + <_> + + + + <_> + 4 1 1 4 -1. + <_> + 3 2 1 2 2. + 1 + 9.8200701177120209e-003 + 8.6944580078125000e-002 + -6.7220121622085571e-001 + -1.2744859457015991e+000 + 7 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 2 12 4 -1. + <_> + 0 4 12 2 2. + 0 + 3.0345980077981949e-002 + -5.6813991069793701e-001 + 2.7571758627891541e-001 + <_> + + <_> + + + + <_> + 8 9 3 8 -1. + <_> + 6 11 3 4 2. + 1 + -4.5385681092739105e-002 + -5.6568390130996704e-001 + 4.2446270585060120e-002 + <_> + + <_> + + + + <_> + 2 6 8 14 -1. + <_> + 2 6 4 7 2. + <_> + 6 13 4 7 2. + 0 + -2.4006670713424683e-001 + 3.9162129163742065e-001 + -3.0378338694572449e-001 + <_> + + <_> + + + + <_> + 11 18 1 2 -1. + <_> + 11 19 1 1 2. + 0 + -1.0817600414156914e-003 + -7.0329940319061279e-001 + 1.1626099795103073e-001 + <_> + + <_> + + + + <_> + 0 18 2 2 -1. + <_> + 0 19 2 1 2. + 0 + -1.6060429625213146e-003 + 2.2388499975204468e-001 + -4.8557040095329285e-001 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + -1.0570240020751953e-001 + -7.4889171123504639e-001 + 2.8992230072617531e-002 + <_> + + <_> + + + + <_> + 4 6 4 4 -1. + <_> + 4 7 4 2 2. + 0 + -2.3500300012528896e-003 + 2.3428779840469360e-001 + -4.2647179961204529e-001 + <_> + + <_> + + + + <_> + 8 0 2 3 -1. + <_> + 7 1 2 1 3. + 1 + -6.1817590147256851e-002 + -8.9189022779464722e-001 + -1.0216370224952698e-002 + <_> + + <_> + + + + <_> + 4 0 3 2 -1. + <_> + 5 1 1 2 3. + 1 + 5.4469848982989788e-003 + -2.6281470060348511e-001 + 3.1677961349487305e-001 + <_> + + <_> + + + + <_> + 11 7 1 2 -1. + <_> + 11 8 1 1 2. + 0 + -6.7602698691189289e-003 + -7.9144752025604248e-001 + 1.2072199955582619e-002 + <_> + + <_> + + + + <_> + 0 7 1 2 -1. + <_> + 0 8 1 1 2. + 0 + 7.8887082054279745e-005 + -4.4443818926811218e-001 + 1.9887650012969971e-001 + <_> + + <_> + + + + <_> + 4 0 8 8 -1. + <_> + 6 0 4 8 2. + 0 + 6.4817398786544800e-002 + -2.3440040647983551e-001 + 2.8372839093208313e-001 + <_> + + <_> + + + + <_> + 0 12 12 7 -1. + <_> + 6 12 6 7 2. + 0 + 2.9690501093864441e-001 + -1.1379630118608475e-001 + 8.4734469652175903e-001 + <_> + + <_> + + + + <_> + 8 0 2 1 -1. + <_> + 8 0 1 1 2. + 1 + -1.2669449672102928e-002 + -5.3791618347167969e-001 + 5.0364010035991669e-002 + <_> + + <_> + + + + <_> + 4 0 1 2 -1. + <_> + 4 0 1 1 2. + 1 + 3.2963419798761606e-003 + 9.5009326934814453e-002 + -6.9295811653137207e-001 + <_> + + <_> + + + + <_> + 6 10 2 6 -1. + <_> + 4 12 2 2 3. + 1 + 8.1940039992332458e-002 + 6.4861620776355267e-003 + -4.8242160677909851e-001 + <_> + + <_> + + + + <_> + 0 4 1 3 -1. + <_> + 0 5 1 1 3. + 0 + 4.5874840579926968e-003 + 7.4269242584705353e-002 + -8.5056728124618530e-001 + <_> + + <_> + + + + <_> + 9 8 3 4 -1. + <_> + 10 8 1 4 3. + 0 + 1.3228190131485462e-002 + -1.8141390383243561e-001 + 5.5488282442092896e-001 + <_> + + <_> + + + + <_> + 0 6 1 2 -1. + <_> + 0 7 1 1 2. + 0 + 8.3280639955773950e-005 + -3.5342589020729065e-001 + 1.6182580590248108e-001 + <_> + + <_> + + + + <_> + 4 4 6 12 -1. + <_> + 4 7 6 6 2. + 0 + 9.3232236802577972e-002 + 3.6166220903396606e-002 + -3.9560291171073914e-001 + <_> + + <_> + + + + <_> + 3 16 4 4 -1. + <_> + 3 18 4 2 2. + 0 + -1.7989000305533409e-002 + 1.8585060536861420e-001 + -2.9997050762176514e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 7 4 1 6 3. + 1 + 8.5582181811332703e-002 + -2.3212260566651821e-003 + -7.5706237554550171e-001 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 5 4 6 1 3. + 1 + 1.4874819666147232e-002 + -2.1825970709323883e-001 + 2.7366569638252258e-001 + <_> + + <_> + + + + <_> + 7 5 3 3 -1. + <_> + 8 6 1 3 3. + 1 + 2.0184369757771492e-002 + 3.5116590559482574e-002 + -4.5619380474090576e-001 + <_> + + <_> + + + + <_> + 5 5 3 3 -1. + <_> + 4 6 3 1 3. + 1 + 1.4273890294134617e-002 + -1.2478730082511902e-001 + 6.1065578460693359e-001 + <_> + + <_> + + + + <_> + 11 0 1 6 -1. + <_> + 11 3 1 3 2. + 0 + 2.6945620775222778e-002 + -5.6217260658740997e-002 + 4.3960160017013550e-001 + <_> + + <_> + + + + <_> + 0 4 6 16 -1. + <_> + 0 12 6 8 2. + 0 + -1.4722250401973724e-002 + -7.0504772663116455e-001 + 8.9823968708515167e-002 + <_> + + <_> + + + + <_> + 11 0 1 6 -1. + <_> + 11 3 1 3 2. + 0 + -3.9676232263445854e-003 + -2.0258559286594391e-001 + 2.4594809859991074e-002 + <_> + + <_> + + + + <_> + 6 12 6 1 -1. + <_> + 6 12 3 1 2. + 1 + -6.9255158305168152e-002 + 7.7862018346786499e-001 + -8.2329802215099335e-002 + -1.3562519550323486e+000 + 8 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 13 12 3 -1. + <_> + 3 13 6 3 2. + 0 + 4.2280860245227814e-002 + -4.3323940038681030e-001 + 3.1084230542182922e-001 + <_> + + <_> + + + + <_> + 4 6 8 2 -1. + <_> + 6 6 4 2 2. + 0 + 3.2466039061546326e-002 + -2.5457349419593811e-001 + 2.8453230857849121e-001 + <_> + + <_> + + + + <_> + 4 2 4 2 -1. + <_> + 4 2 2 1 2. + <_> + 6 3 2 1 2. + 0 + 3.9204079657793045e-003 + -2.4197019636631012e-001 + 3.8850378990173340e-001 + <_> + + <_> + + + + <_> + 10 0 2 6 -1. + <_> + 10 3 2 3 2. + 0 + 1.4881529845297337e-002 + -2.0224849879741669e-001 + 2.0803029835224152e-001 + <_> + + <_> + + + + <_> + 0 4 4 4 -1. + <_> + 0 4 2 2 2. + <_> + 2 6 2 2 2. + 0 + -4.8258059541694820e-004 + 2.0644129812717438e-001 + -4.6135428547859192e-001 + <_> + + <_> + + + + <_> + 10 0 2 6 -1. + <_> + 10 3 2 3 2. + 0 + 1.0871110111474991e-001 + -1.1968149803578854e-002 + -8.3505737781524658e-001 + <_> + + <_> + + + + <_> + 0 0 2 6 -1. + <_> + 0 3 2 3 2. + 0 + 1.1553530202945694e-004 + -6.2181282043457031e-001 + 1.2894719839096069e-001 + <_> + + <_> + + + + <_> + 11 18 1 2 -1. + <_> + 11 19 1 1 2. + 0 + 1.9984820391982794e-003 + 1.2071420252323151e-001 + -5.1865231990814209e-001 + <_> + + <_> + + + + <_> + 0 18 1 2 -1. + <_> + 0 19 1 1 2. + 0 + -1.9442409393377602e-004 + 1.5316960215568542e-001 + -4.6682178974151611e-001 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 6 13 1 3 2. + 1 + 3.4691508859395981e-002 + 5.2325479686260223e-002 + -5.6493771076202393e-001 + <_> + + <_> + + + + <_> + 0 17 12 3 -1. + <_> + 6 17 6 3 2. + 0 + 1.2708869576454163e-001 + -1.1623410135507584e-001 + 6.6390967369079590e-001 + <_> + + <_> + + + + <_> + 0 13 12 6 -1. + <_> + 0 13 6 6 2. + 0 + 1.8425850570201874e-001 + -2.9410699009895325e-001 + 2.7760609984397888e-001 + <_> + + <_> + + + + <_> + 0 5 8 4 -1. + <_> + 0 5 4 2 2. + <_> + 4 7 4 2 2. + 0 + -1.0079169645905495e-002 + 2.0110170543193817e-001 + -3.7747490406036377e-001 + <_> + + <_> + + + + <_> + 1 0 10 3 -1. + <_> + 1 1 10 1 3. + 0 + 2.3211309686303139e-002 + -1.5770949423313141e-001 + 4.1628879308700562e-001 + <_> + + <_> + + + + <_> + 0 2 12 6 -1. + <_> + 0 5 12 3 2. + 0 + -8.5837738588452339e-003 + -6.4297300577163696e-001 + 9.1064400970935822e-002 + <_> + + <_> + + + + <_> + 5 0 5 18 -1. + <_> + 5 6 5 6 3. + 0 + 3.0105128884315491e-001 + 1.8554370850324631e-002 + -3.6014398932456970e-001 + <_> + + <_> + + + + <_> + 0 0 9 9 -1. + <_> + 3 0 3 9 3. + 0 + 5.5468631908297539e-003 + 1.1459550261497498e-001 + -5.0818997621536255e-001 + <_> + + <_> + + + + <_> + 11 6 1 3 -1. + <_> + 11 7 1 1 3. + 0 + -3.2614849042147398e-003 + -6.5068858861923218e-001 + 7.1761913597583771e-002 + <_> + + <_> + + + + <_> + 2 12 4 2 -1. + <_> + 2 12 2 2 2. + 1 + -2.1482119336724281e-003 + 1.3169400393962860e-001 + -3.7837469577789307e-001 + <_> + + <_> + + + + <_> + 11 6 1 3 -1. + <_> + 11 7 1 1 3. + 0 + 4.2770840227603912e-003 + 4.9258850514888763e-002 + -5.8316987752914429e-001 + <_> + + <_> + + + + <_> + 1 10 3 1 -1. + <_> + 2 10 1 1 3. + 0 + -2.8884320054203272e-003 + 3.1445708870887756e-001 + -1.6602359712123871e-001 + <_> + + <_> + + + + <_> + 9 14 3 4 -1. + <_> + 9 16 3 2 2. + 0 + -4.7958120703697205e-002 + -7.2590202093124390e-001 + 1.5948530286550522e-002 + <_> + + <_> + + + + <_> + 0 14 3 4 -1. + <_> + 0 16 3 2 2. + 0 + 2.6324709877371788e-002 + 7.4111200869083405e-002 + -6.6733390092849731e-001 + <_> + + <_> + + + + <_> + 7 5 3 3 -1. + <_> + 8 6 1 3 3. + 1 + 1.3688339851796627e-002 + 4.7244258224964142e-002 + -3.2059279084205627e-001 + <_> + + <_> + + + + <_> + 5 5 3 3 -1. + <_> + 4 6 3 1 3. + 1 + 1.5577600337564945e-002 + -9.6644677221775055e-002 + 5.0794398784637451e-001 + <_> + + <_> + + + + <_> + 11 6 1 3 -1. + <_> + 11 7 1 1 3. + 0 + -8.4227044135332108e-003 + -9.9238747358322144e-001 + 2.0270830020308495e-002 + <_> + + <_> + + + + <_> + 0 6 1 3 -1. + <_> + 0 7 1 1 3. + 0 + 3.8861939683556557e-003 + 7.3856048285961151e-002 + -6.7188322544097900e-001 + <_> + + <_> + + + + <_> + 3 6 6 8 -1. + <_> + 3 10 6 4 2. + 0 + -3.3598121255636215e-002 + -7.3445242643356323e-001 + 5.7080879807472229e-002 + <_> + + <_> + + + + <_> + 6 4 4 3 -1. + <_> + 5 5 4 1 3. + 1 + 1.7251629382371902e-002 + -1.3607659935951233e-001 + 4.2951139807701111e-001 + <_> + + <_> + + + + <_> + 8 5 3 4 -1. + <_> + 9 6 1 4 3. + 1 + -3.1715810298919678e-002 + -7.4400889873504639e-001 + 3.3651608973741531e-002 + <_> + + <_> + + + + <_> + 4 5 4 3 -1. + <_> + 3 6 4 1 3. + 1 + 1.0187040083110332e-002 + -1.6512380540370941e-001 + 3.5162070393562317e-001 + <_> + + <_> + + + + <_> + 7 0 3 1 -1. + <_> + 8 1 1 1 3. + 1 + 3.7060850299894810e-003 + 6.8452596664428711e-002 + -1.8737269937992096e-001 + <_> + + <_> + + + + <_> + 3 0 2 3 -1. + <_> + 2 1 2 1 3. + 1 + -9.5564024522900581e-003 + -5.8053100109100342e-001 + 8.2600042223930359e-002 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + -1.4073489606380463e-001 + -1. + -6.1561721377074718e-003 + -1.4609309434890747e+000 + 9 + -1 + <_> + + + <_> + + <_> + + + + <_> + 5 4 2 4 -1. + <_> + 5 5 2 2 2. + 0 + 8.2872863858938217e-003 + -3.3240118622779846e-001 + 4.0866941213607788e-001 + <_> + + <_> + + + + <_> + 3 14 6 6 -1. + <_> + 3 17 6 3 2. + 0 + -5.3943969309329987e-002 + 2.7990311384201050e-001 + -3.5782578587532043e-001 + <_> + + <_> + + + + <_> + 0 5 8 12 -1. + <_> + 2 5 4 12 2. + 0 + -1.1539819650352001e-002 + 2.1358589828014374e-001 + -4.5100399851799011e-001 + <_> + + <_> + + + + <_> + 11 0 1 4 -1. + <_> + 11 0 1 2 2. + 1 + -1.5745559707283974e-002 + 2.1471889317035675e-001 + -9.9175170063972473e-002 + <_> + + <_> + + + + <_> + 1 0 4 1 -1. + <_> + 1 0 2 1 2. + 1 + -1.3527829432860017e-003 + 1.5119549632072449e-001 + -5.2674210071563721e-001 + <_> + + <_> + + + + <_> + 4 18 6 2 -1. + <_> + 7 18 3 1 2. + <_> + 4 19 3 1 2. + 0 + -1.1468210257589817e-002 + 1.3523469865322113e-001 + -3.7286050617694855e-002 + <_> + + <_> + + + + <_> + 0 18 8 2 -1. + <_> + 0 18 4 1 2. + <_> + 4 19 4 1 2. + 0 + 8.5535906255245209e-003 + -2.5730869174003601e-001 + 2.4693550169467926e-001 + <_> + + <_> + + + + <_> + 4 0 8 8 -1. + <_> + 6 0 4 8 2. + 0 + 5.6266319006681442e-002 + -2.1571849286556244e-001 + 1.8734970688819885e-001 + <_> + + <_> + + + + <_> + 0 0 2 1 -1. + <_> + 1 0 1 1 2. + 0 + 2.0349300466477871e-003 + 8.9395299553871155e-002 + -6.2484967708587646e-001 + <_> + + <_> + + + + <_> + 10 0 2 1 -1. + <_> + 10 0 1 1 2. + 0 + -1.0920839849859476e-003 + -3.2366481423377991e-001 + 6.9054901599884033e-002 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 6 13 3 1 2. + 1 + -5.1597058773040771e-002 + 6.1383968591690063e-001 + -9.5396347343921661e-002 + <_> + + <_> + + + + <_> + 0 13 12 1 -1. + <_> + 3 13 6 1 2. + 0 + 1.7433969303965569e-002 + -2.5729641318321228e-001 + 2.5275719165802002e-001 + <_> + + <_> + + + + <_> + 0 11 8 5 -1. + <_> + 4 11 4 5 2. + 0 + 7.6819643378257751e-002 + 8.7492428719997406e-002 + -6.7382502555847168e-001 + <_> + + <_> + + + + <_> + 8 6 4 14 -1. + <_> + 10 6 2 7 2. + <_> + 8 13 2 7 2. + 0 + 8.0648958683013916e-002 + -5.7000648230314255e-002 + 4.2771929502487183e-001 + <_> + + <_> + + + + <_> + 0 6 4 14 -1. + <_> + 0 6 2 7 2. + <_> + 2 13 2 7 2. + 0 + 7.0360638201236725e-003 + -4.2870849370956421e-001 + 1.4574399590492249e-001 + <_> + + <_> + + + + <_> + 4 3 8 2 -1. + <_> + 4 4 8 1 2. + 0 + 4.9487157957628369e-004 + -4.4867759943008423e-001 + 8.7952293455600739e-002 + <_> + + <_> + + + + <_> + 0 0 2 1 -1. + <_> + 1 0 1 1 2. + 0 + -2.0319919567555189e-003 + -6.9378471374511719e-001 + 7.9090960323810577e-002 + <_> + + <_> + + + + <_> + 1 0 10 3 -1. + <_> + 1 1 10 1 3. + 0 + 1.5986919403076172e-002 + -1.8177279829978943e-001 + 3.3544349670410156e-001 + <_> + + <_> + + + + <_> + 0 18 3 2 -1. + <_> + 1 18 1 2 3. + 0 + 1.0031439887825400e-004 + -2.8036159276962280e-001 + 1.8939669430255890e-001 + <_> + + <_> + + + + <_> + 0 4 12 12 -1. + <_> + 0 8 12 4 3. + 0 + -2.0664870738983154e-001 + -7.0004421472549438e-001 + 6.2915571033954620e-002 + <_> + + <_> + + + + <_> + 0 6 6 14 -1. + <_> + 0 13 6 7 2. + 0 + 1.0939550120383501e-003 + -5.6122779846191406e-001 + 7.9117156565189362e-002 + <_> + + <_> + + + + <_> + 8 0 3 1 -1. + <_> + 9 1 1 1 3. + 1 + 1.0714650154113770e-002 + 3.6672711372375488e-002 + -4.8171210289001465e-001 + <_> + + <_> + + + + <_> + 5 7 2 3 -1. + <_> + 4 8 2 1 3. + 1 + 1.2993469834327698e-002 + -1.3089600205421448e-001 + 3.2844379544258118e-001 + <_> + + <_> + + + + <_> + 11 3 1 3 -1. + <_> + 11 4 1 1 3. + 0 + 5.4268362000584602e-003 + 4.6886149793863297e-002 + -5.8115488290786743e-001 + <_> + + <_> + + + + <_> + 2 1 3 2 -1. + <_> + 2 1 3 1 2. + 1 + 1.0718739591538906e-002 + 5.9297699481248856e-002 + -6.6856807470321655e-001 + <_> + + <_> + + + + <_> + 11 3 1 3 -1. + <_> + 11 4 1 1 3. + 0 + -3.1285220757126808e-003 + -3.5857740044593811e-001 + 2.8134709224104881e-002 + <_> + + <_> + + + + <_> + 3 17 1 2 -1. + <_> + 3 17 1 1 2. + 1 + 5.2357040112838149e-004 + -3.4198528528213501e-001 + 1.2199939787387848e-001 + <_> + + <_> + + + + <_> + 11 3 1 3 -1. + <_> + 11 4 1 1 3. + 0 + 1.0644399560987949e-002 + 3.9803087711334229e-003 + -6.9705927371978760e-001 + <_> + + <_> + + + + <_> + 6 6 2 3 -1. + <_> + 5 7 2 1 3. + 1 + 1.5901770442724228e-002 + -7.6809287071228027e-002 + 5.2953928709030151e-001 + <_> + + <_> + + + + <_> + 11 3 1 3 -1. + <_> + 11 4 1 1 3. + 0 + -1.0395360179245472e-002 + -6.4491081237792969e-001 + 1.0781600140035152e-002 + <_> + + <_> + + + + <_> + 0 3 1 3 -1. + <_> + 0 4 1 1 3. + 0 + 3.7131321150809526e-003 + 6.6979996860027313e-002 + -6.2111258506774902e-001 + <_> + + <_> + + + + <_> + 6 4 3 2 -1. + <_> + 7 5 1 2 3. + 1 + 2.3174570873379707e-002 + 1.6732679679989815e-002 + -4.5888119935989380e-001 + <_> + + <_> + + + + <_> + 6 4 2 3 -1. + <_> + 5 5 2 1 3. + 1 + 1.1146579869091511e-002 + -1.1638499796390533e-001 + 4.3002909421920776e-001 + <_> + + <_> + + + + <_> + 11 8 1 4 -1. + <_> + 11 9 1 2 2. + 0 + 1.2715480290353298e-002 + 1.6517929732799530e-002 + -6.6795057058334351e-001 + <_> + + <_> + + + + <_> + 6 2 4 6 -1. + <_> + 4 4 4 2 3. + 1 + -1.2653400190174580e-002 + 1.1365109682083130e-001 + -3.7035998702049255e-001 + <_> + + <_> + + + + <_> + 5 17 6 2 -1. + <_> + 8 17 3 1 2. + <_> + 5 18 3 1 2. + 0 + -7.1139880456030369e-003 + 1.7468209564685822e-001 + -1.2769439816474915e-001 + <_> + + <_> + + + + <_> + 3 0 6 2 -1. + <_> + 3 0 3 1 2. + <_> + 6 1 3 1 2. + 0 + -1.3703290373086929e-002 + 4.2330458760261536e-001 + -9.5448397099971771e-002 + <_> + + <_> + + + + <_> + 11 3 1 2 -1. + <_> + 11 4 1 1 2. + 0 + 7.5888428837060928e-003 + -8.7192570790648460e-003 + 3.0307659506797791e-001 + <_> + + <_> + + + + <_> + 0 3 1 2 -1. + <_> + 0 4 1 1 2. + 0 + -5.7711452245712280e-004 + -5.0375598669052124e-001 + 9.0188682079315186e-002 + <_> + + <_> + + + + <_> + 10 4 2 4 -1. + <_> + 10 5 2 2 2. + 0 + -6.1391671188175678e-003 + -6.0663592815399170e-001 + 4.6589769423007965e-002 + <_> + + <_> + + + + <_> + 0 8 1 4 -1. + <_> + 0 9 1 2 2. + 0 + 9.4300412456505001e-005 + -2.6559790968894958e-001 + 1.5030109882354736e-001 + <_> + + <_> + + + + <_> + 0 13 12 5 -1. + <_> + 0 13 6 5 2. + 0 + -2.4399429559707642e-001 + 6.4060389995574951e-001 + -6.8897739052772522e-002 + <_> + + <_> + + + + <_> + 1 9 10 10 -1. + <_> + 1 9 5 5 2. + <_> + 6 14 5 5 2. + 0 + -1.2823240458965302e-001 + 2.1190899610519409e-001 + -2.7341139316558838e-001 + -1.4843599796295166e+000 + 10 + -1 + <_> + + + <_> + + <_> + + + + <_> + 1 1 6 2 -1. + <_> + 1 1 3 1 2. + <_> + 4 2 3 1 2. + 0 + -9.8697589710354805e-003 + 4.8807978630065918e-001 + -2.6589471101760864e-001 + <_> + + <_> + + + + <_> + 7 4 3 5 -1. + <_> + 8 5 1 5 3. + 1 + 3.3131919801235199e-002 + 3.2597500830888748e-002 + -6.3295251131057739e-001 + <_> + + <_> + + + + <_> + 6 3 6 1 -1. + <_> + 8 5 2 1 3. + 1 + 1.7511799931526184e-002 + -3.5473251342773438e-001 + 2.8011149168014526e-001 + <_> + + <_> + + + + <_> + 11 4 1 12 -1. + <_> + 11 8 1 4 3. + 0 + -7.3885500431060791e-002 + 4.7378170490264893e-001 + -1.1292530223727226e-002 + <_> + + <_> + + + + <_> + 0 4 1 12 -1. + <_> + 0 8 1 4 3. + 0 + 1.8212760332971811e-003 + -4.6179610490798950e-001 + 1.4266149699687958e-001 + <_> + + <_> + + + + <_> + 8 8 4 8 -1. + <_> + 6 10 4 4 2. + 1 + -8.5360601544380188e-002 + -6.6754668951034546e-001 + 7.5132578611373901e-002 + <_> + + <_> + + + + <_> + 1 7 10 12 -1. + <_> + 1 7 5 6 2. + <_> + 6 13 5 6 2. + 0 + -2.7539798617362976e-001 + 3.8147959113121033e-001 + -2.3665140569210052e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 8 5 2 6 3. + 1 + 3.0699970200657845e-002 + 5.1691979169845581e-002 + -2.4286730587482452e-001 + <_> + + <_> + + + + <_> + 3 6 4 4 -1. + <_> + 3 6 2 2 2. + <_> + 5 8 2 2 2. + 0 + -9.6332989633083344e-003 + 3.3072310686111450e-001 + -2.0818190276622772e-001 + <_> + + <_> + + + + <_> + 10 2 2 2 -1. + <_> + 10 3 2 1 2. + 0 + 1.6330240294337273e-002 + 3.4118140320060775e-005 + -8.0960237979888916e-001 + <_> + + <_> + + + + <_> + 0 2 2 2 -1. + <_> + 0 3 2 1 2. + 0 + 8.6133222794160247e-005 + -3.7730661034584045e-001 + 1.3947279751300812e-001 + <_> + + <_> + + + + <_> + 8 17 2 1 -1. + <_> + 8 17 1 1 2. + 1 + -3.0760519206523895e-002 + 6.7611587047576904e-001 + -1.4665770344436169e-002 + <_> + + <_> + + + + <_> + 0 8 3 3 -1. + <_> + 1 8 1 3 3. + 0 + 6.8717780523002148e-003 + -1.6677060723304749e-001 + 3.0840030312538147e-001 + <_> + + <_> + + + + <_> + 5 14 3 6 -1. + <_> + 6 14 1 6 3. + 0 + 1.7696250230073929e-002 + 3.8468770682811737e-002 + -5.9128028154373169e-001 + <_> + + <_> + + + + <_> + 4 14 3 5 -1. + <_> + 5 14 1 5 3. + 0 + 1.4457659795880318e-002 + 7.1180373430252075e-002 + -6.8788748979568481e-001 + <_> + + <_> + + + + <_> + 10 0 2 2 -1. + <_> + 10 1 2 1 2. + 0 + 4.4003669172525406e-003 + -1.7107939720153809e-001 + 3.3334150910377502e-001 + <_> + + <_> + + + + <_> + 0 0 2 2 -1. + <_> + 0 1 2 1 2. + 0 + -1.9785019103437662e-003 + -6.3402158021926880e-001 + 8.5248172283172607e-002 + <_> + + <_> + + + + <_> + 0 12 12 7 -1. + <_> + 0 12 6 7 2. + 0 + -3.5506778955459595e-001 + 6.9163411855697632e-001 + -8.7763786315917969e-002 + <_> + + <_> + + + + <_> + 6 14 3 2 -1. + <_> + 7 15 1 2 3. + 1 + 1.2596770189702511e-002 + -2.0116379857063293e-001 + 3.4040948748588562e-001 + <_> + + <_> + + + + <_> + 11 16 1 4 -1. + <_> + 11 18 1 2 2. + 0 + -2.3926040157675743e-003 + -6.2525659799575806e-001 + 1.1060170084238052e-001 + <_> + + <_> + + + + <_> + 0 16 1 4 -1. + <_> + 0 18 1 2 2. + 0 + -8.7672837253194302e-005 + 1.4002850651741028e-001 + -3.9103108644485474e-001 + <_> + + <_> + + + + <_> + 4 2 6 4 -1. + <_> + 4 4 6 2 2. + 0 + 5.4524061270058155e-003 + -3.1052809953689575e-001 + 6.3757672905921936e-002 + <_> + + <_> + + + + <_> + 5 6 3 3 -1. + <_> + 4 7 3 1 3. + 1 + 1.2568219564855099e-002 + -1.3675519824028015e-001 + 3.2680550217628479e-001 + <_> + + <_> + + + + <_> + 8 0 4 20 -1. + <_> + 8 10 4 10 2. + 0 + 3.7843358516693115e-001 + -3.7364691495895386e-002 + 3.7789309024810791e-001 + <_> + + <_> + + + + <_> + 3 11 2 3 -1. + <_> + 3 12 2 1 3. + 0 + -3.3601790200918913e-003 + 2.9605069756507874e-001 + -1.5206739306449890e-001 + <_> + + <_> + + + + <_> + 8 0 4 20 -1. + <_> + 8 10 4 10 2. + 0 + -4.3185380101203918e-001 + -6.8029761314392090e-001 + 1.2745309621095657e-002 + <_> + + <_> + + + + <_> + 0 0 4 20 -1. + <_> + 0 10 4 10 2. + 0 + 7.3479618877172470e-003 + -6.6707527637481689e-001 + 6.7926846444606781e-002 + <_> + + <_> + + + + <_> + 7 5 3 3 -1. + <_> + 6 6 3 1 3. + 1 + 7.5943907722830772e-003 + -1.1112800240516663e-001 + 2.2462299466133118e-001 + <_> + + <_> + + + + <_> + 5 5 3 3 -1. + <_> + 6 6 1 3 3. + 1 + -7.3589297244325280e-005 + 1.3988719880580902e-001 + -3.4220328927040100e-001 + <_> + + <_> + + + + <_> + 7 0 3 1 -1. + <_> + 8 1 1 1 3. + 1 + -1.0304169700248167e-004 + 8.2018472254276276e-002 + -1.0476870089769363e-001 + <_> + + <_> + + + + <_> + 5 0 1 3 -1. + <_> + 4 1 1 1 3. + 1 + -5.4624290205538273e-003 + -5.1264250278472900e-001 + 9.2095062136650085e-002 + <_> + + <_> + + + + <_> + 0 9 12 3 -1. + <_> + 0 10 12 1 3. + 0 + 1.9663229584693909e-002 + 6.1935991048812866e-002 + -6.1648821830749512e-001 + <_> + + <_> + + + + <_> + 0 0 8 1 -1. + <_> + 2 0 4 1 2. + 0 + -1.1055600043619052e-004 + 1.4308770000934601e-001 + -2.7447059750556946e-001 + <_> + + <_> + + + + <_> + 7 13 4 2 -1. + <_> + 9 13 2 1 2. + <_> + 7 14 2 1 2. + 0 + 3.8737419527024031e-003 + -1.0690200328826904e-001 + 2.0657220482826233e-001 + <_> + + <_> + + + + <_> + 1 13 4 2 -1. + <_> + 1 13 2 1 2. + <_> + 3 14 2 1 2. + 0 + -4.5131230726838112e-003 + 3.4341660141944885e-001 + -1.2317349761724472e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 8 5 2 6 3. + 1 + -6.1594668775796890e-002 + 9.3623742461204529e-002 + -4.5765519142150879e-002 + <_> + + <_> + + + + <_> + 2 9 2 1 -1. + <_> + 3 9 1 1 2. + 0 + 1.2142979539930820e-003 + -1.3058850169181824e-001 + 3.0691918730735779e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 8 5 2 6 3. + 1 + 1.3168719410896301e-001 + 1.1348670348525047e-002 + -3.6062520742416382e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + -9.8962578922510147e-003 + 9.7268536686897278e-002 + -4.5470228791236877e-001 + <_> + + <_> + + + + <_> + 10 6 2 3 -1. + <_> + 10 7 2 1 3. + 0 + -4.3822340667247772e-003 + -6.9014567136764526e-001 + 7.1008093655109406e-002 + <_> + + <_> + + + + <_> + 6 3 4 3 -1. + <_> + 5 4 4 1 3. + 1 + -2.4433590471744537e-002 + 5.0112801790237427e-001 + -9.8408728837966919e-002 + <_> + + <_> + + + + <_> + 7 0 3 1 -1. + <_> + 8 1 1 1 3. + 1 + -8.6958734318614006e-003 + -1.4006440341472626e-001 + 3.6845669150352478e-002 + -1.4225620031356812e+000 + 11 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 5 1 3 -1. + <_> + 5 6 1 1 3. + 1 + -1.7152750864624977e-002 + 4.7029718756675720e-001 + -2.2067089378833771e-001 + <_> + + <_> + + + + <_> + 8 9 3 8 -1. + <_> + 6 11 3 4 2. + 1 + 8.3040937781333923e-002 + 5.5113639682531357e-002 + -5.5488407611846924e-001 + <_> + + <_> + + + + <_> + 4 9 8 3 -1. + <_> + 6 11 4 3 2. + 1 + 1.2245059758424759e-001 + -2.8312590718269348e-001 + 3.4973090887069702e-001 + <_> + + <_> + + + + <_> + 6 0 1 3 -1. + <_> + 6 1 1 1 3. + 0 + 7.3496531695127487e-003 + -1.3282130658626556e-001 + 4.8876601457595825e-001 + <_> + + <_> + + + + <_> + 4 0 4 2 -1. + <_> + 4 0 2 1 2. + <_> + 6 1 2 1 2. + 0 + -9.3082878738641739e-003 + 4.5475938916206360e-001 + -1.4194749295711517e-001 + <_> + + <_> + + + + <_> + 0 10 12 2 -1. + <_> + 0 11 12 1 2. + 0 + 1.7290420830249786e-002 + 9.8470740020275116e-002 + -6.8155962228775024e-001 + <_> + + <_> + + + + <_> + 0 11 8 5 -1. + <_> + 4 11 4 5 2. + 0 + 6.8027682602405548e-002 + 1.2287759780883789e-001 + -5.8085542917251587e-001 + <_> + + <_> + + + + <_> + 7 0 4 2 -1. + <_> + 7 0 2 2 2. + 0 + -2.5710109621286392e-003 + -2.8932929039001465e-001 + 9.2327423393726349e-002 + <_> + + <_> + + + + <_> + 2 2 7 8 -1. + <_> + 2 4 7 4 2. + 0 + -2.7197790332138538e-003 + -4.8277780413627625e-001 + 1.2942260503768921e-001 + <_> + + <_> + + + + <_> + 7 0 4 2 -1. + <_> + 7 0 2 2 2. + 0 + 3.6168839782476425e-002 + -3.3225961029529572e-002 + 2.8994488716125488e-001 + <_> + + <_> + + + + <_> + 1 0 4 2 -1. + <_> + 3 0 2 2 2. + 0 + -4.5704417861998081e-003 + -5.9805792570114136e-001 + 1.0446850210428238e-001 + <_> + + <_> + + + + <_> + 9 17 3 3 -1. + <_> + 9 18 3 1 3. + 0 + 3.7568379193544388e-003 + 1.2488850206136703e-001 + -5.7084852457046509e-001 + <_> + + <_> + + + + <_> + 0 17 3 3 -1. + <_> + 0 18 3 1 3. + 0 + 3.0054030939936638e-003 + -3.2693040370941162e-001 + 1.9752669334411621e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 18 6 2 2. + 0 + -1.0322710126638412e-001 + 5.9689277410507202e-001 + -9.9626749753952026e-002 + <_> + + <_> + + + + <_> + 0 11 12 5 -1. + <_> + 3 11 6 5 2. + 0 + 8.5584551095962524e-002 + -2.3595149815082550e-001 + 2.7769410610198975e-001 + <_> + + <_> + + + + <_> + 8 7 4 1 -1. + <_> + 8 7 2 1 2. + 1 + -1.7628820613026619e-002 + 2.3300230503082275e-001 + -3.8094460964202881e-002 + <_> + + <_> + + + + <_> + 4 7 1 4 -1. + <_> + 4 7 1 2 2. + 1 + -7.3259319178760052e-003 + 1.5533800423145294e-001 + -3.4289830923080444e-001 + <_> + + <_> + + + + <_> + 4 0 6 7 -1. + <_> + 6 0 2 7 3. + 0 + 1.6643910109996796e-001 + 1.3593060430139303e-004 + -6.0628050565719604e-001 + <_> + + <_> + + + + <_> + 2 0 6 7 -1. + <_> + 4 0 2 7 3. + 0 + 1.3041920028626919e-002 + 1.0876829922199249e-001 + -4.7265630960464478e-001 + <_> + + <_> + + + + <_> + 0 16 12 3 -1. + <_> + 0 17 12 1 3. + 0 + -1.3597619719803333e-002 + -5.8280581235885620e-001 + 7.2698637843132019e-002 + <_> + + <_> + + + + <_> + 4 17 4 2 -1. + <_> + 4 17 2 1 2. + <_> + 6 18 2 1 2. + 0 + 6.8220919929444790e-003 + -1.4359709620475769e-001 + 3.4434759616851807e-001 + <_> + + <_> + + + + <_> + 9 0 3 1 -1. + <_> + 10 0 1 1 3. + 0 + -1.3025919906795025e-004 + 7.5394742190837860e-002 + -6.7537508904933929e-002 + <_> + + <_> + + + + <_> + 0 0 3 1 -1. + <_> + 1 0 1 1 3. + 0 + -2.4602119810879230e-003 + -5.1882988214492798e-001 + 8.0956049263477325e-002 + <_> + + <_> + + + + <_> + 6 4 3 2 -1. + <_> + 7 5 1 2 3. + 1 + -3.2538071274757385e-002 + -5.8500260114669800e-001 + 5.7338178157806396e-003 + <_> + + <_> + + + + <_> + 3 6 3 1 -1. + <_> + 4 6 1 1 3. + 0 + 2.0106420852243900e-003 + -1.0640989989042282e-001 + 4.0276700258255005e-001 + <_> + + <_> + + + + <_> + 9 2 3 7 -1. + <_> + 10 3 1 7 3. + 1 + -4.6432539820671082e-002 + -4.2023709416389465e-001 + 4.2063061147928238e-002 + <_> + + <_> + + + + <_> + 5 5 2 2 -1. + <_> + 5 5 2 1 2. + 1 + -1.2824350036680698e-002 + 4.8449409008026123e-001 + -9.4362497329711914e-002 + <_> + + <_> + + + + <_> + 7 5 3 4 -1. + <_> + 8 6 1 4 3. + 1 + 3.4120719879865646e-002 + 2.7428179979324341e-002 + -5.6730318069458008e-001 + <_> + + <_> + + + + <_> + 5 5 4 3 -1. + <_> + 4 6 4 1 3. + 1 + -4.4012650847434998e-002 + 3.7047350406646729e-001 + -1.3064679503440857e-001 + <_> + + <_> + + + + <_> + 10 4 2 2 -1. + <_> + 10 5 2 1 2. + 0 + -3.7362610455602407e-003 + -6.1717242002487183e-001 + 4.6860579401254654e-002 + <_> + + <_> + + + + <_> + 0 3 2 3 -1. + <_> + 0 4 2 1 3. + 0 + -5.2141821943223476e-003 + -6.5322470664978027e-001 + 5.3996030241250992e-002 + <_> + + <_> + + + + <_> + 10 4 2 2 -1. + <_> + 10 5 2 1 2. + 0 + 6.4924731850624084e-003 + 4.4800970703363419e-002 + -4.3987420201301575e-001 + <_> + + <_> + + + + <_> + 0 4 2 2 -1. + <_> + 0 5 2 1 2. + 0 + -4.2384970001876354e-003 + -7.1687930822372437e-001 + 5.4430369287729263e-002 + <_> + + <_> + + + + <_> + 7 10 2 1 -1. + <_> + 7 10 1 1 2. + 0 + -3.1804300379008055e-003 + 2.4815900623798370e-001 + -8.9008152484893799e-002 + <_> + + <_> + + + + <_> + 3 10 2 1 -1. + <_> + 4 10 1 1 2. + 0 + 2.9277798603288829e-004 + -2.1440739929676056e-001 + 2.0239150524139404e-001 + <_> + + <_> + + + + <_> + 5 0 2 2 -1. + <_> + 5 1 2 1 2. + 0 + -1.1838439851999283e-002 + 6.8225288391113281e-001 + -5.6109890341758728e-002 + <_> + + <_> + + + + <_> + 5 14 4 2 -1. + <_> + 5 14 4 1 2. + 1 + -2.0604960620403290e-002 + -6.4495718479156494e-001 + 6.5811157226562500e-002 + -1.3051190376281738e+000 + 12 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 6 3 3 -1. + <_> + 4 7 3 1 3. + 0 + -5.7252319529652596e-003 + 3.4108111262321472e-001 + -3.3441230654716492e-001 + <_> + + <_> + + + + <_> + 3 5 6 14 -1. + <_> + 6 5 3 7 2. + <_> + 3 12 3 7 2. + 0 + 1.5814049541950226e-001 + -2.9555070400238037e-001 + 2.9280221462249756e-001 + <_> + + <_> + + + + <_> + 3 0 3 2 -1. + <_> + 3 1 3 1 2. + 0 + 3.5558689851313829e-003 + -2.8485581278800964e-001 + 2.4933080375194550e-001 + <_> + + <_> + + + + <_> + 7 18 5 2 -1. + <_> + 7 19 5 1 2. + 0 + -3.1524680089205503e-003 + -4.6672669053077698e-001 + 7.6127722859382629e-002 + <_> + + <_> + + + + <_> + 0 18 10 2 -1. + <_> + 0 19 10 1 2. + 0 + -1.4493550173938274e-002 + 2.5777289271354675e-001 + -2.4369129538536072e-001 + <_> + + <_> + + + + <_> + 11 2 1 15 -1. + <_> + 11 7 1 5 3. + 0 + -6.8386606872081757e-002 + 5.2669358253479004e-001 + 8.9219277724623680e-003 + <_> + + <_> + + + + <_> + 0 4 1 6 -1. + <_> + 0 7 1 3 2. + 0 + 1.0660409461706877e-003 + -4.9784231185913086e-001 + 1.1696430295705795e-001 + <_> + + <_> + + + + <_> + 3 2 9 8 -1. + <_> + 3 4 9 4 2. + 0 + 1.6208799555897713e-002 + -3.0983239412307739e-001 + 9.5886580646038055e-002 + <_> + + <_> + + + + <_> + 0 15 12 5 -1. + <_> + 6 15 6 5 2. + 0 + 2.8249868750572205e-001 + -7.3715627193450928e-002 + 6.4200782775878906e-001 + <_> + + <_> + + + + <_> + 6 9 3 6 -1. + <_> + 4 11 3 2 3. + 1 + 8.6361259222030640e-002 + 4.0710549801588058e-002 + -5.0559818744659424e-001 + <_> + + <_> + + + + <_> + 6 9 6 3 -1. + <_> + 8 11 2 3 3. + 1 + 5.1451180130243301e-002 + -3.3384099602699280e-001 + 1.6614030301570892e-001 + <_> + + <_> + + + + <_> + 2 0 10 2 -1. + <_> + 2 0 5 2 2. + 0 + -6.9037936627864838e-002 + -3.1987860798835754e-001 + 3.4255299717187881e-002 + <_> + + <_> + + + + <_> + 0 0 10 2 -1. + <_> + 5 0 5 2 2. + 0 + -5.6569739244878292e-003 + -6.1266559362411499e-001 + 8.3148159086704254e-002 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 8 5 2 6 3. + 1 + -7.1886749938130379e-003 + 4.2386818677186966e-002 + -9.7789242863655090e-002 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 4 5 6 2 3. + 1 + -2.6780599728226662e-002 + 1.2735369801521301e-001 + -3.4852239489555359e-001 + <_> + + <_> + + + + <_> + 6 0 6 5 -1. + <_> + 6 0 3 5 2. + 1 + -6.9346590898931026e-003 + 4.4443860650062561e-002 + -2.6666578650474548e-001 + <_> + + <_> + + + + <_> + 6 0 5 6 -1. + <_> + 6 0 5 3 2. + 1 + 1.2057109922170639e-001 + 9.1515138745307922e-002 + -5.5102181434631348e-001 + <_> + + <_> + + + + <_> + 8 8 3 2 -1. + <_> + 9 9 1 2 3. + 1 + 1.0571300052106380e-002 + -1.1927139759063721e-001 + 1.5043540298938751e-001 + <_> + + <_> + + + + <_> + 4 8 2 3 -1. + <_> + 3 9 2 1 3. + 1 + -1.4446419663727283e-002 + 3.2619118690490723e-001 + -1.3021939992904663e-001 + <_> + + <_> + + + + <_> + 11 6 1 3 -1. + <_> + 11 7 1 1 3. + 0 + 4.9188970588147640e-003 + 2.4317760020494461e-002 + -5.8825939893722534e-001 + <_> + + <_> + + + + <_> + 0 6 1 3 -1. + <_> + 0 7 1 1 3. + 0 + -3.8240209687501192e-003 + -6.5660482645034790e-001 + 6.3337683677673340e-002 + <_> + + <_> + + + + <_> + 0 11 12 8 -1. + <_> + 0 15 12 4 2. + 0 + -1.7404669523239136e-001 + -5.4772597551345825e-001 + 6.0019370168447495e-002 + <_> + + <_> + + + + <_> + 3 13 6 3 -1. + <_> + 5 13 2 3 3. + 0 + 4.5922618359327316e-002 + 5.0438169389963150e-002 + -6.9467681646347046e-001 + <_> + + <_> + + + + <_> + 5 16 2 4 -1. + <_> + 5 17 2 2 2. + 0 + -3.9035470690578222e-003 + 2.2018410265445709e-001 + -1.8376649916172028e-001 + <_> + + <_> + + + + <_> + 1 1 2 1 -1. + <_> + 1 1 1 1 2. + 1 + 1.7436769558116794e-003 + 6.1212658882141113e-002 + -5.7988357543945313e-001 + <_> + + <_> + + + + <_> + 6 15 2 3 -1. + <_> + 5 16 2 1 3. + 1 + -9.7301546484231949e-003 + -5.1599711179733276e-001 + 4.9021121114492416e-002 + <_> + + <_> + + + + <_> + 5 5 3 3 -1. + <_> + 4 6 3 1 3. + 1 + -5.0866428762674332e-002 + 4.3118700385093689e-001 + -9.5599338412284851e-002 + <_> + + <_> + + + + <_> + 6 5 2 3 -1. + <_> + 6 6 2 1 3. + 0 + 1.5334750059992075e-004 + -8.4842063486576080e-002 + 5.3982339799404144e-002 + <_> + + <_> + + + + <_> + 4 5 2 3 -1. + <_> + 4 6 2 1 3. + 0 + -7.9509448260068893e-003 + 4.7792288661003113e-001 + -9.3340940773487091e-002 + <_> + + <_> + + + + <_> + 10 5 2 3 -1. + <_> + 10 6 2 1 3. + 0 + -4.4662738218903542e-003 + -6.6406428813934326e-001 + 7.0635370910167694e-002 + <_> + + <_> + + + + <_> + 6 5 2 3 -1. + <_> + 5 6 2 1 3. + 1 + 6.7459428682923317e-003 + -9.5945097506046295e-002 + 4.5204031467437744e-001 + <_> + + <_> + + + + <_> + 8 7 1 8 -1. + <_> + 6 9 1 4 2. + 1 + -4.8576910048723221e-002 + -2.5402069091796875e-001 + 3.5480510443449020e-002 + <_> + + <_> + + + + <_> + 0 5 2 3 -1. + <_> + 0 6 2 1 3. + 0 + -8.1895291805267334e-003 + -6.9631862640380859e-001 + 5.4189778864383698e-002 + <_> + + <_> + + + + <_> + 5 5 2 3 -1. + <_> + 5 5 1 3 2. + 0 + -1.3830559328198433e-004 + 7.7265933156013489e-002 + -4.3882951140403748e-001 + <_> + + <_> + + + + <_> + 4 7 8 1 -1. + <_> + 6 9 4 1 2. + 1 + -2.9827160760760307e-002 + 5.1934647560119629e-001 + -7.4816159904003143e-002 + <_> + + <_> + + + + <_> + 6 15 2 3 -1. + <_> + 5 16 2 1 3. + 1 + 1.9728230312466621e-002 + 4.6895399689674377e-002 + -5.6989020109176636e-001 + <_> + + <_> + + + + <_> + 6 15 3 2 -1. + <_> + 7 16 1 2 3. + 1 + 1.2107780203223228e-002 + -1.3739739358425140e-001 + 3.2666760683059692e-001 + <_> + + <_> + + + + <_> + 9 13 2 3 -1. + <_> + 9 14 2 1 3. + 0 + 6.9206808693706989e-003 + 4.6539328992366791e-002 + -4.9861478805541992e-001 + <_> + + <_> + + + + <_> + 1 13 2 3 -1. + <_> + 1 14 2 1 3. + 0 + 7.5631309300661087e-003 + -1.0235120356082916e-001 + 3.9567971229553223e-001 + <_> + + <_> + + + + <_> + 0 5 12 12 -1. + <_> + 0 9 12 4 3. + 0 + -2.3844289779663086e-001 + -7.1881687641143799e-001 + 4.9742348492145538e-002 + <_> + + <_> + + + + <_> + 0 9 3 2 -1. + <_> + 1 9 1 2 3. + 0 + -9.2327659949660301e-003 + 4.8625311255455017e-001 + -7.8327029943466187e-002 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 8 15 2 1 3. + 1 + 1.2344529852271080e-002 + -4.5567270368337631e-002 + 1.6513639688491821e-001 + <_> + + <_> + + + + <_> + 0 9 2 4 -1. + <_> + 0 9 1 2 2. + <_> + 1 11 1 2 2. + 0 + -1.0889769764617085e-003 + 2.3016020655632019e-001 + -1.4696329832077026e-001 + <_> + + <_> + + + + <_> + 2 17 8 2 -1. + <_> + 6 17 4 1 2. + <_> + 2 18 4 1 2. + 0 + -5.1214238628745079e-003 + 1.7787009477615356e-001 + -1.9967870414257050e-001 + <_> + + <_> + + + + <_> + 1 8 9 2 -1. + <_> + 1 9 9 1 2. + 0 + 2.3381220176815987e-002 + 3.9966959506273270e-002 + -7.6583552360534668e-001 + -1.2928479909896851e+000 + 13 + -1 + <_> + + + <_> + + <_> + + + + <_> + 5 4 1 4 -1. + <_> + 5 5 1 2 2. + 0 + 5.8875479735434055e-003 + -2.6197949051856995e-001 + 3.9267268776893616e-001 + <_> + + <_> + + + + <_> + 8 0 3 3 -1. + <_> + 7 1 3 1 3. + 1 + -2.0563710480928421e-002 + 2.3240800201892853e-001 + -3.6058109253644943e-002 + <_> + + <_> + + + + <_> + 4 0 3 3 -1. + <_> + 5 1 1 3 3. + 1 + 2.4195060133934021e-002 + -1.7246599495410919e-001 + 4.0554100275039673e-001 + <_> + + <_> + + + + <_> + 0 13 12 6 -1. + <_> + 0 13 6 6 2. + 0 + 2.2053229808807373e-001 + -2.4937939643859863e-001 + 2.4980540573596954e-001 + <_> + + <_> + + + + <_> + 5 4 3 3 -1. + <_> + 6 5 1 3 3. + 1 + 8.1213507801294327e-003 + 9.8432846367359161e-002 + -5.0667357444763184e-001 + <_> + + <_> + + + + <_> + 9 17 1 3 -1. + <_> + 9 18 1 1 3. + 0 + -1.5637070173397660e-003 + -4.1526609659194946e-001 + 1.3340100646018982e-001 + <_> + + <_> + + + + <_> + 2 17 1 3 -1. + <_> + 2 18 1 1 3. + 0 + 1.2210609856992960e-003 + -2.5663951039314270e-001 + 2.1268320083618164e-001 + <_> + + <_> + + + + <_> + 0 9 12 6 -1. + <_> + 0 11 12 2 3. + 0 + 4.5655488967895508e-002 + 8.5712976753711700e-002 + -5.5701047182083130e-001 + <_> + + <_> + + + + <_> + 5 6 6 2 -1. + <_> + 5 6 3 2 2. + 1 + -1.7322370782494545e-002 + 1.0083419829607010e-001 + -4.3052899837493896e-001 + <_> + + <_> + + + + <_> + 6 4 3 4 -1. + <_> + 7 5 1 4 3. + 1 + 2.7879169210791588e-002 + 4.4392268173396587e-003 + -5.7203328609466553e-001 + <_> + + <_> + + + + <_> + 6 4 4 3 -1. + <_> + 5 5 4 1 3. + 1 + -4.7942388802766800e-002 + 4.9971351027488708e-001 + -1.0569220036268234e-001 + <_> + + <_> + + + + <_> + 11 4 1 16 -1. + <_> + 11 8 1 8 2. + 0 + -9.0003162622451782e-002 + 7.7226841449737549e-001 + -3.5037949681282043e-002 + <_> + + <_> + + + + <_> + 0 0 1 20 -1. + <_> + 0 5 1 10 2. + 0 + 2.1878979168832302e-003 + -4.3980291485786438e-001 + 1.0962349921464920e-001 + <_> + + <_> + + + + <_> + 9 0 2 1 -1. + <_> + 9 0 1 1 2. + 1 + -1.1160460300743580e-002 + -6.0748499631881714e-001 + 2.5118330493569374e-002 + <_> + + <_> + + + + <_> + 3 0 1 2 -1. + <_> + 3 0 1 1 2. + 1 + 2.3293609265238047e-003 + 7.4755467474460602e-002 + -5.6645327806472778e-001 + <_> + + <_> + + + + <_> + 6 13 6 6 -1. + <_> + 9 13 3 3 2. + <_> + 6 16 3 3 2. + 0 + -3.2051369547843933e-002 + 1.3710969686508179e-001 + -1.4014610648155212e-001 + <_> + + <_> + + + + <_> + 6 10 6 4 -1. + <_> + 8 12 2 4 3. + 1 + -1.0117290169000626e-001 + 6.2204962968826294e-001 + -6.4412176609039307e-002 + <_> + + <_> + + + + <_> + 1 0 10 3 -1. + <_> + 1 1 10 1 3. + 0 + 4.2040869593620300e-002 + -8.5930466651916504e-002 + 4.9315661191940308e-001 + <_> + + <_> + + + + <_> + 0 13 6 6 -1. + <_> + 0 13 3 3 2. + <_> + 3 16 3 3 2. + 0 + 2.5582410395145416e-002 + 6.1051581054925919e-002 + -6.5449321269989014e-001 + <_> + + <_> + + + + <_> + 8 8 3 1 -1. + <_> + 9 9 1 1 3. + 1 + 1.0514019988477230e-002 + -1.0234809666872025e-001 + 2.6112779974937439e-001 + <_> + + <_> + + + + <_> + 0 7 2 2 -1. + <_> + 0 8 2 1 2. + 0 + 1.1631770030362532e-004 + -3.1768348813056946e-001 + 1.2542060017585754e-001 + <_> + + <_> + + + + <_> + 8 9 2 2 -1. + <_> + 8 9 1 2 2. + 0 + -4.4300020672380924e-003 + 1.9109399616718292e-001 + -5.2662618458271027e-002 + <_> + + <_> + + + + <_> + 2 9 2 2 -1. + <_> + 3 9 1 2 2. + 0 + 2.0806640386581421e-003 + -1.4428110420703888e-001 + 3.0112838745117188e-001 + <_> + + <_> + + + + <_> + 11 1 1 2 -1. + <_> + 11 2 1 1 2. + 0 + 5.4104570299386978e-003 + -5.4554589092731476e-002 + 3.5240170359611511e-001 + <_> + + <_> + + + + <_> + 5 0 1 3 -1. + <_> + 4 1 1 1 3. + 1 + 1.0801830329000950e-002 + 5.5018458515405655e-002 + -7.4443417787551880e-001 + <_> + + <_> + + + + <_> + 4 4 5 12 -1. + <_> + 4 8 5 4 3. + 0 + 4.2296931147575378e-002 + 6.1844110488891602e-002 + -3.3144399523735046e-001 + <_> + + <_> + + + + <_> + 0 0 3 3 -1. + <_> + 1 0 1 3 3. + 0 + 5.9895617887377739e-003 + 6.4745798707008362e-002 + -5.6030327081680298e-001 + <_> + + <_> + + + + <_> + 8 7 3 3 -1. + <_> + 9 8 1 3 3. + 1 + -9.4227874651551247e-003 + -3.0067789554595947e-001 + 4.3195281177759171e-002 + <_> + + <_> + + + + <_> + 4 7 3 3 -1. + <_> + 3 8 3 1 3. + 1 + -2.0783370360732079e-002 + 3.7524980306625366e-001 + -1.0968690365552902e-001 + <_> + + <_> + + + + <_> + 11 1 1 2 -1. + <_> + 11 2 1 1 2. + 0 + -5.2015861729159951e-004 + -1.1337819695472717e-001 + 3.7144880741834641e-002 + <_> + + <_> + + + + <_> + 0 1 1 2 -1. + <_> + 0 2 1 1 2. + 0 + -8.0162001540884376e-004 + -5.2545320987701416e-001 + 6.6209748387336731e-002 + <_> + + <_> + + + + <_> + 8 17 2 1 -1. + <_> + 8 17 1 1 2. + 1 + -2.5214110501110554e-003 + -1.5936410427093506e-001 + 5.1849711686372757e-002 + <_> + + <_> + + + + <_> + 4 17 1 2 -1. + <_> + 4 17 1 1 2. + 1 + 9.0704779722727835e-005 + -3.3334940671920776e-001 + 1.0919860005378723e-001 + <_> + + <_> + + + + <_> + 7 6 2 4 -1. + <_> + 8 6 1 2 2. + <_> + 7 8 1 2 2. + 0 + -1.8114539561793208e-003 + 1.1214060336351395e-001 + -9.0960927307605743e-002 + <_> + + <_> + + + + <_> + 6 8 6 6 -1. + <_> + 6 8 6 3 2. + 1 + -1.9519029557704926e-001 + -7.2080957889556885e-001 + 5.0182379782199860e-002 + <_> + + <_> + + + + <_> + 7 6 2 4 -1. + <_> + 8 6 1 2 2. + <_> + 7 8 1 2 2. + 0 + -1.4884449541568756e-002 + -6.0010558366775513e-001 + 9.1695934534072876e-003 + <_> + + <_> + + + + <_> + 3 6 2 4 -1. + <_> + 3 6 1 2 2. + <_> + 4 8 1 2 2. + 0 + -9.3493862077593803e-003 + 4.8005661368370056e-001 + -7.6954081654548645e-002 + <_> + + <_> + + + + <_> + 6 1 6 2 -1. + <_> + 8 3 2 2 3. + 1 + 7.1461386978626251e-002 + -5.7781968265771866e-002 + 2.6106640696525574e-001 + <_> + + <_> + + + + <_> + 0 11 6 5 -1. + <_> + 3 11 3 5 2. + 0 + 5.1590640097856522e-002 + 7.1806840598583221e-002 + -4.6015501022338867e-001 + <_> + + <_> + + + + <_> + 7 13 3 3 -1. + <_> + 8 13 1 3 3. + 0 + 3.0857140664011240e-003 + -9.2065691947937012e-002 + 1.1266019940376282e-001 + <_> + + <_> + + + + <_> + 2 13 3 3 -1. + <_> + 3 13 1 3 3. + 0 + 1.7517179949209094e-003 + -1.9908079504966736e-001 + 1.9879740476608276e-001 + <_> + + <_> + + + + <_> + 6 1 6 2 -1. + <_> + 8 3 2 2 3. + 1 + 6.3493461348116398e-003 + -1.0544289648532867e-001 + 4.3338119983673096e-002 + <_> + + <_> + + + + <_> + 6 1 2 6 -1. + <_> + 4 3 2 2 3. + 1 + 4.2910311371088028e-002 + 5.2926450967788696e-002 + -6.6493779420852661e-001 + <_> + + <_> + + + + <_> + 0 0 12 7 -1. + <_> + 0 0 6 7 2. + 0 + -2.8933840990066528e-001 + -5.9245282411575317e-001 + 5.0023719668388367e-002 + <_> + + <_> + + + + <_> + 1 9 10 3 -1. + <_> + 1 10 10 1 3. + 0 + 1.9839199259877205e-002 + 4.1037648916244507e-002 + -6.7570680379867554e-001 + <_> + + <_> + + + + <_> + 0 9 12 4 -1. + <_> + 0 10 12 2 2. + 0 + -2.9357530176639557e-002 + -6.5960741043090820e-001 + 4.1811358183622360e-002 + <_> + + <_> + + + + <_> + 0 5 3 15 -1. + <_> + 0 10 3 5 3. + 0 + 8.8180392980575562e-002 + 6.5817430615425110e-002 + -4.4950678944587708e-001 + <_> + + <_> + + + + <_> + 5 0 7 18 -1. + <_> + 5 9 7 9 2. + 0 + -1.3282440602779388e-001 + -2.1098449826240540e-001 + 3.9650738239288330e-002 + <_> + + <_> + + + + <_> + 0 0 4 5 -1. + <_> + 2 0 2 5 2. + 0 + 8.0266319855581969e-005 + -2.5888821482658386e-001 + 1.1488880217075348e-001 + -1.3127609491348267e+000 + 14 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 2 4 2 -1. + <_> + 4 2 2 1 2. + <_> + 6 3 2 1 2. + 0 + 6.5426998771727085e-003 + -2.2366699576377869e-001 + 4.7720021009445190e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 7 6 1 3 3. + 1 + -2.2333480592351407e-004 + 1.0184849798679352e-001 + -1.8614460527896881e-001 + <_> + + <_> + + + + <_> + 3 7 6 2 -1. + <_> + 3 7 3 1 2. + <_> + 6 8 3 1 2. + 0 + -6.0191731899976730e-003 + 3.1382268667221069e-001 + -2.3328569531440735e-001 + <_> + + <_> + + + + <_> + 1 8 10 10 -1. + <_> + 6 8 5 5 2. + <_> + 1 13 5 5 2. + 0 + 1.7179940640926361e-001 + -2.9191988706588745e-001 + 2.1794080734252930e-001 + <_> + + <_> + + + + <_> + 1 0 10 3 -1. + <_> + 1 1 10 1 3. + 0 + 1.6310229897499084e-002 + -1.4051440358161926e-001 + 3.2606941461563110e-001 + <_> + + <_> + + + + <_> + 0 17 12 3 -1. + <_> + 0 17 6 3 2. + 0 + -1.5107460319995880e-001 + 6.4690059423446655e-001 + -5.2486609667539597e-002 + <_> + + <_> + + + + <_> + 0 0 1 12 -1. + <_> + 0 6 1 6 2. + 0 + 4.6439900994300842e-002 + -2.4340909719467163e-001 + 2.6854258775711060e-001 + <_> + + <_> + + + + <_> + 10 17 2 1 -1. + <_> + 10 17 1 1 2. + 1 + -4.3716500513255596e-003 + -2.9228550195693970e-001 + 9.8407112061977386e-002 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 0 18 6 1 2. + <_> + 6 19 6 1 2. + 0 + 1.6864160075783730e-002 + -2.8363880515098572e-001 + 1.9571739435195923e-001 + <_> + + <_> + + + + <_> + 6 3 3 5 -1. + <_> + 7 4 1 5 3. + 1 + 2.5575649924576283e-003 + 4.4347479939460754e-002 + -1.3447460532188416e-001 + <_> + + <_> + + + + <_> + 6 3 5 3 -1. + <_> + 5 4 5 1 3. + 1 + 2.0957190543413162e-002 + -1.8374939262866974e-001 + 2.6384368538856506e-001 + <_> + + <_> + + + + <_> + 11 5 1 3 -1. + <_> + 11 6 1 1 3. + 0 + 4.1607948951423168e-003 + 4.9291279166936874e-002 + -6.1921811103820801e-001 + <_> + + <_> + + + + <_> + 0 5 1 3 -1. + <_> + 0 6 1 1 3. + 0 + 4.1489768773317337e-003 + 4.1641891002655029e-002 + -7.3988562822341919e-001 + <_> + + <_> + + + + <_> + 7 5 3 2 -1. + <_> + 8 6 1 2 3. + 1 + 2.1313559263944626e-002 + 2.3694250732660294e-002 + -5.6835669279098511e-001 + <_> + + <_> + + + + <_> + 5 5 2 3 -1. + <_> + 4 6 2 1 3. + 1 + 1.2101300060749054e-002 + -9.5187656581401825e-002 + 4.6901950240135193e-001 + <_> + + <_> + + + + <_> + 6 0 2 1 -1. + <_> + 6 0 1 1 2. + 0 + 1.8083410104736686e-003 + 4.7500770539045334e-002 + -3.0990800261497498e-001 + <_> + + <_> + + + + <_> + 5 0 2 2 -1. + <_> + 5 1 2 1 2. + 0 + -1.0990530252456665e-002 + 6.7560458183288574e-001 + -6.0268498957157135e-002 + <_> + + <_> + + + + <_> + 11 8 1 2 -1. + <_> + 11 9 1 1 2. + 0 + -8.9888361981138587e-004 + 1.6142509877681732e-001 + -8.0034710466861725e-002 + <_> + + <_> + + + + <_> + 0 8 1 2 -1. + <_> + 0 9 1 1 2. + 0 + 8.5803032561670989e-005 + -2.5957980751991272e-001 + 1.5043449401855469e-001 + <_> + + <_> + + + + <_> + 7 0 4 2 -1. + <_> + 9 0 2 1 2. + <_> + 7 1 2 1 2. + 0 + -1.0529270395636559e-002 + 4.8798549175262451e-001 + -1.0572060197591782e-001 + <_> + + <_> + + + + <_> + 4 0 2 2 -1. + <_> + 5 0 1 2 2. + 0 + -2.5140570942312479e-003 + -5.9965860843658447e-001 + 7.1445137262344360e-002 + <_> + + <_> + + + + <_> + 8 0 3 1 -1. + <_> + 9 1 1 1 3. + 1 + -2.0928360521793365e-002 + -6.3737767934799194e-001 + 1.1195439845323563e-002 + <_> + + <_> + + + + <_> + 0 4 8 12 -1. + <_> + 0 7 8 6 2. + 0 + 8.4567293524742126e-003 + 1.0487599670886993e-001 + -3.3027571439743042e-001 + <_> + + <_> + + + + <_> + 0 14 12 6 -1. + <_> + 0 16 12 2 3. + 0 + 1.1649870127439499e-001 + 4.9215629696846008e-002 + -7.1875381469726563e-001 + <_> + + <_> + + + + <_> + 4 0 1 3 -1. + <_> + 3 1 1 1 3. + 1 + 1.0911310091614723e-002 + 4.0617398917675018e-002 + -7.1910649538040161e-001 + <_> + + <_> + + + + <_> + 10 17 2 1 -1. + <_> + 10 17 1 1 2. + 1 + -2.4141639471054077e-002 + 4.6759098768234253e-001 + -3.2959330826997757e-002 + <_> + + <_> + + + + <_> + 2 17 1 2 -1. + <_> + 2 17 1 1 2. + 1 + 1.2029770296066999e-003 + -3.1624960899353027e-001 + 1.1505530029535294e-001 + <_> + + <_> + + + + <_> + 9 2 3 1 -1. + <_> + 10 3 1 1 3. + 1 + 9.8068173974752426e-003 + -3.6025181412696838e-002 + 1.7123579978942871e-001 + <_> + + <_> + + + + <_> + 3 2 1 3 -1. + <_> + 2 3 1 1 3. + 1 + 6.7418841645121574e-003 + 6.2854416668415070e-002 + -5.5376541614532471e-001 + <_> + + <_> + + + + <_> + 10 11 2 2 -1. + <_> + 10 12 2 1 2. + 0 + -1.3345720246434212e-002 + -7.5741612911224365e-001 + 9.3524847179651260e-003 + <_> + + <_> + + + + <_> + 0 9 12 8 -1. + <_> + 0 11 12 4 2. + 0 + 8.8471651077270508e-002 + 5.5774558335542679e-002 + -5.2644717693328857e-001 + <_> + + <_> + + + + <_> + 5 8 2 8 -1. + <_> + 5 10 2 4 2. + 0 + -1.4308050274848938e-002 + -5.0163388252258301e-001 + 6.1552900820970535e-002 + <_> + + <_> + + + + <_> + 5 5 1 2 -1. + <_> + 5 6 1 1 2. + 0 + 2.3234330583363771e-003 + -8.7273299694061279e-002 + 3.7597200274467468e-001 + <_> + + <_> + + + + <_> + 9 4 3 4 -1. + <_> + 9 5 3 2 2. + 0 + -6.6605149768292904e-003 + -5.6011527776718140e-001 + 4.5979429036378860e-002 + <_> + + <_> + + + + <_> + 1 7 4 1 -1. + <_> + 3 7 2 1 2. + 0 + -2.3684150073677301e-004 + 9.2453077435493469e-002 + -3.4188869595527649e-001 + <_> + + <_> + + + + <_> + 10 9 2 1 -1. + <_> + 10 9 1 1 2. + 0 + 5.2499719895422459e-003 + -1.0243079811334610e-001 + 3.8211381435394287e-001 + <_> + + <_> + + + + <_> + 0 9 2 1 -1. + <_> + 1 9 1 1 2. + 0 + 9.6710777143016458e-005 + -1.4891329407691956e-001 + 2.4878869950771332e-001 + <_> + + <_> + + + + <_> + 10 6 2 1 -1. + <_> + 10 6 1 1 2. + 1 + -3.1435599084943533e-003 + 2.0501570403575897e-001 + -5.9435389935970306e-002 + <_> + + <_> + + + + <_> + 2 6 1 2 -1. + <_> + 2 6 1 1 2. + 1 + -1.9189229351468384e-004 + 1.2612619996070862e-001 + -3.2496848702430725e-001 + <_> + + <_> + + + + <_> + 6 5 1 3 -1. + <_> + 6 6 1 1 3. + 0 + -4.6893218532204628e-003 + 3.2404568791389465e-001 + -3.2848190516233444e-002 + <_> + + <_> + + + + <_> + 0 4 1 3 -1. + <_> + 0 5 1 1 3. + 0 + 3.0783370602875948e-003 + 5.5750191211700439e-002 + -5.7443851232528687e-001 + <_> + + <_> + + + + <_> + 7 0 4 2 -1. + <_> + 9 0 2 1 2. + <_> + 7 1 2 1 2. + 0 + 1.3539710082113743e-002 + -3.2638911157846451e-002 + 4.8875731229782104e-001 + <_> + + <_> + + + + <_> + 1 0 4 2 -1. + <_> + 1 0 2 1 2. + <_> + 3 1 2 1 2. + 0 + 8.2393882621545345e-005 + -2.2491760551929474e-001 + 1.5178939700126648e-001 + <_> + + <_> + + + + <_> + 5 0 3 3 -1. + <_> + 6 0 1 3 3. + 0 + -9.3342671170830727e-003 + -5.7278221845626831e-001 + 4.6149488538503647e-002 + <_> + + <_> + + + + <_> + 4 11 3 3 -1. + <_> + 5 12 1 3 3. + 1 + 4.5541571453213692e-003 + -2.0548130571842194e-001 + 1.4704200625419617e-001 + <_> + + <_> + + + + <_> + 6 10 1 6 -1. + <_> + 6 10 1 3 2. + 1 + 2.4691719561815262e-002 + 2.0886249840259552e-002 + -5.6028658151626587e-001 + <_> + + <_> + + + + <_> + 2 9 2 1 -1. + <_> + 3 9 1 1 2. + 0 + 9.7412186732981354e-005 + -1.5648730099201202e-001 + 1.9009509682655334e-001 + <_> + + <_> + + + + <_> + 9 0 3 2 -1. + <_> + 9 1 3 1 2. + 0 + 5.7823117822408676e-003 + -1.2173660099506378e-001 + 2.1024130284786224e-001 + <_> + + <_> + + + + <_> + 6 11 6 1 -1. + <_> + 6 11 3 1 2. + 1 + -6.4938321709632874e-002 + 5.5764448642730713e-001 + -6.1514221131801605e-002 + <_> + + <_> + + + + <_> + 7 15 1 3 -1. + <_> + 6 16 1 1 3. + 1 + -5.9424177743494511e-003 + -4.4680491089820862e-001 + 5.5648550391197205e-002 + <_> + + <_> + + + + <_> + 2 16 6 2 -1. + <_> + 2 16 3 1 2. + <_> + 5 17 3 1 2. + 0 + -5.0992597825825214e-003 + 1.9794790446758270e-001 + -1.8055149912834167e-001 + <_> + + <_> + + + + <_> + 6 1 2 6 -1. + <_> + 6 1 1 6 2. + 1 + -1.5280229970812798e-002 + -8.6270570755004883e-002 + 3.5552538931369781e-002 + <_> + + <_> + + + + <_> + 6 1 6 2 -1. + <_> + 6 1 6 1 2. + 1 + -7.4432790279388428e-003 + 1.7408570647239685e-001 + -1.8400490283966064e-001 + <_> + + <_> + + + + <_> + 8 9 3 1 -1. + <_> + 9 9 1 1 3. + 0 + 5.1331128925085068e-003 + -8.8491149246692657e-002 + 3.1532418727874756e-001 + <_> + + <_> + + + + <_> + 1 9 3 1 -1. + <_> + 2 9 1 1 3. + 0 + 2.4648790713399649e-003 + -8.3607397973537445e-002 + 3.5939309000968933e-001 + -1.3777979612350464e+000 + 15 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 2 6 1 -1. + <_> + 8 4 2 1 3. + 1 + 3.2584890723228455e-002 + -2.9446709156036377e-001 + 3.8783320784568787e-001 + <_> + + <_> + + + + <_> + 7 7 2 4 -1. + <_> + 8 7 1 2 2. + <_> + 7 9 1 2 2. + 0 + -1.5954829752445221e-002 + -8.7387222051620483e-001 + 1.3140209950506687e-002 + <_> + + <_> + + + + <_> + 3 7 2 4 -1. + <_> + 3 7 1 2 2. + <_> + 4 9 1 2 2. + 0 + 6.5294029191136360e-003 + -1.8746000528335571e-001 + 3.4920379519462585e-001 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + -6.9139063358306885e-002 + -3.2066041231155396e-001 + 2.1070230752229691e-002 + <_> + + <_> + + + + <_> + 2 4 5 12 -1. + <_> + 2 7 5 6 2. + 0 + -2.7401080355048180e-002 + 1.6137300431728363e-001 + -3.3988159894943237e-001 + <_> + + <_> + + + + <_> + 5 0 7 18 -1. + <_> + 5 9 7 9 2. + 0 + 5.4834091663360596e-001 + -1.1290470138192177e-002 + -1.0005040168762207e+000 + <_> + + <_> + + + + <_> + 0 0 7 18 -1. + <_> + 0 9 7 9 2. + 0 + 4.6463169157505035e-002 + -7.0668822526931763e-001 + 5.8523610234260559e-002 + <_> + + <_> + + + + <_> + 11 9 1 6 -1. + <_> + 11 12 1 3 2. + 0 + 3.5692781209945679e-002 + -1.2722860090434551e-002 + 5.1669907569885254e-001 + <_> + + <_> + + + + <_> + 4 0 4 2 -1. + <_> + 4 0 2 1 2. + <_> + 6 1 2 1 2. + 0 + -8.8253971189260483e-003 + 3.5113370418548584e-001 + -1.2264049798250198e-001 + <_> + + <_> + + + + <_> + 11 7 1 6 -1. + <_> + 11 9 1 2 3. + 0 + -2.4928439408540726e-002 + -4.1226190328598022e-001 + 8.2819983363151550e-003 + <_> + + <_> + + + + <_> + 0 7 1 6 -1. + <_> + 0 9 1 2 3. + 0 + 8.3438487490639091e-004 + -3.1004768610000610e-001 + 1.2824219465255737e-001 + <_> + + <_> + + + + <_> + 5 0 2 3 -1. + <_> + 5 0 1 3 2. + 0 + 4.3677380308508873e-003 + 8.7895832955837250e-002 + -5.5109828710556030e-001 + <_> + + <_> + + + + <_> + 3 15 6 2 -1. + <_> + 3 15 3 1 2. + <_> + 6 16 3 1 2. + 0 + -6.0594570823013783e-003 + 2.3694829642772675e-001 + -1.6963149607181549e-001 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 6 13 1 3 2. + 1 + -1.3386299833655357e-002 + -2.9353159666061401e-001 + 3.3642090857028961e-002 + <_> + + <_> + + + + <_> + 0 11 8 5 -1. + <_> + 4 11 4 5 2. + 0 + 5.5047020316123962e-002 + 9.9271617829799652e-002 + -4.0973669290542603e-001 + <_> + + <_> + + + + <_> + 10 1 2 5 -1. + <_> + 10 1 1 5 2. + 0 + 1.7345769330859184e-002 + -1.0950370132923126e-001 + 4.2251870036125183e-001 + <_> + + <_> + + + + <_> + 0 7 12 13 -1. + <_> + 6 7 6 13 2. + 0 + 5.1694452762603760e-001 + -5.7410959154367447e-002 + 6.4137631654739380e-001 + <_> + + <_> + + + + <_> + 8 8 3 8 -1. + <_> + 6 10 3 4 2. + 1 + 6.5628431737422943e-002 + 3.3641148358583450e-002 + -6.0003411769866943e-001 + <_> + + <_> + + + + <_> + 4 8 8 3 -1. + <_> + 6 10 4 3 2. + 1 + 1.0161089897155762e-001 + -2.5070580840110779e-001 + 1.8186099827289581e-001 + <_> + + <_> + + + + <_> + 1 0 10 3 -1. + <_> + 1 1 10 1 3. + 0 + 2.9830370098352432e-002 + -1.1608160287141800e-001 + 3.5246831178665161e-001 + <_> + + <_> + + + + <_> + 0 2 1 2 -1. + <_> + 0 3 1 1 2. + 0 + -6.6538550890982151e-004 + -5.6480127573013306e-001 + 6.4513862133026123e-002 + <_> + + <_> + + + + <_> + 9 12 2 3 -1. + <_> + 9 13 2 1 3. + 0 + 8.9011844247579575e-003 + 3.7113070487976074e-002 + -6.2943869829177856e-001 + <_> + + <_> + + + + <_> + 1 12 2 3 -1. + <_> + 1 13 2 1 3. + 0 + -5.7988148182630539e-003 + 3.3002421259880066e-001 + -1.1569269746541977e-001 + <_> + + <_> + + + + <_> + 9 0 3 1 -1. + <_> + 10 1 1 1 3. + 1 + 1.8202450126409531e-002 + 2.2297389805316925e-002 + -6.8679827451705933e-001 + <_> + + <_> + + + + <_> + 3 0 1 3 -1. + <_> + 2 1 1 1 3. + 1 + -6.3430098816752434e-003 + -5.9504687786102295e-001 + 5.3902018815279007e-002 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + 1.0256610065698624e-001 + 1.1425909586250782e-002 + -3.4088680148124695e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + -2.1729130297899246e-002 + 1.0024060308933258e-001 + -3.6016431450843811e-001 + <_> + + <_> + + + + <_> + 7 5 2 3 -1. + <_> + 7 5 1 3 2. + 1 + -4.0402188897132874e-002 + -7.9971337318420410e-001 + 1.0374830104410648e-002 + <_> + + <_> + + + + <_> + 5 5 3 2 -1. + <_> + 5 5 3 1 2. + 1 + -1.1156830005347729e-002 + 4.1818261146545410e-001 + -1.0622619837522507e-001 + <_> + + <_> + + + + <_> + 8 10 2 1 -1. + <_> + 8 10 1 1 2. + 0 + 1.0242810240015388e-003 + -7.2071209549903870e-002 + 9.9886089563369751e-002 + <_> + + <_> + + + + <_> + 2 10 2 1 -1. + <_> + 3 10 1 1 2. + 0 + 9.5549278194084764e-004 + -1.6656149923801422e-001 + 2.7860009670257568e-001 + <_> + + <_> + + + + <_> + 4 4 4 2 -1. + <_> + 4 5 4 1 2. + 0 + 1.3702700380235910e-004 + -3.1575959920883179e-001 + 1.1808790266513824e-001 + <_> + + <_> + + + + <_> + 0 9 12 9 -1. + <_> + 3 9 6 9 2. + 0 + -1.9174149632453918e-001 + 5.2235382795333862e-001 + -7.6672300696372986e-002 + <_> + + <_> + + + + <_> + 9 12 1 3 -1. + <_> + 9 13 1 1 3. + 0 + 2.5123620871454477e-003 + -8.5517987608909607e-002 + 2.7882871031761169e-001 + <_> + + <_> + + + + <_> + 2 12 1 3 -1. + <_> + 2 13 1 1 3. + 0 + 3.6384440027177334e-003 + -1.0173840075731277e-001 + 3.6575859785079956e-001 + <_> + + <_> + + + + <_> + 6 12 3 5 -1. + <_> + 7 13 1 5 3. + 1 + -9.1068800538778305e-003 + -1.9999110698699951e-001 + 3.5431660711765289e-002 + <_> + + <_> + + + + <_> + 6 12 5 3 -1. + <_> + 5 13 5 1 3. + 1 + -2.5456059724092484e-002 + -6.6976618766784668e-001 + 5.1672291010618210e-002 + <_> + + <_> + + + + <_> + 3 17 6 3 -1. + <_> + 3 18 6 1 3. + 0 + -2.5856729596853256e-002 + -7.3498648405075073e-001 + 2.7689380571246147e-002 + <_> + + <_> + + + + <_> + 5 15 2 4 -1. + <_> + 5 16 2 2 2. + 0 + 8.5871294140815735e-003 + -1.1443380266427994e-001 + 2.7319890260696411e-001 + <_> + + <_> + + + + <_> + 7 18 3 2 -1. + <_> + 8 18 1 2 3. + 0 + 3.5716209094971418e-003 + 6.0280900448560715e-002 + -2.6631888747215271e-001 + <_> + + <_> + + + + <_> + 1 4 2 4 -1. + <_> + 1 5 2 2 2. + 0 + 1.0332760401070118e-002 + 3.8581959903240204e-002 + -6.7532962560653687e-001 + <_> + + <_> + + + + <_> + 10 4 2 3 -1. + <_> + 9 5 2 1 3. + 1 + -8.3224009722471237e-003 + 2.5268268585205078e-001 + -6.8770729005336761e-002 + <_> + + <_> + + + + <_> + 2 4 3 2 -1. + <_> + 3 5 1 2 3. + 1 + -1.8182119820266962e-003 + -3.1761169433593750e-001 + 9.2666782438755035e-002 + <_> + + <_> + + + + <_> + 6 5 3 1 -1. + <_> + 7 6 1 1 3. + 1 + -1.3169780373573303e-002 + -5.3651332855224609e-001 + 2.8106879442930222e-002 + <_> + + <_> + + + + <_> + 6 6 2 3 -1. + <_> + 5 7 2 1 3. + 1 + 2.0408600568771362e-002 + -6.0603220015764236e-002 + 5.0572431087493896e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 8 5 2 6 3. + 1 + 1.7321230471134186e-001 + 2.1015009842813015e-003 + 3.2260191440582275e-001 + <_> + + <_> + + + + <_> + 6 3 6 6 -1. + <_> + 4 5 6 2 3. + 1 + -5.8910921216011047e-002 + 1.4044930040836334e-001 + -2.0362600684165955e-001 + <_> + + <_> + + + + <_> + 10 4 2 3 -1. + <_> + 10 5 2 1 3. + 0 + 4.9123559147119522e-003 + 7.1367353200912476e-002 + -5.0733560323715210e-001 + <_> + + <_> + + + + <_> + 0 18 1 2 -1. + <_> + 0 19 1 1 2. + 0 + -1.3819620653521270e-004 + 7.6624020934104919e-002 + -3.4903231263160706e-001 + <_> + + <_> + + + + <_> + 0 1 12 8 -1. + <_> + 0 5 12 4 2. + 0 + 1.2017219560220838e-003 + -5.1169282197952271e-001 + 5.4793931543827057e-002 + <_> + + <_> + + + + <_> + 0 4 2 3 -1. + <_> + 0 5 2 1 3. + 0 + -5.4135429672896862e-003 + -5.0181478261947632e-001 + 5.0226181745529175e-002 + <_> + + <_> + + + + <_> + 7 6 3 2 -1. + <_> + 8 7 1 2 3. + 1 + -3.3707648515701294e-002 + -8.5764700174331665e-001 + 4.7642397694289684e-003 + <_> + + <_> + + + + <_> + 5 6 2 3 -1. + <_> + 4 7 2 1 3. + 1 + 1.2718940153717995e-002 + -1.0830610245466232e-001 + 2.8867751359939575e-001 + <_> + + <_> + + + + <_> + 6 4 3 2 -1. + <_> + 7 5 1 2 3. + 1 + -2.0672269165515900e-002 + -3.0906811356544495e-001 + 2.1581029519438744e-002 + <_> + + <_> + + + + <_> + 6 4 2 3 -1. + <_> + 5 5 2 1 3. + 1 + 1.5933969989418983e-002 + -8.3755359053611755e-002 + 4.1743949055671692e-001 + <_> + + <_> + + + + <_> + 5 0 3 2 -1. + <_> + 6 0 1 2 3. + 0 + 9.3405526131391525e-003 + 4.7591928392648697e-002 + -6.5143817663192749e-001 + <_> + + <_> + + + + <_> + 5 15 3 2 -1. + <_> + 5 15 3 1 2. + 1 + 1.3016579672694206e-002 + 5.3528260439634323e-002 + -4.8644289374351501e-001 + -1.2673230171203613e+000 + 16 + -1 + <_> + + + <_> + + <_> + + + + <_> + 5 0 1 3 -1. + <_> + 5 1 1 1 3. + 0 + 5.0423052161931992e-003 + -2.2111539542675018e-001 + 4.3673288822174072e-001 + <_> + + <_> + + + + <_> + 5 4 4 3 -1. + <_> + 5 5 4 1 3. + 0 + 3.3594230189919472e-003 + -1.7003799974918365e-001 + 1.2387859821319580e-001 + <_> + + <_> + + + + <_> + 3 6 3 3 -1. + <_> + 4 7 1 1 9. + 0 + -2.2854709997773170e-002 + 3.0707350373268127e-001 + -1.9186529517173767e-001 + <_> + + <_> + + + + <_> + 7 16 1 4 -1. + <_> + 7 18 1 2 2. + 0 + 4.3850108049809933e-003 + 3.2038759440183640e-002 + -1.4620819687843323e-001 + <_> + + <_> + + + + <_> + 4 16 1 4 -1. + <_> + 4 18 1 2 2. + 0 + -5.3011639975011349e-003 + 1.6375949978828430e-001 + -2.8174880146980286e-001 + <_> + + <_> + + + + <_> + 6 13 1 6 -1. + <_> + 6 13 1 3 2. + 1 + 4.9680870026350021e-002 + 4.2250480502843857e-002 + -6.0391640663146973e-001 + <_> + + <_> + + + + <_> + 6 13 6 1 -1. + <_> + 6 13 3 1 2. + 1 + -5.1453109830617905e-002 + 6.5720152854919434e-001 + -7.0812806487083435e-002 + <_> + + <_> + + + + <_> + 6 7 1 6 -1. + <_> + 4 9 1 2 3. + 1 + 2.7113489806652069e-002 + 2.9805190861225128e-002 + -4.0825900435447693e-001 + <_> + + <_> + + + + <_> + 6 7 6 1 -1. + <_> + 8 9 2 1 3. + 1 + 2.3578230291604996e-002 + -3.0918011069297791e-001 + 2.1382910013198853e-001 + <_> + + <_> + + + + <_> + 11 9 1 6 -1. + <_> + 11 12 1 3 2. + 0 + 2.9583559371531010e-003 + 2.3970389738678932e-002 + -1.6768220067024231e-001 + <_> + + <_> + + + + <_> + 0 9 1 6 -1. + <_> + 0 12 1 3 2. + 0 + -2.8374159592203796e-004 + 1.9550369679927826e-001 + -2.6317828893661499e-001 + <_> + + <_> + + + + <_> + 0 0 12 1 -1. + <_> + 3 0 6 1 2. + 0 + 3.8295589387416840e-002 + -8.1490896642208099e-002 + 4.1922101378440857e-001 + <_> + + <_> + + + + <_> + 3 0 6 8 -1. + <_> + 3 4 6 4 2. + 0 + -1.0575760155916214e-002 + -5.5699461698532104e-001 + 6.0772120952606201e-002 + <_> + + <_> + + + + <_> + 3 3 6 12 -1. + <_> + 3 7 6 4 3. + 0 + -1.3283690204843879e-003 + 9.2958763241767883e-002 + -3.3554950356483459e-001 + <_> + + <_> + + + + <_> + 4 6 1 2 -1. + <_> + 4 7 1 1 2. + 0 + 1.8217159667983651e-003 + -9.9800482392311096e-002 + 3.8015770912170410e-001 + <_> + + <_> + + + + <_> + 11 0 1 2 -1. + <_> + 11 1 1 1 2. + 0 + -1.8067359924316406e-003 + -5.1108711957931519e-001 + 6.8366326391696930e-002 + <_> + + <_> + + + + <_> + 0 12 8 3 -1. + <_> + 4 12 4 3 2. + 0 + 6.6835001111030579e-002 + 3.1457249075174332e-002 + -6.9415211677551270e-001 + <_> + + <_> + + + + <_> + 10 0 2 4 -1. + <_> + 11 0 1 2 2. + <_> + 10 2 1 2 2. + 0 + -1.3109239749610424e-002 + 6.0284411907196045e-001 + -8.0423787236213684e-002 + <_> + + <_> + + + + <_> + 0 0 2 4 -1. + <_> + 0 0 1 2 2. + <_> + 1 2 1 2 2. + 0 + -1.9930349662899971e-003 + -4.1979709267616272e-001 + 8.9367941021919250e-002 + <_> + + <_> + + + + <_> + 10 0 2 1 -1. + <_> + 10 0 1 1 2. + 0 + -1.0855719447135925e-003 + -2.4703420698642731e-001 + 5.2764680236577988e-002 + <_> + + <_> + + + + <_> + 0 0 2 1 -1. + <_> + 1 0 1 1 2. + 0 + -2.0320110488682985e-003 + -6.1820042133331299e-001 + 5.1938790827989578e-002 + <_> + + <_> + + + + <_> + 10 9 2 6 -1. + <_> + 11 9 1 3 2. + <_> + 10 12 1 3 2. + 0 + 1.6026819124817848e-002 + -8.5486106574535370e-002 + 5.8234047889709473e-001 + <_> + + <_> + + + + <_> + 0 10 12 3 -1. + <_> + 0 11 12 1 3. + 0 + 1.7896020784974098e-002 + 6.8894177675247192e-002 + -5.8082962036132813e-001 + <_> + + <_> + + + + <_> + 7 11 1 3 -1. + <_> + 7 12 1 1 3. + 0 + -2.4853560607880354e-003 + 2.0646420121192932e-001 + -6.0466051101684570e-002 + <_> + + <_> + + + + <_> + 4 11 1 3 -1. + <_> + 4 12 1 1 3. + 0 + -1.8073250539600849e-003 + 2.5038561224937439e-001 + -1.3862800598144531e-001 + <_> + + <_> + + + + <_> + 6 11 2 3 -1. + <_> + 6 12 2 1 3. + 0 + -1.1800680309534073e-002 + -5.5517327785491943e-001 + 2.3907609283924103e-002 + <_> + + <_> + + + + <_> + 4 11 2 3 -1. + <_> + 4 12 2 1 3. + 0 + 5.3180782124400139e-003 + -1.0365380346775055e-001 + 3.5622540116310120e-001 + <_> + + <_> + + + + <_> + 6 0 3 1 -1. + <_> + 7 1 1 1 3. + 1 + -1.9885929941665381e-004 + 7.9137459397315979e-002 + -7.1248553693294525e-002 + <_> + + <_> + + + + <_> + 6 0 1 3 -1. + <_> + 5 1 1 1 3. + 1 + 1.2722889892756939e-002 + 3.6043450236320496e-002 + -7.7585661411285400e-001 + <_> + + <_> + + + + <_> + 4 1 4 2 -1. + <_> + 6 1 2 1 2. + <_> + 4 2 2 1 2. + 0 + 5.4894611239433289e-003 + -1.1198099702596664e-001 + 2.9539060592651367e-001 + <_> + + <_> + + + + <_> + 6 0 2 6 -1. + <_> + 4 2 2 2 3. + 1 + 3.1117599457502365e-002 + 6.8027697503566742e-002 + -4.7621628642082214e-001 + <_> + + <_> + + + + <_> + 10 9 2 6 -1. + <_> + 11 9 1 3 2. + <_> + 10 12 1 3 2. + 0 + -1.0922919958829880e-002 + 3.7011030316352844e-001 + -1.5059700608253479e-001 + <_> + + <_> + + + + <_> + 0 9 2 6 -1. + <_> + 0 9 1 3 2. + <_> + 1 12 1 3 2. + 0 + -1.7167469486594200e-003 + 2.7644971013069153e-001 + -1.1304590106010437e-001 + <_> + + <_> + + + + <_> + 3 8 6 2 -1. + <_> + 3 9 6 1 2. + 0 + -1.3501050416380167e-003 + -3.5303080081939697e-001 + 9.9187247455120087e-002 + <_> + + <_> + + + + <_> + 0 8 12 3 -1. + <_> + 0 9 12 1 3. + 0 + 1.9909780472517014e-002 + 6.5169408917427063e-002 + -4.9353629350662231e-001 + <_> + + <_> + + + + <_> + 6 4 3 2 -1. + <_> + 7 5 1 2 3. + 1 + 2.3044180124998093e-002 + 1.7247360199689865e-002 + -3.9788180589675903e-001 + <_> + + <_> + + + + <_> + 6 4 2 3 -1. + <_> + 5 5 2 1 3. + 1 + 9.6177039667963982e-003 + -1.1394459754228592e-001 + 3.1357648968696594e-001 + <_> + + <_> + + + + <_> + 11 7 1 2 -1. + <_> + 11 8 1 1 2. + 0 + -7.6275239698588848e-003 + -9.2318731546401978e-001 + 7.8877164050936699e-003 + <_> + + <_> + + + + <_> + 0 7 1 2 -1. + <_> + 0 8 1 1 2. + 0 + 8.7190303020179272e-005 + -3.0970078706741333e-001 + 9.5611982047557831e-002 + <_> + + <_> + + + + <_> + 5 0 4 2 -1. + <_> + 7 0 2 1 2. + <_> + 5 1 2 1 2. + 0 + -1.1889990419149399e-002 + 4.7901371121406555e-001 + -3.5577189177274704e-002 + <_> + + <_> + + + + <_> + 4 0 3 3 -1. + <_> + 5 0 1 3 3. + 0 + 8.4557365626096725e-003 + 5.2709650248289108e-002 + -5.7321697473526001e-001 + <_> + + <_> + + + + <_> + 8 5 2 3 -1. + <_> + 8 5 1 3 2. + 1 + 1.1996040120720863e-002 + 1.9709009677171707e-002 + -6.9532912969589233e-001 + <_> + + <_> + + + + <_> + 2 0 6 2 -1. + <_> + 2 0 3 1 2. + <_> + 5 1 3 1 2. + 0 + -2.7005810290575027e-002 + 5.9652292728424072e-001 + -5.1673818379640579e-002 + <_> + + <_> + + + + <_> + 10 17 1 3 -1. + <_> + 10 18 1 1 3. + 0 + 1.8543410114943981e-003 + 7.2791919112205505e-002 + -5.0846791267395020e-001 + <_> + + <_> + + + + <_> + 0 0 4 4 -1. + <_> + 0 2 4 2 2. + 0 + 7.5675587868317962e-004 + -3.8867241144180298e-001 + 6.5925061702728271e-002 + <_> + + <_> + + + + <_> + 8 5 2 3 -1. + <_> + 8 5 1 3 2. + 1 + -3.8905180990695953e-002 + -6.0740387439727783e-001 + 3.5101689863950014e-003 + <_> + + <_> + + + + <_> + 4 5 3 2 -1. + <_> + 4 5 3 1 2. + 1 + -5.7714940048754215e-003 + 1.7274090647697449e-001 + -1.7644210159778595e-001 + <_> + + <_> + + + + <_> + 6 5 3 1 -1. + <_> + 7 6 1 1 3. + 1 + -9.1350553557276726e-003 + -2.8621628880500793e-001 + 3.0258299782872200e-002 + <_> + + <_> + + + + <_> + 6 5 1 3 -1. + <_> + 5 6 1 1 3. + 1 + 4.5439298264682293e-003 + -8.5076972842216492e-002 + 4.1360539197921753e-001 + <_> + + <_> + + + + <_> + 10 1 2 7 -1. + <_> + 10 1 1 7 2. + 0 + 1.5785360708832741e-002 + -9.6528999507427216e-002 + 2.8125289082527161e-001 + <_> + + <_> + + + + <_> + 0 1 2 8 -1. + <_> + 1 1 1 8 2. + 0 + 1.7944289371371269e-002 + 5.0230890512466431e-002 + -6.4134520292282104e-001 + <_> + + <_> + + + + <_> + 11 11 1 6 -1. + <_> + 11 11 1 3 2. + 1 + -3.8975570350885391e-002 + -2.5966680049896240e-001 + 3.0592629685997963e-002 + <_> + + <_> + + + + <_> + 1 11 6 1 -1. + <_> + 1 11 3 1 2. + 1 + 5.2373361540958285e-004 + 1.0446350276470184e-001 + -3.1365889310836792e-001 + <_> + + <_> + + + + <_> + 6 3 6 3 -1. + <_> + 8 5 2 3 3. + 1 + -2.5457229465246201e-002 + -1.6731269657611847e-001 + 3.7427790462970734e-002 + <_> + + <_> + + + + <_> + 0 2 6 6 -1. + <_> + 2 4 2 2 9. + 0 + -4.2908679693937302e-002 + -4.0295800566673279e-001 + 6.5455727279186249e-002 + <_> + + <_> + + + + <_> + 8 3 4 1 -1. + <_> + 9 4 2 1 2. + 1 + -5.1728109829127789e-003 + 3.1299790740013123e-001 + -7.0367880165576935e-002 + <_> + + <_> + + + + <_> + 4 3 1 4 -1. + <_> + 3 4 1 2 2. + 1 + -1.8753990298137069e-004 + 1.5299630165100098e-001 + -2.0695990324020386e-001 + <_> + + <_> + + + + <_> + 4 14 4 2 -1. + <_> + 6 14 2 1 2. + <_> + 4 15 2 1 2. + 0 + -1.9984589889645576e-003 + 2.6436290144920349e-001 + -1.0118020325899124e-001 + <_> + + <_> + + + + <_> + 5 16 1 4 -1. + <_> + 5 17 1 2 2. + 0 + -3.7929560057818890e-003 + 2.8518161177635193e-001 + -1.0743419826030731e-001 + <_> + + <_> + + + + <_> + 6 12 3 5 -1. + <_> + 7 13 1 5 3. + 1 + 4.5540980994701385e-002 + 4.5009840279817581e-002 + -2.0425949990749359e-001 + <_> + + <_> + + + + <_> + 6 12 5 3 -1. + <_> + 5 13 5 1 3. + 1 + 2.4831600487232208e-002 + 4.9255561083555222e-002 + -6.0236537456512451e-001 + -1.3531359434127808e+000 + 17 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 2 4 2 -1. + <_> + 4 2 2 1 2. + <_> + 6 3 2 1 2. + 0 + 3.9991321973502636e-003 + -2.6711270213127136e-001 + 3.5392650961875916e-001 + <_> + + <_> + + + + <_> + 8 8 3 3 -1. + <_> + 9 9 1 3 3. + 1 + 1.1023290455341339e-002 + -1.0786689817905426e-001 + 1.0729049891233444e-001 + <_> + + <_> + + + + <_> + 5 4 5 3 -1. + <_> + 4 5 5 1 3. + 1 + -3.7521351128816605e-002 + 3.0647391080856323e-001 + -2.1749919652938843e-001 + <_> + + <_> + + + + <_> + 9 17 2 3 -1. + <_> + 9 18 2 1 3. + 0 + -2.7670729905366898e-003 + -3.9869681000709534e-001 + 8.7402120232582092e-002 + <_> + + <_> + + + + <_> + 1 17 2 3 -1. + <_> + 1 18 2 1 3. + 0 + 1.9890109542757273e-003 + -3.2719919085502625e-001 + 2.0264029502868652e-001 + <_> + + <_> + + + + <_> + 8 2 4 10 -1. + <_> + 10 2 2 5 2. + <_> + 8 7 2 5 2. + 0 + 1.9364669919013977e-002 + -5.1705140620470047e-002 + 1.2021850049495697e-001 + <_> + + <_> + + + + <_> + 0 2 4 10 -1. + <_> + 0 2 2 5 2. + <_> + 2 7 2 5 2. + 0 + -1.1918369680643082e-002 + 1.2546530365943909e-001 + -3.7106749415397644e-001 + <_> + + <_> + + + + <_> + 0 13 12 5 -1. + <_> + 3 13 6 5 2. + 0 + 9.5910847187042236e-002 + -1.7389330267906189e-001 + 2.2600440680980682e-001 + <_> + + <_> + + + + <_> + 0 18 12 2 -1. + <_> + 6 18 6 2 2. + 0 + 1.0751710087060928e-001 + -7.8588336706161499e-002 + 5.7250618934631348e-001 + <_> + + <_> + + + + <_> + 4 14 5 6 -1. + <_> + 4 17 5 3 2. + 0 + -3.1022340059280396e-002 + 1.4575169980525970e-001 + -3.2396531105041504e-001 + <_> + + <_> + + + + <_> + 0 0 12 3 -1. + <_> + 0 1 12 1 3. + 0 + 1.6883790493011475e-002 + -1.6565980017185211e-001 + 2.9082998633384705e-001 + <_> + + <_> + + + + <_> + 0 3 12 2 -1. + <_> + 0 4 12 1 2. + 0 + 5.0262849981663749e-005 + -5.7035660743713379e-001 + 6.2110569328069687e-002 + <_> + + <_> + + + + <_> + 0 0 8 8 -1. + <_> + 2 0 4 8 2. + 0 + 9.1006923466920853e-003 + 5.5405318737030029e-002 + -4.9272969365119934e-001 + <_> + + <_> + + + + <_> + 6 10 6 3 -1. + <_> + 6 10 3 3 2. + 1 + -1.6937600076198578e-001 + 5.4915368556976318e-001 + -3.9581310003995895e-002 + <_> + + <_> + + + + <_> + 4 10 6 4 -1. + <_> + 4 10 6 2 2. + 1 + 1.9913749769330025e-002 + 9.4958506524562836e-002 + -5.1041561365127563e-001 + <_> + + <_> + + + + <_> + 6 0 2 2 -1. + <_> + 7 0 1 1 2. + <_> + 6 1 1 1 2. + 0 + 3.0223759822547436e-003 + -6.3331179320812225e-002 + 2.0407359302043915e-001 + <_> + + <_> + + + + <_> + 4 0 2 2 -1. + <_> + 4 0 1 1 2. + <_> + 5 1 1 1 2. + 0 + -4.5423391275107861e-003 + 4.2783120274543762e-001 + -7.8888073563575745e-002 + <_> + + <_> + + + + <_> + 7 13 5 2 -1. + <_> + 7 13 5 1 2. + 1 + -3.5147000104188919e-002 + -6.1061471700668335e-001 + 2.5506079196929932e-002 + <_> + + <_> + + + + <_> + 0 0 1 3 -1. + <_> + 0 1 1 1 3. + 0 + 2.0077088847756386e-003 + 6.3804052770137787e-002 + -4.4934588670730591e-001 + <_> + + <_> + + + + <_> + 11 0 1 2 -1. + <_> + 11 1 1 1 2. + 0 + -1.5540630556643009e-003 + -4.0192028880119324e-001 + 3.1636688858270645e-002 + <_> + + <_> + + + + <_> + 5 5 3 3 -1. + <_> + 4 6 3 1 3. + 1 + 1.4254899695515633e-002 + -7.9566307365894318e-002 + 3.8706529140472412e-001 + <_> + + <_> + + + + <_> + 6 3 3 4 -1. + <_> + 7 4 1 4 3. + 1 + 1.1024920269846916e-002 + 6.7027233541011810e-002 + -2.8063619136810303e-001 + <_> + + <_> + + + + <_> + 3 6 2 4 -1. + <_> + 3 6 1 2 2. + <_> + 4 8 1 2 2. + 0 + -5.1981899887323380e-003 + 3.6570119857788086e-001 + -1.1679860204458237e-001 + <_> + + <_> + + + + <_> + 7 13 5 2 -1. + <_> + 7 13 5 1 2. + 1 + 4.9434448592364788e-003 + 4.9997199326753616e-002 + -1.4642210304737091e-001 + <_> + + <_> + + + + <_> + 5 13 2 5 -1. + <_> + 5 13 1 5 2. + 1 + -1.6670800745487213e-002 + -4.9238750338554382e-001 + 6.1317440122365952e-002 + <_> + + <_> + + + + <_> + 11 0 1 2 -1. + <_> + 11 1 1 1 2. + 0 + 7.7939140610396862e-003 + -2.9953140765428543e-002 + 2.3316749930381775e-001 + <_> + + <_> + + + + <_> + 0 0 1 2 -1. + <_> + 0 1 1 1 2. + 0 + -1.4590610517188907e-003 + -5.7006311416625977e-001 + 5.3406499326229095e-002 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 5 6 3 1 3. + 1 + -2.2517830133438110e-002 + 1.1464659869670868e-001 + -1.2585699558258057e-001 + <_> + + <_> + + + + <_> + 6 5 3 3 -1. + <_> + 7 6 1 3 3. + 1 + 1.4919370412826538e-002 + 5.2204128354787827e-002 + -5.6187790632247925e-001 + <_> + + <_> + + + + <_> + 0 15 12 5 -1. + <_> + 3 15 6 5 2. + 0 + -1.8656760454177856e-001 + 6.0989791154861450e-001 + -5.0142709165811539e-002 + <_> + + <_> + + + + <_> + 3 17 1 2 -1. + <_> + 3 17 1 1 2. + 1 + 1.2466400221455842e-004 + -3.2725819945335388e-001 + 8.6407169699668884e-002 + <_> + + <_> + + + + <_> + 8 9 3 2 -1. + <_> + 9 9 1 2 3. + 0 + -8.5008898749947548e-003 + 4.0898931026458740e-001 + -8.6464531719684601e-002 + <_> + + <_> + + + + <_> + 1 14 4 6 -1. + <_> + 1 14 2 3 2. + <_> + 3 17 2 3 2. + 0 + 1.4465590007603168e-002 + 5.5936750024557114e-002 + -5.2939140796661377e-001 + <_> + + <_> + + + + <_> + 8 9 3 2 -1. + <_> + 9 9 1 2 3. + 0 + 1.1536439880728722e-002 + -9.3967936933040619e-002 + 4.0461421012878418e-001 + <_> + + <_> + + + + <_> + 2 9 8 3 -1. + <_> + 2 10 8 1 3. + 0 + 1.6789000481367111e-002 + 4.9098148941993713e-002 + -6.1509531736373901e-001 + <_> + + <_> + + + + <_> + 8 9 3 2 -1. + <_> + 9 9 1 2 3. + 0 + -2.9727790970355272e-003 + 1.5688349306583405e-001 + -7.9878687858581543e-002 + <_> + + <_> + + + + <_> + 3 12 1 3 -1. + <_> + 3 13 1 1 3. + 0 + 2.7876989915966988e-003 + -1.1298049986362457e-001 + 2.3814339935779572e-001 + <_> + + <_> + + + + <_> + 8 12 1 3 -1. + <_> + 8 13 1 1 3. + 0 + 2.6815771125257015e-003 + -6.3131898641586304e-002 + 1.7341490089893341e-001 + <_> + + <_> + + + + <_> + 3 12 1 3 -1. + <_> + 3 13 1 1 3. + 0 + -1.6932430444285274e-003 + 2.9134979844093323e-001 + -9.7688913345336914e-002 + <_> + + <_> + + + + <_> + 9 3 3 6 -1. + <_> + 10 5 1 2 9. + 0 + -2.1838879212737083e-002 + 2.2410179674625397e-001 + -6.3271783292293549e-002 + <_> + + <_> + + + + <_> + 0 3 3 6 -1. + <_> + 1 5 1 2 9. + 0 + -4.6455059200525284e-002 + -6.6729080677032471e-001 + 4.1569691151380539e-002 + <_> + + <_> + + + + <_> + 6 4 6 16 -1. + <_> + 6 12 6 8 2. + 0 + 3.4257268905639648e-001 + -4.3775469064712524e-002 + 4.2250889539718628e-001 + <_> + + <_> + + + + <_> + 1 9 3 2 -1. + <_> + 2 9 1 2 3. + 0 + -9.7134057432413101e-003 + 2.8876009583473206e-001 + -1.0904739797115326e-001 + <_> + + <_> + + + + <_> + 8 5 2 6 -1. + <_> + 9 5 1 3 2. + <_> + 8 8 1 3 2. + 0 + -1.9520539790391922e-003 + 1.1463859677314758e-001 + -1.0175020247697830e-001 + <_> + + <_> + + + + <_> + 2 5 2 6 -1. + <_> + 2 5 1 3 2. + <_> + 3 8 1 3 2. + 0 + -1.8771419301629066e-002 + 6.2400698661804199e-001 + -5.0913780927658081e-002 + <_> + + <_> + + + + <_> + 0 2 12 18 -1. + <_> + 6 2 6 9 2. + <_> + 0 11 6 9 2. + 0 + 2.5264939665794373e-001 + -2.2805340588092804e-001 + 1.4274069666862488e-001 + <_> + + <_> + + + + <_> + 0 13 12 4 -1. + <_> + 0 13 6 2 2. + <_> + 6 15 6 2 2. + 0 + -7.8301310539245605e-002 + -4.9581411480903625e-001 + 5.4817609488964081e-002 + <_> + + <_> + + + + <_> + 0 4 12 12 -1. + <_> + 0 7 12 6 2. + 0 + -1.6115349531173706e-001 + -5.7617807388305664e-001 + 4.2033191770315170e-002 + <_> + + <_> + + + + <_> + 4 14 3 6 -1. + <_> + 5 14 1 6 3. + 0 + 1.3769039884209633e-002 + 4.6666219830513000e-002 + -5.0551378726959229e-001 + <_> + + <_> + + + + <_> + 6 11 2 3 -1. + <_> + 6 12 2 1 3. + 0 + -1.8329080194234848e-002 + -7.9812979698181152e-001 + -6.3357828184962273e-004 + <_> + + <_> + + + + <_> + 4 11 2 3 -1. + <_> + 4 12 2 1 3. + 0 + -3.9759539067745209e-003 + 2.6330900192260742e-001 + -1.0175059735774994e-001 + <_> + + <_> + + + + <_> + 1 9 10 2 -1. + <_> + 6 9 5 1 2. + <_> + 1 10 5 1 2. + 0 + 1.9660349935293198e-002 + 3.9909198880195618e-002 + -6.7467451095581055e-001 + <_> + + <_> + + + + <_> + 6 3 3 6 -1. + <_> + 4 5 3 2 3. + 1 + -8.9697521179914474e-003 + 5.5054008960723877e-002 + -4.3380209803581238e-001 + <_> + + <_> + + + + <_> + 4 10 8 7 -1. + <_> + 4 10 4 7 2. + 0 + 1.7052260041236877e-001 + -8.9983023703098297e-002 + 1.5587039291858673e-001 + <_> + + <_> + + + + <_> + 6 7 6 4 -1. + <_> + 6 7 3 4 2. + 1 + -6.7584879696369171e-002 + 1.8699319660663605e-001 + -1.3449880480766296e-001 + <_> + + <_> + + + + <_> + 7 13 4 2 -1. + <_> + 9 13 2 1 2. + <_> + 7 14 2 1 2. + 0 + -4.9654832109808922e-003 + 2.1740439534187317e-001 + -6.8494133651256561e-002 + <_> + + <_> + + + + <_> + 1 13 4 2 -1. + <_> + 1 13 2 1 2. + <_> + 3 14 2 1 2. + 0 + -3.6419339012354612e-003 + 2.2659860551357269e-001 + -1.1511819809675217e-001 + <_> + + <_> + + + + <_> + 9 8 2 3 -1. + <_> + 9 8 1 3 2. + 0 + 3.0941639095544815e-002 + 9.5881456509232521e-003 + -4.3764260411262512e-001 + <_> + + <_> + + + + <_> + 1 8 2 3 -1. + <_> + 2 8 1 3 2. + 0 + 2.0714900456368923e-003 + -6.9400407373905182e-002 + 3.5815268754959106e-001 + -1.1971529722213745e+000 + 18 + -1 + diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 6ad33cde09..4602135f39 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -7,7 +7,7 @@ file(GLOB FILES_DOC_VS vidsurv/*.doc) file(GLOB FILES_TEX *.tex *.sty *.bib) file(GLOB FILES_TEX_PICS pics/*.png pics/*.jpg) -if(BUILD_DOCS AND PDFLATEX_COMPILER AND HAVE_SPHINX) +if(BUILD_DOCS AND HAVE_SPHINX) project(opencv_docs) @@ -20,6 +20,7 @@ file(GLOB_RECURSE OPENCV_FILES_TUT_PICT tutorials/*.png tutorials/*.jpg) set(OPENCV_DOC_DEPS conf.py ${OPENCV_FILES_REF} ${OPENCV_FILES_REF_PICT} ${OPENCV_FILES_UG} ${OPENCV_FILES_TUT} ${OPENCV_FILES_TUT_PICT}) +if (PDFLATEX_COMPILER) add_custom_target(docs ${SPHINX_BUILD} -b latex -c ${CMAKE_CURRENT_SOURCE_DIR} @@ -28,6 +29,7 @@ add_custom_target(docs ${CMAKE_CURRENT_SOURCE_DIR}/pics ${CMAKE_CURRENT_BINARY_DIR}/doc/opencv1/pics COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/mymath.sty ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/patch_refman_latex.py" opencv2refman.tex COMMAND ${PDFLATEX_COMPILER} opencv2refman.tex COMMAND ${PDFLATEX_COMPILER} opencv2refman.tex COMMAND ${PDFLATEX_COMPILER} opencv_user.tex @@ -37,6 +39,8 @@ add_custom_target(docs DEPENDS ${OPENCV_DOC_DEPS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating the PDF Manuals") + +endif() add_custom_target(html_docs ${SPHINX_BUILD} diff --git a/doc/_themes/blue/static/default.css_t b/doc/_themes/blue/static/default.css_t index c5de392e22..56317cc69a 100644 --- a/doc/_themes/blue/static/default.css_t +++ b/doc/_themes/blue/static/default.css_t @@ -80,6 +80,7 @@ div.related a { } div.sphinxsidebar { + word-wrap: break-word; {%- if theme_stickysidebar|tobool %} top: 30px; margin: 0; @@ -140,7 +141,7 @@ div.sphinxsidebar p.topless { } div.sphinxsidebar ul { - margin: 10px; + margin: 10px 0 10px 10px; padding: 0; color: {{ theme_sidebartextcolor }}; } @@ -261,15 +262,15 @@ pre { } tt { - color: {{ theme_headtext_color }} - background-color: #ecf0f3; + color: {{ theme_headtextcolor }}; + /*background-color: #ecf0f3;*/ padding: 0 1px 0 1px; font-size: 1.2em; } tt.descname { - color: {{ theme_headtext_color }} - background-color: #ecf0f3; + color: {{ theme_headtextcolor }}; + /*background-color: #ecf0f3;*/ padding: 0 1px 0 1px; font-size: 1.4em; } @@ -283,7 +284,7 @@ dl.function > dt:first-child { margin-bottom: 7px; } -dl.cfunction > dt:first-child { +dl.c\:function > dt:first-child { margin-bottom: 7px; color: #8080B0; } @@ -308,3 +309,57 @@ table.field-list { ul.simple { list-style: none; } + +em.menuselection, em.guilabel { + font-family: {{ theme_guifont }}; +} + +.enumeratevisibleitemswithsquare ul { +list-style: square; +margin-bottom: 0px; +margin-left: 0px; +margin-right: 0px; +margin-top: 0px; +} + +.enumeratevisibleitemswithsquare li { +margin-bottom: 0.2em; +margin-left: 0px; +margin-right: 0px; +margin-top: 0.2em; + } + + .enumeratevisibleitemswithsquare p { + margin-bottom: 0pt; + margin-top: 1pt; + } + + .enumeratevisibleitemswithsquare dl{ +margin-bottom: 0px; +margin-left: 0px; +margin-right: 0px; +margin-top: 0px; + } + + .toctableopencv + { + width: 100% ; + table-layout: fixed; + } + + + .toctableopencv colgroup col:first-child + { + width: 100pt !important; + max-width: 100pt !important; + min-width: 100pt !important; + } + + .toctableopencv colgroup col:nth-child(2) + { + width: 100% !important; + } + +div.body ul.search li { + text-align: left; +} diff --git a/doc/_themes/blue/theme.conf b/doc/_themes/blue/theme.conf index b9691ffd39..206193f6f2 100644 --- a/doc/_themes/blue/theme.conf +++ b/doc/_themes/blue/theme.conf @@ -6,7 +6,6 @@ pygments_style = sphinx [options] rightsidebar = false stickysidebar = false - footerbgcolor = #004068 footertextcolor = #ffffff sidebarbgcolor = #006090 @@ -26,7 +25,7 @@ codetextcolor = #333333 feedbackbgcolor = #004068 feedbacktextcolor = #ffffff feedbacklinkcolor = #ffffff - bodyfont = sans-serif headfont = 'Trebuchet MS', sans-serif -lang = none +guifont = "Lucida Sans","Lucida Sans Unicode","Lucida Grande",Verdana,Arial,Helvetica,sans-serif +lang = none \ No newline at end of file diff --git a/doc/check_docs_whitelist.txt b/doc/check_docs_whitelist.txt index c36edd582b..8359178b96 100644 --- a/doc/check_docs_whitelist.txt +++ b/doc/check_docs_whitelist.txt @@ -37,6 +37,108 @@ cv::BOWTrainer::BOWTrainer cv::BOWTrainer::clear cv::AdjusterAdapter::clone +cv::MSER::MSER +cv::StarDetector::StarDetector +cv::SIFT::CommonParams::CommonParams +cv::SIFT::SIFT +cv::SURF::SURF +cv::SimpleBlobDetector::Params::Params + +cv::FastFeatureDetector::read +cv::MserFeatureDetector::read +cv::StarFeatureDetector::read +cv::SurfFeatureDetector::read +cv::SiftFeatureDetector::read +cv::GoodFeaturesToTrackDetector::read +cv::OrbFeatureDetector::read + +cv::FastFeatureDetector::write +cv::MserFeatureDetector::write +cv::StarFeatureDetector::write +cv::SurfFeatureDetector::write +cv::SiftFeatureDetector::write +cv::GoodFeaturesToTrackDetector::write +cv::OrbFeatureDetector::write + +cv::DynamicAdaptedFeatureDetector::empty +cv::GridAdaptedFeatureDetector::empty +cv::PyramidAdaptedFeatureDetector::empty + +cv::BriefDescriptorExtractor::descriptorSize +cv::SurfDescriptorExtractor::descriptorSize +cv::SiftDescriptorExtractor::descriptorSize +cv::OpponentColorDescriptorExtractor::descriptorSize +cv::OrbDescriptorExtractor::descriptorSize + +cv::BriefDescriptorExtractor::descriptorType +cv::SurfDescriptorExtractor::descriptorType +cv::SiftDescriptorExtractor::descriptorType +cv::OpponentColorDescriptorExtractor::descriptorType +cv::OrbDescriptorExtractor::descriptorType + +cv::SurfDescriptorExtractor::read +cv::SiftDescriptorExtractor::read +cv::OpponentColorDescriptorExtractor::read +cv::OrbDescriptorExtractor::read + +cv::SurfDescriptorExtractor::write +cv::SiftDescriptorExtractor::write +cv::OpponentColorDescriptorExtractor::write +cv::OrbDescriptorExtractor::write + +cv::OpponentColorDescriptorExtractor::empty + +cv::FlannBasedMatcher::train + +cv::FlannBasedMatcher::clear + +cv::FlannBasedMatcher::clone + +cv::FlannBasedMatcher::isMaskSupported + + +cv::GenericDescriptorMatcher::GenericDescriptorMatcher + +cv::VectorDescriptorMatcher::clear +cv::FernDescriptorMatcher::clear +cv::OneWayDescriptorMatcher::clear + +cv::VectorDescriptorMatcher::empty +cv::FernDescriptorMatcher::empty +cv::OneWayDescriptorMatcher::empty + +cv::OneWayDescriptorMatcher::read + +cv::VectorDescriptorMatcher::isMaskSupported +cv::FernDescriptorMatcher::isMaskSupported +cv::OneWayDescriptorMatcher::isMaskSupported + +cv::VectorDescriptorMatcher::train +cv::FernDescriptorMatcher::train +cv::OneWayDescriptorMatcher::train + +cv::VectorDescriptorMatcher::read +cv::FernDescriptorMatcher::read + +cv::VectorDescriptorMatcher::write +cv::FernDescriptorMatcher::write +cv::OneWayDescriptorMatcher::write + + + +cv::FastAdjuster::good +cv::StarAdjuster::good +cv::SurfAdjuster::good +cv::FastAdjuster::tooFew +cv::StarAdjuster::tooFew +cv::SurfAdjuster::tooFew +cv::FastAdjuster::tooMany +cv::StarAdjuster::tooMany +cv::SurfAdjuster::tooMany +cv::FastAdjuster::clone +cv::StarAdjuster::clone +cv::SurfAdjuster::clone + ######################################## calib3d ################################### CvLevMarq Mat cv::findFundamentalMat( InputArray points1, InputArray points2, OutputArray mask, int method=FM_RANSAC, double param1=3., double param2=0.99) diff --git a/doc/conf.py b/doc/conf.py index 94207bdd4c..a195d4727c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -25,7 +25,7 @@ sys.path.insert(0, os.path.abspath('.')) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.todo', 'sphinx.ext.extlinks', 'ocv'] +extensions = ['sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.todo', 'sphinx.ext.extlinks', 'ocv', 'sphinx.ext.doctest'] doctest_test_doctest_blocks = 'block' # Add any paths that contain templates here, relative to this directory. @@ -65,7 +65,7 @@ release = '2.3' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = [] +exclude_patterns = ['doc/tutorials/definitions'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None @@ -168,9 +168,9 @@ html_use_index = True # Output file base name for HTML help builder. htmlhelp_basename = 'opencv' -# OpenCV docs use some custom LaTeX macros in the formulae. Make sure we include the definitions +# OpenCV docs use some custom LaTeX macros in the formula. Make sure we include the definitions pngmath_latex_preamble = r""" -\usepackage{euler}\usepackage{amssymb}\usepackage{amsmath}\usepackage{bbm} +\usepackage{euler}\usepackage[usenames,dvipsnames]{color}\usepackage{amssymb}\usepackage{amsmath}\usepackage{bbm}\usepackage{colortbl} \newcommand{\matTT}[9]{ \[ \left|\begin{array}{ccc} @@ -235,6 +235,9 @@ preamble =""" \usepackage{euler} \usepackage[scaled=0.85]{beramono} \usepackage{mymath}\usepackage{amssymb}\usepackage{amsmath}\usepackage{bbm}\setcounter{secnumdepth}{1} +\usepackage{colortbl} +\usepackage{enumitem} +\setlist{labelsep=1ex} """ latex_elements = {'preamble': preamble} @@ -294,12 +297,68 @@ extlinks = {'cvt_color': ('http://opencv.willowgarage.com/documentation/cpp/imgp 'rng': ('http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html?#rng%s', None), 'put_text': ('http://opencv.willowgarage.com/documentation/cpp/core_drawing_functions.html?#putText%s', None), 'gaussian_blur': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-gaussianblur%s', None), - 'blur': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-blur%s', None), + 'blur': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-blur%s', None), 'median_blur': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-medianblur%s', None), 'bilateral_filter': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-bilateralfilter%s', None), - 'erode': ('http://opencv.jp/opencv-2.2_org/cpp/imgproc_image_filtering.html#cv-erode%s', None), + 'erode': ('http://opencv.jp/opencv-2.2_org/cpp/imgproc_image_filtering.html#cv-erode%s', None), 'dilate': ('http://opencv.jp/opencv-2.2_org/cpp/imgproc_image_filtering.html#cv-dilate%s', None), - 'get_structuring_element': ('http://opencv.jp/opencv-2.2_org/cpp/imgproc_image_filtering.html#cv-getstructuringelement%s', None) + 'get_structuring_element': ('http://opencv.jp/opencv-2.2_org/cpp/imgproc_image_filtering.html#cv-getstructuringelement%s', None), + 'flood_fill': ( 'http://opencv.jp/opencv-2.2_org/cpp/imgproc_miscellaneous_image_transformations.html?#floodFill%s', None), + 'morphology_ex': ('http://opencv.jp/opencv-2.2_org/cpp/imgproc_image_filtering.html?highlight=morphology#morphologyEx%s', None), + 'pyr_down': ('http://opencv.willowgarage.com/documentation/cpp/imgproc_image_filtering.html#cv-pyrdown%s', None), + 'pyr_up': ('http://opencv.willowgarage.com/documentation/cpp/imgproc_image_filtering.html#cv-pyrup%s', None), + 'resize': ('http://opencv.willowgarage.com/documentation/cpp/imgproc_geometric_image_transformations.html#cv-resize%s', None), + 'threshold': ('http://opencv.willowgarage.com/documentation/cpp/miscellaneous_image_transformations.html#cv-threshold%s', None), + 'filter2d': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-filter2d%s', None), + 'copy_make_border': ('http://opencv.willowgarage.com/documentation/cpp/imgproc_image_filtering.html?#copyMakeBorder%s', None), + 'sobel': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-sobel%s', None), + 'scharr': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-scharr%s', None), + 'laplacian': ('http://opencv.willowgarage.com/documentation/cpp/image_filtering.html#cv-laplacian%s', None), + 'canny': ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#Canny%s', None), + 'copy_to': ('http://opencv.willowgarage.com/documentation/cpp/core_basic_structures.html?#Mat::copyTo%s', None), + 'opencv_group' : ('http://tech.groups.yahoo.com/group/OpenCV/%s', None), + 'hough_lines' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-houghlines%s', None), + 'hough_lines_p' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-houghlinesp%s', None), + 'hough_circles' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-houghcircles%s', None), + 'remap' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_geometric_image_transformations.html?#remap%s', None), + 'warp_affine' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_geometric_image_transformations.html?#cv-warpaffine%s' , None), + 'get_rotation_matrix_2d' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_geometric_image_transformations.html?#cv-getrotationmatrix2d%s', None), + 'get_affine_transform' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_geometric_image_transformations.html?#cv-getaffinetransform%s', None), + 'equalize_hist' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_histograms.html?#equalizeHist%s', None), + 'split' : ('http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html?#split%s', None), + 'calc_hist' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_histograms.html?#calcHist%s', None), + 'normalize' : ('http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html?#normalize%s', None), + 'match_template' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_object_detection.html?#matchTemplate%s', None), + 'min_max_loc' : ('http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html?#minMaxLoc%s', None), + 'mix_channels' : ( 'http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html?#mixChannels%s', None), + 'calc_back_project' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_histograms.html?#calcBackProject%s', None), + 'compare_hist' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_histograms.html?#compareHist%s', None), + 'corner_harris' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cornerHarris%s', None), + 'good_features_to_track' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-goodfeaturestotrack%s', None), + 'corner_min_eigenval' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-cornermineigenval%s', None), + 'corner_eigenvals_and_vecs' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-cornereigenvalsandvecs%s', None), + 'corner_sub_pix' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html?#cv-cornersubpix%s', None), + 'find_contours' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-findcontours%s', None), + 'convex_hull' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-convexhull%s', None), + 'draw_contours' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-drawcontours%s', None), + 'bounding_rect' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-boundingrect%s', None), + 'min_enclosing_circle' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-minenclosingcircle%s', None), + 'min_area_rect' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-minarearect%s', None), + 'fit_ellipse' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-fitellipse%s', None), + 'moments' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-moments%s', None), + 'contour_area' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-contourarea%s', None), + 'arc_length' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-arclength%s', None), + 'basicstructures' : ('http://opencv.itseez.com/modules/core/doc/basic_structures.html#%s', None), + 'oldbasicstructures' : ('http://opencv.itseez.com/modules/core/doc/old_basic_structures.html#%s', None), + 'readwriteimagevideo' : ('http://opencv.itseez.com/modules/highgui/doc/reading_and_writing_images_and_video.html#%s', None), + 'operationsonarrays' : ('http://opencv.itseez.com/modules/core/doc/operations_on_arrays.html#%s', None), + 'utilitysystemfunctions':('http://opencv.itseez.com/modules/core/doc/utility_and_system_functions_and_macros.html#%s', None), + 'imgprocfilter':('http://opencv.itseez.com/modules/imgproc/doc/filtering.html#%s', None), + 'svms':('http://opencv.itseez.com/modules/ml/doc/support_vector_machines.html#%s', None), + 'xmlymlpers':('http://opencv.itseez.com/modules/core/doc/xml_yaml_persistence.html#%s', None), + 'huivideo' : ('http://opencv.itseez.com/modules/highgui/doc/reading_and_writing_images_and_video.html#%s', None), + 'filtering':('http://opencv.itseez.com/modules/imgproc/doc/filtering.html#%s', None), + 'point_polygon_test' : ('http://opencv.willowgarage.com/documentation/cpp/imgproc_structural_analysis_and_shape_descriptors.html#cv-pointpolygontest%s', None) } diff --git a/doc/license.txt b/doc/license.txt index b1a443a744..af0330790c 100644 --- a/doc/license.txt +++ b/doc/license.txt @@ -15,10 +15,10 @@ Third party copyrights are property of their respective owners. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistribution's of source code must retain the above copyright notice, + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistribution's in binary form must reproduce the above copyright notice, + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. diff --git a/doc/ocv.py b/doc/ocv.py index 566bda7df1..a2f026630a 100644 --- a/doc/ocv.py +++ b/doc/ocv.py @@ -215,7 +215,7 @@ class OCVPyObject(ObjectDescription): signode['ids'].append(fullname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) - objects = self.env.domaindata['py']['objects'] + objects = self.env.domaindata['ocv']['objects'] if fullname in objects: self.env.warn( self.env.docname, @@ -224,7 +224,7 @@ class OCVPyObject(ObjectDescription): self.env.doc2path(objects[fullname][0]) + ', use :noindex: for one of them', self.lineno) - objects[fullname] = (self.env.docname, self.objtype) + objects.setdefault(fullname, (self.env.docname, self.objtype, name_cls[0])) indextext = self.get_index_text(modname, name_cls) if indextext: @@ -669,7 +669,7 @@ class FuncDefExpr(NamedDefExpr): u'.'.join(x.get_id() for x in self.signature) or u'', self.const and u'C' or u'' ) - + def __unicode__(self): buf = self.get_modifiers() if self.explicit: @@ -864,6 +864,13 @@ class DefinitionParser(object): def _parse_type_expr(self): typename = self._parse_name() + if typename and self.skip_string('['): + typename.name += '[' + if self.match(re.compile(r'\d*')): + typename.name += self.last_match.group(0) + typename.name += ']' + if not self.skip_string(']'): + self.fail('expected type') self.skip_ws() if not self.skip_string('<'): return typename @@ -1126,7 +1133,11 @@ class OCVObject(ObjectDescription): node += nodes.Text(' ') def add_target_and_index(self, sigobj, sig, signode): - theid = sigobj.get_id() + theid = sig#obj.get_id() + theid = re.sub(r" +", " ", theid) + theid = re.sub(r"=[^,()]+\([^)]*?\)[^,)]*(,|\))", "\\1", theid) + theid = re.sub(r"=[^,)]+(,|\))", "\\1", theid) + theid = theid.replace("( ", "(").replace(" )", ")") name = unicode(sigobj.name) if theid not in self.state.document.ids: signode['names'].append(theid) @@ -1134,7 +1145,9 @@ class OCVObject(ObjectDescription): signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) - self.env.domaindata['ocv']['objects'].setdefault(name, + #self.env.domaindata['ocv']['objects'].setdefault(name, + #(self.env.docname, self.objtype, theid)) + self.env.domaindata['ocv']['objects'].setdefault(theid, (self.env.docname, self.objtype, theid)) indextext = self.get_index_text(name) @@ -1430,7 +1443,7 @@ class OCVDomain(Domain): raise DefinitionError('') except DefinitionError: refdoc = node.get('refdoc', fromdocname) - env.warn(refdoc, 'unparseable C++ definition: %r' % target, + env.warn(refdoc, 'unparseable1 C++ definition: %r' % target, node.line) return None @@ -1451,6 +1464,26 @@ class OCVDomain(Domain): def get_objects(self): for refname, (docname, type, theid) in self.data['objects'].iteritems(): yield (refname, refname, type, docname, refname, 1) - + + def get_type_name(self, type, primary=False): + """ + Return full name for given ObjType. + """ + if primary: + return type.lname + + return { + 'class': _('C++ class'), + 'struct': _('C/C++ struct'), + 'function': _('C++ function'), + 'cfunction': _('C function'), + 'jfunction': _('Java method'), + 'pyfunction': _('Python function'), + 'pyoldfunction': _('Legacy Python function'), + 'member': _('C++ member'), + 'type': _('C/C++ type'), + 'namespace': _('C++ namespace'), + }.get(type.lname, _('%s %s') % (self.label, type.lname)) + def setup(app): app.add_domain(OCVDomain) diff --git a/doc/opencv2refman.pdf b/doc/opencv2refman.pdf index f9feff670c..6eb15ddae2 100644 Binary files a/doc/opencv2refman.pdf and b/doc/opencv2refman.pdf differ diff --git a/doc/opencv_tutorials.pdf b/doc/opencv_tutorials.pdf index 3c7ead2365..44d0d0e25e 100644 Binary files a/doc/opencv_tutorials.pdf and b/doc/opencv_tutorials.pdf differ diff --git a/doc/opencv_user.pdf b/doc/opencv_user.pdf index bbe5b7a7c2..d17a332564 100644 Binary files a/doc/opencv_user.pdf and b/doc/opencv_user.pdf differ diff --git a/doc/patch_refman_latex.py b/doc/patch_refman_latex.py new file mode 100644 index 0000000000..2691746845 --- /dev/null +++ b/doc/patch_refman_latex.py @@ -0,0 +1,22 @@ +import sys + +f=open(sys.argv[1], "rt") +ll = list(f.readlines()) +f.close() +f=open(sys.argv[1], "wt") +singleparam = False + +for l in ll: + l = l.replace("\\code{~const}}{}", "}{\\code{~const}}") + if l.startswith("\\item[{Parameters}] \\leavevmode"): + if not l.startswith("\\item[{Parameters}] \\leavevmode\\begin{itemize}"): + singleparam = True + l = "\\item[{Parameters}] \\leavevmode\\begin{itemize}[label=]\n" + if singleparam: + l += "\\item {}\n" + elif singleparam and l.startswith("\\end{description}\\end{quote}"): + l = "\\end{itemize}\n" + l + singleparam = False + f.write(l) + +f.close() diff --git a/doc/tutorials/calib3d/camera_calibration_square_chess/camera_calibration_square_chess.rst b/doc/tutorials/calib3d/camera_calibration_square_chess/camera_calibration_square_chess.rst new file mode 100644 index 0000000000..601445ad1f --- /dev/null +++ b/doc/tutorials/calib3d/camera_calibration_square_chess/camera_calibration_square_chess.rst @@ -0,0 +1,62 @@ +.. _CameraCalibrationSquareChessBoardTutorial: + +Camera calibration with square chessboard +***************************************** + +.. highlight:: cpp + +The goal of this tutorial is to learn how to calibrate a camera given a set of chessboard images. + +*Test data*: use images in your data/chess folder. + +#. + Compile opencv with samples by setting ``BUILD_EXAMPLES`` to ``ON`` in cmake configuration. + +#. + Go to ``bin`` folder and use ``imagelist_creator`` to create an ``XML/YAML`` list of your images. + +#. + Then, run ``calibration`` sample to get camera parameters. Use square size equal to 3cm. + +Pose estimation +=============== + +Now, let us write a code that detects a chessboard in a new image and finds its distance from the camera. You can apply the same method to any object with known 3D geometry that you can detect in an image. + +*Test data*: use chess_test*.jpg images from your data folder. + +#. + Create an empty console project. Load a test image: :: + + Mat img = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); + +#. + Detect a chessboard in this image using findChessboard function. :: + + bool found = findChessboardCorners( img, boardSize, ptvec, CV_CALIB_CB_ADAPTIVE_THRESH ); + +#. + Now, write a function that generates a ``vector`` array of 3d coordinates of a chessboard in any coordinate system. For simplicity, let us choose a system such that one of the chessboard corners is in the origin and the board is in the plane *z = 0*. + +#. + Read camera parameters from XML/YAML file: :: + + FileStorage fs(filename, FileStorage::READ); + Mat intrinsics, distortion; + fs["camera_matrix"] >> intrinsics; + fs["distortion_coefficients"] >> distortion; + +#. + Now we are ready to find chessboard pose by running ``solvePnP``: :: + + vector boardPoints; + // fill the array + ... + + solvePnP(Mat(boardPoints), Mat(foundBoardCorners), cameraMatrix, + distCoeffs, rvec, tvec, false); + +#. + Calculate reprojection error like it is done in ``calibration`` sample (see ``opencv/samples/cpp/calibration.cpp``, function ``computeReprojectionErrors``). + +Question: how to calculate the distance from the camera origin to any of the corners? \ No newline at end of file diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration_square_chess.jpg b/doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration_square_chess.jpg new file mode 100644 index 0000000000..1fcab0f83c Binary files /dev/null and b/doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration_square_chess.jpg differ diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst b/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst index 45a43a41bd..ce5812ec2c 100644 --- a/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst +++ b/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst @@ -5,4 +5,32 @@ Although we got most of our images in a 2D format they do come from a 3D world. Here you will learn how to find out from the 2D images information about the 3D world. -.. include:: ../../definitions/noContent.rst +.. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |CameraCalSqChess| **Title:** :ref:`CameraCalibrationSquareChessBoardTutorial` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_VictorE| + + You will use some chessboard images to calibrate your camera. + + ===================== ============================================== + + .. |CameraCalSqChess| image:: images/camera_calibration_square_chess.jpg + :height: 90pt + :width: 90pt + +.. raw:: latex + + \pagebreak + +.. toctree:: + :hidden: + + ../camera_calibration_square_chess/camera_calibration_square_chess diff --git a/doc/tutorials/core/adding_images/adding_images.rst b/doc/tutorials/core/adding_images/adding_images.rst index 701d5734a3..e37f4f7064 100644 --- a/doc/tutorials/core/adding_images/adding_images.rst +++ b/doc/tutorials/core/adding_images/adding_images.rst @@ -114,6 +114,6 @@ Explanation Result ======= -.. image:: images/Adding_Images_Tutorial_Result_0.png +.. image:: images/Adding_Images_Tutorial_Result_0.jpg :alt: Blending Images Tutorial - Final Result - :align: center + :align: center \ No newline at end of file diff --git a/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.jpg b/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..f5c4526c44 Binary files /dev/null and b/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.png b/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.png deleted file mode 100644 index 1f2a5bb37b..0000000000 Binary files a/doc/tutorials/core/adding_images/images/Adding_Images_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png index 73a95301a6..29abc4a123 100644 Binary files a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png and b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0.png differ diff --git a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0a.png b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0a.png deleted file mode 100644 index dedf7ee8a3..0000000000 Binary files a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0a.png and /dev/null differ diff --git a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0b.png b/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0b.png deleted file mode 100644 index 649798c191..0000000000 Binary files a/doc/tutorials/core/basic_geometric_drawing/images/Drawing_1_Tutorial_Result_0b.png and /dev/null differ diff --git a/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst b/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst index 08e804d9c6..cb605d0ccc 100644 --- a/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst +++ b/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst @@ -8,13 +8,15 @@ Goal In this tutorial you will learn how to: -* Access pixel values +.. container:: enumeratevisibleitemswithsquare -* Initialize a matrix with zeros + + Access pixel values -* Learn what :saturate_cast:`saturate_cast <>` does and why it is useful + + Initialize a matrix with zeros -* Get some cool info about pixel transformations + + Learn what :saturate_cast:`saturate_cast <>` does and why it is useful + + + Get some cool info about pixel transformations Cool Theory ================= @@ -92,9 +94,10 @@ Code { for( int x = 0; x < image.cols; x++ ) { for( int c = 0; c < 3; c++ ) { - new_image.at(y,x)[c] = saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); + new_image.at(y,x)[c] = + saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); } - } + } } /// Create Windows @@ -145,8 +148,9 @@ Explanation for( int y = 0; y < image.rows; y++ ) { for( int x = 0; x < image.cols; x++ ) { for( int c = 0; c < 3; c++ ) - { new_image.at(y,x)[c] = saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); } - } + { new_image.at(y,x)[c] = + saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); } + } } Notice the following: @@ -185,7 +189,7 @@ Result .. code-block:: bash - $ ./BasicLinearTransforms lena.png + $ ./BasicLinearTransforms lena.jpg Basic Linear Transforms ------------------------- * Enter the alpha value [1.0-3.0]: 2.2 @@ -193,7 +197,6 @@ Result * We get this: -.. image:: images/Basic_Linear_Transform_Tutorial_Result_0.png - :height: 400px +.. image:: images/Basic_Linear_Transform_Tutorial_Result_0.jpg :alt: Basic Linear Transform - Final Result - :align: center + :align: center \ No newline at end of file diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.jpg b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..527367cc92 Binary files /dev/null and b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.png b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.png deleted file mode 100644 index bef4df653a..0000000000 Binary files a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_a.png b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_a.png deleted file mode 100644 index 978df3f668..0000000000 Binary files a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_a.png and /dev/null differ diff --git a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_b.png b/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_b.png deleted file mode 100644 index 904dc044d0..0000000000 Binary files a/doc/tutorials/core/basic_linear_transform/images/Basic_Linear_Transform_b.png and /dev/null differ diff --git a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.rst b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.rst new file mode 100644 index 0000000000..6bc6eaeea5 --- /dev/null +++ b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.rst @@ -0,0 +1,143 @@ +.. _discretFourierTransform: + +Discrete Fourier Transform +************************** + +Goal +==== + +We'll seek answers for the following questions: + +.. container:: enumeratevisibleitemswithsquare + + + What is a Fourier transform and why use it? + + How to do it in OpenCV? + + Usage of functions such as: :imgprocfilter:`copyMakeBorder() `, :operationsonarrays:`merge() `, :operationsonarrays:`dft() `, :operationsonarrays:`getOptimalDFTSize() `, :operationsonarrays:`log() ` and :operationsonarrays:`normalize() ` . + +Source code +=========== + +You can :download:`download this from here <../../../../samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp>` or find it in the :file:`samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp` of the OpenCV source code library. + +Here's a sample usage of :operationsonarrays:`dft() ` : + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 1-3, 5, 19-20, 23-78 + +Explanation +=========== + +The Fourier Transform will decompose an image into its sinus and cosines components. In other words, it will transform an image from its spatial domain to its frequency domain. The idea is that any function may be approximated exactly with the sum of infinite sinus and cosines functions. The Fourier Transform is a way how to do this. Mathematically a two dimensional images Fourier transform is: + +.. math:: + + F(k,l) = \displaystyle\sum\limits_{i=0}^{N-1}\sum\limits_{j=0}^{N-1} f(i,j)e^{-i2\pi(\frac{ki}{N}+\frac{lj}{N})} + + e^{ix} = \cos{x} + i\sin {x} + +Here f is the image value in its spatial domain and F in its frequency domain. The result of the transformation is complex numbers. Displaying this is possible either via a *real* image and a *complex* image or via a *magnitude* and a *phase* image. However, throughout the image processing algorithms only the *magnitude* image is interesting as this contains all the information we need about the images geometric structure. Nevertheless, if you intend to make some modifications of the image in these forms and then you need to retransform it you'll need to preserve both of these. + +In this sample I'll show how to calculate and show the *magnitude* image of a Fourier Transform. In case of digital images are discrete. This means they may take up a value from a given domain value. For example in a basic gray scale image values usually are between zero and 255. Therefore the Fourier Transform too needs to be of a discrete type resulting in a Discrete Fourier Transform (*DFT*). You'll want to use this whenever you need to determine the structure of an image from a geometrical point of view. Here are the steps to follow (in case of a gray scale input image *I*): + +1. **Expand the image to an optimal size**. The performance of a DFT is dependent of the image size. It tends to be the fastest for image sizes that are multiple of the numbers two, three and five. Therefore, to achieve maximal performance it is generally a good idea to pad border values to the image to get a size with such traits. The :operationsonarrays:`getOptimalDFTSize() ` returns this optimal size and we can use the :imgprocfilter:`copyMakeBorder() ` function to expand the borders of an image: + + .. code-block:: cpp + + Mat padded; //expand input image to optimal size + int m = getOptimalDFTSize( I.rows ); + int n = getOptimalDFTSize( I.cols ); // on the border add zero pixels + copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); + + The appended pixels are initialized with zero. + +2. **Make place for both the complex and the real values**. The result of a Fourier Transform is complex. This implies that for each image value the result is two image values (one per component). Moreover, the frequency domains range is much larger than its spatial counterpart. Therefore, we store these usually at least in a *float* format. Therefore we'll convert our input image to this type and expand it with another channel to hold the complex values: + + .. code-block:: cpp + + Mat planes[] = {Mat_(padded), Mat::zeros(padded.size(), CV_32F)}; + Mat complexI; + merge(planes, 2, complexI); // Add to the expanded another plane with zeros + +3. **Make the Discrete Fourier Transform**. It's possible an in-place calculation (same input as output): + + .. code-block:: cpp + + dft(complexI, complexI); // this way the result may fit in the source matrix + +4. **Transform the real and complex values to magnitude**. A complex number has a real (*Re*) and a complex (imaginary - *Im*) part. The results of a DFT are complex numbers. The magnitude of a DFT is: + + .. math:: + + M = \sqrt[2]{ {Re(DFT(I))}^2 + {Im(DFT(I))}^2} + + Translated to OpenCV code: + + .. code-block:: cpp + + split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) + magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude + Mat magI = planes[0]; + +5. **Switch to a logarithmic scale**. It turns out that the dynamic range of the Fourier coefficients is too large to be displayed on the screen. We have some small and some high changing values that we can't observe like this. Therefore the high values will all turn out as white points, while the small ones as black. To use the gray scale values to for visualization we can transform our linear scale to a logarithmic one: + + .. math:: + + M_1 = \log{(1 + M)} + + Translated to OpenCV code: + + .. code-block:: cpp + + magI += Scalar::all(1); // switch to logarithmic scale + log(magI, magI); + +6. **Crop and rearrange**. Remember, that at the first step, we expanded the image? Well, it's time to throw away the newly introduced values. For visualization purposes we may also rearrange the quadrants of the result, so that the origin (zero, zero) corresponds with the image center. + + .. code-block:: cpp + + magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); + int cx = magI.cols/2; + int cy = magI.rows/2; + + Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant + Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right + Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left + Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right + + Mat tmp; // swap quadrants (Top-Left with Bottom-Right) + q0.copyTo(tmp); + q3.copyTo(q0); + tmp.copyTo(q3); + + q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) + q2.copyTo(q1); + tmp.copyTo(q2); + +7. **Normalize**. This is done again for visualization purposes. We now have the magnitudes, however this are still out of our image display range of zero to one. We normalize our values to this range using the :operationsonarrays:`normalize() ` function. + + .. code-block:: cpp + + normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a + // viewable image form (float between values 0 and 1). + +Result +====== + +An application idea would be to determine the geometrical orientation present in the image. For example, let us find out if a text is horizontal or not? Looking at some text you'll notice that the text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two main components of a text snippet may be also seen in case of the Fourier transform. Let us use :download:`this horizontal <../../../../samples/cpp/tutorial_code/images/imageTextN.png>` and :download:`this rotated<../../../../samples/cpp/tutorial_code/images/imageTextR.png>` image about a text. + +In case of the horizontal text: + +.. image:: images/result_normal.jpg + :alt: In case of normal text + :align: center + +In case of a rotated text: + +.. image:: images/result_rotated.jpg + :alt: In case of rotated text + :align: center + +You can see that the most influential components of the frequency domain (brightest dots on the magnitude image) follow the geometric rotation of objects on the image. From this we may calculate the offset and perform an image rotation to correct eventual miss alignments. diff --git a/doc/tutorials/core/discrete_fourier_transform/images/result_normal.jpg b/doc/tutorials/core/discrete_fourier_transform/images/result_normal.jpg new file mode 100644 index 0000000000..7e538f6b0b Binary files /dev/null and b/doc/tutorials/core/discrete_fourier_transform/images/result_normal.jpg differ diff --git a/doc/tutorials/core/discrete_fourier_transform/images/result_rotated.jpg b/doc/tutorials/core/discrete_fourier_transform/images/result_rotated.jpg new file mode 100644 index 0000000000..9a6c28ee8f Binary files /dev/null and b/doc/tutorials/core/discrete_fourier_transform/images/result_rotated.jpg differ diff --git a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst new file mode 100644 index 0000000000..01ded5fd4d --- /dev/null +++ b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst @@ -0,0 +1,280 @@ +.. _fileInputOutputXMLYAML: + +File Input and Output using XML and YAML files +********************************************** + +Goal +==== + +You'll find answers for the following questions: + +.. container:: enumeratevisibleitemswithsquare + + + How to print and read text entries to a file and OpenCV using YAML or XML files? + + How to do the same for OpenCV data structures? + + How to do this for your data structures? + + Usage of OpenCV data structures such as :xmlymlpers:`FileStorage `, :xmlymlpers:`FileNode ` or :xmlymlpers:`FileNodeIterator `. + +Source code +=========== + +You can :download:`download this from here <../../../../samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp>` or find it in the :file:`samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp` of the OpenCV source code library. + +Here's a sample code of how to achieve all the stuff enumerated at the goal list. + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 1-7, 21-154 + +Explanation +=========== + +Here we talk only about XML and YAML file inputs. Your output (and its respective input) file may have only one of these extensions and the structure coming from this. They are two kinds of data structures you may serialize: *mappings* (like the STL map) and *element sequence* (like the STL vector>. The difference between these is that in a map every element has a unique name through what you may access it. For sequences you need to go through them to query a specific item. + +1. **XML\\YAML File Open and Close.** Before you write any content to such file you need to open it and at the end to close it. The XML\YAML data structure in OpenCV is :xmlymlpers:`FileStorage `. To specify that this structure to which file binds on your hard drive you can use either its constructor or the *open()* function of this: + + .. code-block:: cpp + + string filename = "I.xml"; + FileStorage fs(filename, FileStorage::WRITE); + \\... + fs.open(filename, FileStorage::READ); + + Either one of this you use the second argument is a constant specifying the type of operations you'll be able to on them: WRITE, READ or APPEND. The extension specified in the file name also determinates the output format that will be used. The output may be even compressed if you specify an extension such as *.xml.gz*. + + The file automatically closes when the :xmlymlpers:`FileStorage ` objects is destroyed. However, you may explicitly call for this by using the *release* function: + + .. code-block:: cpp + + fs.release(); // explicit close + +#. **Input and Output of text and numbers.** The data structure uses the same << output operator that the STL library. For outputting any type of data structure we need first to specify its name. We do this by just simply printing out the name of this. For basic types you may follow this with the print of the value : + + .. code-block:: cpp + + fs << "iterationNr" << 100; + + Reading in is a simple addressing (via the [] operator) and casting operation or a read via the >> operator : + + .. code-block:: cpp + + int itNr; + fs["iterationNr"] >> itNr; + itNr = (int) fs["iterationNr"]; + +#. **Input\\Output of OpenCV Data structures.** Well these behave exactly just as the basic C++ types: + + .. code-block:: cpp + + Mat R = Mat_::eye (3, 3), + T = Mat_::zeros(3, 1); + + fs << "R" << R; // Write cv::Mat + fs << "T" << T; + + fs["R"] >> R; // Read cv::Mat + fs["T"] >> T; + +#. **Input\\Output of vectors (arrays) and associative maps.** As I mentioned beforehand we can output maps and sequences (array, vector) too. Again we first print the name of the variable and then we have to specify if our output is either a sequence or map. + + For sequence before the first element print the "[" character and after the last one the "]" character: + + .. code-block:: cpp + + fs << "strings" << "["; // text - string sequence + fs << "image1.jpg" << "Awesomeness" << "baboon.jpg"; + fs << "]"; // close sequence + + For maps the drill is the same however now we use the "{" and "}" delimiter characters: + + .. code-block:: cpp + + fs << "Mapping"; // text - mapping + fs << "{" << "One" << 1; + fs << "Two" << 2 << "}"; + + To read from these we use the :xmlymlpers:`FileNode ` and the :xmlymlpers:`FileNodeIterator ` data structures. The [] operator of the :xmlymlpers:`FileStorage ` class returns a :xmlymlpers:`FileNode ` data type. If the node is sequential we can use the :xmlymlpers:`FileNodeIterator ` to iterate through the items: + + .. code-block:: cpp + + FileNode n = fs["strings"]; // Read string sequence - Get node + if (n.type() != FileNode::SEQ) + { + cerr << "strings is not a sequence! FAIL" << endl; + return 1; + } + + FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node + for (; it != it_end; ++it) + cout << (string)*it << endl; + + For maps you can use the [] operator again to acces the given item (or the >> operator too): + + .. code-block:: cpp + + n = fs["Mapping"]; // Read mappings from a sequence + cout << "Two " << (int)(n["Two"]) << "; "; + cout << "One " << (int)(n["One"]) << endl << endl; + +#. **Read and write your own data structures.** Suppose you have a data structure such as: + + .. code-block:: cpp + + class MyData + { + public: + MyData() : A(0), X(0), id() {} + public: // Data Members + int A; + double X; + string id; + }; + + It's possible to serialize this through the OpenCV I/O XML/YAML interface (just as in case of the OpenCV data structures) by adding a read and a write function inside and outside of your class. For the inside part: + + .. code-block:: cpp + + void write(FileStorage& fs) const //Write serialization for this class + { + fs << "{" << "A" << A << "X" << X << "id" << id << "}"; + } + + void read(const FileNode& node) //Read serialization for this class + { + A = (int)node["A"]; + X = (double)node["X"]; + id = (string)node["id"]; + } + + Then you need to add the following functions definitions outside the class: + + .. code-block:: cpp + + void write(FileStorage& fs, const std::string&, const MyData& x) + { + x.write(fs); + } + + void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()) + { + if(node.empty()) + x = default_value; + else + x.read(node); + } + + Here you can observe that in the read section we defined what happens if the user tries to read a non-existing node. In this case we just return the default initialization value, however a more verbose solution would be to return for instance a minus one value for an object ID. + + Once you added these four functions use the >> operator for write and the << operator for read: + + .. code-block:: cpp + + MyData m(1); + fs << "MyData" << m; // your own data structures + fs["MyData"] >> m; // Read your own structure_ + + Or to try out reading a non-existing read: + + .. code-block:: cpp + + fs["NonExisting"] >> m; // Do not add a fs << "NonExisting" << m command for this to work + cout << endl << "NonExisting = " << endl << m << endl; + +Result +====== + +Well mostly we just print out the defined numbers. On the screen of your console you could see: + +.. code-block:: bash + + Write Done. + + Reading: + 100image1.jpg + Awesomeness + baboon.jpg + Two 2; One 1 + + + R = [1, 0, 0; + 0, 1, 0; + 0, 0, 1] + T = [0; 0; 0] + + MyData = + { id = mydata1234, X = 3.14159, A = 97} + + Attempt to read NonExisting (should initialize the data structure with its default). + NonExisting = + { id = , X = 0, A = 0} + + Tip: Open up output.xml with a text editor to see the serialized data. + +Nevertheless, it's much more interesting what you may see in the output xml file: + +.. code-block:: xml + + + + 100 + + image1.jpg Awesomeness baboon.jpg + + 1 + 2 + + 3 + 3 +
u
+ + 1 0 0 0 1 0 0 0 1
+ + 3 + 1 +
d
+ + 0. 0. 0.
+ + 97 + 3.1415926535897931e+000 + mydata1234 +
+ +Or the YAML file: + +.. code-block:: yaml + + %YAML:1.0 + iterationNr: 100 + strings: + - "image1.jpg" + - Awesomeness + - "baboon.jpg" + Mapping: + One: 1 + Two: 2 + R: !!opencv-matrix + rows: 3 + cols: 3 + dt: u + data: [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ] + T: !!opencv-matrix + rows: 3 + cols: 1 + dt: d + data: [ 0., 0., 0. ] + MyData: + A: 97 + X: 3.1415926535897931e+000 + id: mydata1234 + +You may observe a runtime instance of this on the `YouTube here `_ . + +.. raw:: html + +
+ +
+ diff --git a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.rst b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.rst new file mode 100644 index 0000000000..11b0d6b24d --- /dev/null +++ b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.rst @@ -0,0 +1,183 @@ +.. _howToScanImagesOpenCV: + +How to scan images, lookup tables and time measurement with OpenCV +******************************************************************* + +Goal +==== + +We'll seek answers for the following questions: + +.. container:: enumeratevisibleitemswithsquare + + + How to go through each and every pixel of an image? + + How is OpenCV matrix values stored? + + How to measure the performance of our algorithm? + + What are lookup tables and why use them? + +Our test case +============= + +Let us consider a simple color reduction method. Using the unsigned char C and C++ type for matrix item storing a channel of pixel may have up to 256 different values. For a three channel image this can allow the formation of way too many colors (16 million to be exact). Working with so many color shades may give a heavy blow to our algorithm performance. However, sometimes it is enough to work with a lot less of them to get the same final result. + +In this cases it's common that we make a *color space reduction*. This means that we divide the color space current value with a new input value to end up with fewer colors. For instance every value between zero and nine takes the new value zero, every value between ten and nineteen the value ten and so on. + +When you divide an *uchar* (unsigned char - aka values between zero and 255) value with an *int* value the result will be also *char*. These values may only be char values. Therefore, any fraction will be rounded down. Taking advantage of this fact the upper operation in the *uchar* domain may be expressed as: + +.. math:: + + I_{new} = (\frac{I_{old}}{10}) * 10 + +A simple color space reduction algorithm would consist of just passing through every pixel of an image matrix and applying this formula. It's worth noting that we do a divide and a multiplication operation. These operations are bloody expensive for a system. If possible it's worth avoiding them by using cheaper operations such as a few subtractions, addition or in best case a simple assignment. Furthermore, note that we only have a limited number of input values for the upper operation. In case of the *uchar* system this is 256 to be exact. + +Therefore, for larger images it would be wise to calculate all possible values beforehand and during the assignment just make the assignment, by using a lookup table. Lookup tables are simple arrays (having one or more dimensions) that for a given input value variation holds the final output value. Its strength lies that we do not need to make the calculation, we just need to read the result. + +Our test case program (and the sample presented here) will do the following: read in a console line argument image (that may be either color or gray scale - console line argument too) and apply the reduction with the given console line argument integer value. In OpenCV, at the moment they are three major ways of going through an image pixel by pixel. To make things a little more interesting will make the scanning for each image using all of these methods, and print out how long it took. + +You can download the full source code :download:`here <../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp>` or look it up in the samples directory of OpenCV at the cpp tutorial code for the core section. Its basic usage is: + +.. code-block:: bash + + how_to_scan_images imageName.jpg intValueToReduce [G] + +The final argument is optional. If given the image will be loaded in gray scale format, otherwise the RGB color way is used. The first thing is to calculate the lookup table. + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp + :language: cpp + :tab-width: 4 + :lines: 48-60 + +Here we first use the C++ *stringstream* class to convert the third command line argument from text to an integer format. Then we use a simple look and the upper formula to calculate the lookup table. No OpenCV specific stuff here. + +Another issue is how do we measure time? Well OpenCV offers two simple functions to achieve this :UtilitySystemFunctions:`getTickCount() ` and :UtilitySystemFunctions:`getTickFrequency() `. The first returns the number of ticks of your systems CPU from a certain event (like since you booted your system). The second returns how many times your CPU emits a tick during a second. So to measure in seconds the number of time elapsed between two operations is easy as: + +.. code-block:: cpp + + double t = (double)getTickCount(); + // do something ... + t = ((double)getTickCount() - t)/getTickFrequency(); + cout << "Times passed in seconds: " << t << endl; + +.. _How_Image_Stored_Memory: + +How the image matrix is stored in the memory? +============================================= + +As you could already read in my :ref:`matTheBasicImageContainer` tutorial the size of the matrix depends of the color system used. More accurately, it depends from the number of channels used. In case of a gray scale image we have something like: + +.. math:: + + \newcommand{\tabItG}[1] { \textcolor{black}{#1} \cellcolor[gray]{0.8}} + \begin{tabular} {ccccc} + ~ & \multicolumn{1}{c}{Column 0} & \multicolumn{1}{c}{Column 1} & \multicolumn{1}{c}{Column ...} & \multicolumn{1}{c}{Column m}\\ + Row 0 & \tabItG{0,0} & \tabItG{0,1} & \tabItG{...} & \tabItG{0, m} \\ + Row 1 & \tabItG{1,0} & \tabItG{1,1} & \tabItG{...} & \tabItG{1, m} \\ + Row ... & \tabItG{...,0} & \tabItG{...,1} & \tabItG{...} & \tabItG{..., m} \\ + Row n & \tabItG{n,0} & \tabItG{n,1} & \tabItG{n,...} & \tabItG{n, m} \\ + \end{tabular} + +For multichannel images the columns contain as many sub columns as the number of channels. For example in case of an RGB color system: + +.. math:: + + \newcommand{\tabIt}[1] { \textcolor{yellow}{#1} \cellcolor{blue} & \textcolor{black}{#1} \cellcolor{green} & \textcolor{black}{#1} \cellcolor{red}} + \begin{tabular} {ccccccccccccc} + ~ & \multicolumn{3}{c}{Column 0} & \multicolumn{3}{c}{Column 1} & \multicolumn{3}{c}{Column ...} & \multicolumn{3}{c}{Column m}\\ + Row 0 & \tabIt{0,0} & \tabIt{0,1} & \tabIt{...} & \tabIt{0, m} \\ + Row 1 & \tabIt{1,0} & \tabIt{1,1} & \tabIt{...} & \tabIt{1, m} \\ + Row ... & \tabIt{...,0} & \tabIt{...,1} & \tabIt{...} & \tabIt{..., m} \\ + Row n & \tabIt{n,0} & \tabIt{n,1} & \tabIt{n,...} & \tabIt{n, m} \\ + \end{tabular} + +Note that the order of the channels is inverse: BGR instead of RGB. Because in many cases the memory is large enough to store the rows in a successive fashion the rows may follow one after another, creating a single long row. Because everything is in a single place following one after another this may help to speed up the scanning process. We can use the :basicstructures:`isContinuous() ` function to *ask* the matrix if this is the case. Continue on to the next section to find an example. + +The efficient way +================= + +When it comes to performance you cannot beat the classic C style operator[] (pointer) access. Therefore, the most efficient method we can recommend for making the assignment is: + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp + :language: cpp + :tab-width: 4 + :lines: 116-143 + +Here we basically just acquire a pointer to the start of each row and go through it until it ends. In the special case that the matrix is stored in a continues manner we only need to request the pointer a single time and go all the way to the end. We need to look out for color images: we have three channels so we need to pass through three times more items in each row. + +There's another way of this. The *data* data member of a *Mat* object returns the pointer to the first row, first column. If this pointer is null you have no valid input in that object. Checking this is the simplest method to check if your image loading was a success. In case the storage is continues we can use this to go through the whole data pointer. In case of a gray scale image this would look like: + +.. code-block:: cpp + + uchar* p = I.data; + + for( unsigned int i =0; i < ncol*nrows; ++i) + *p++ = table[*p]; + +You would get the same result. However, this code is a lot harder to read later on. It gets even harder if you have some more advanced technique there. Moreover, in practice I've observed you'll get the same performance result (as most of the modern compilers will probably make this small optimization trick automatically for you). + +The iterator (safe) method +========================== + +In case of the efficient way making sure that you pass through the right amount of *uchar* fields and to skip the gaps that may occur between the rows was your responsibility. The iterator method is considered a safer way as it takes over these tasks from the user. All you need to do is ask the begin and the end of the image matrix and then just increase the begin iterator until you reach the end. To acquire the value *pointed* by the iterator use the * operator (add it before it). + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp + :language: cpp + :tab-width: 4 + :lines: 145-173 + +In case of color images we have three uchar items per column. This may be considered a short vector of uchar items, that has been baptized in OpenCV with the *Vec3b* name. To access the n-th sub column we use simple operator[] access. It's important to remember that OpenCV iterators go through the columns and automatically skip to the next row. Therefore in case of color images if you use a simple *uchar* iterator you'll be able to access only the blue channel values. + +On-the-fly address calculation with reference returning +======================================================= + +The final method isn't recommended for scanning. It was made to acquire or modify somehow random elements in the image. Its basic usage is to specify the row and column number of the item you want to access. During our earlier scanning methods you could already observe that is important through what type we are looking at the image. It's no different here as you need manually to specify what type to use at the automatic lookup. You can observe this in case of the gray scale images for the following source code (the usage of the + :basicstructures:`at() ` function): + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp + :language: cpp + :tab-width: 4 + :lines: 175-207 + +The functions takes your input type and coordinates and calculates on the fly the address of the queried item. Then returns a reference to that. This may be a constant when you *get* the value and non-constant when you *set* the value. As a safety step in **debug mode only*** there is performed a check that your input coordinates are valid and does exist. If this isn't the case you'll get a nice output message of this on the standard error output stream. Compared to the efficient way in release mode the only difference in using this is that for every element of the image you'll get a new row pointer for what we use the C operator[] to acquire the column element. + +If you need to multiple lookups using this method for an image it may be troublesome and time consuming to enter the type and the at keyword for each of the accesses. To solve this problem OpenCV has a :basicstructures:`Mat_ ` data type. It's the same as Mat with the extra need that at definition you need to specify the data type through what to look at the data matrix, however in return you can use the operator() for fast access of items. To make things even better this is easily convertible from and to the usual :basicstructures:`Mat ` data type. A sample usage of this you can see in case of the color images of the upper function. Nevertheless, it's important to note that the same operation (with the same runtime speed) could have been done with the :basicstructures:`at() ` function. It's just a less to write for the lazy programmer trick. + +The Core Function +================= + +This is a bonus method of achieving lookup table modification in an image. Because in image processing it's quite common that you want to replace all of a given image value to some other value OpenCV has a function that makes the modification without the need from you to write the scanning of the image. We use the :operationsOnArrays:`LUT() ` function of the core module. First we build a Mat type of the lookup table: + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp + :language: cpp + :tab-width: 4 + :lines: 98-101 + +Finally call the function (I is our input image and J the output one): + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp + :language: cpp + :tab-width: 4 + :lines: 106 + +Performance Difference +====================== + +For the best result compile the program and run it on your own speed. For showing off better the differences I've used a quite large (2560 X 1600) image. The performance presented here are for color images. For a more accurate value I've averaged the value I got from the call of the function for hundred times. + +============= ==================== +Efficient Way 79.4717 milliseconds + +Iterator 83.7201 milliseconds + +On-The-Fly RA 93.7878 milliseconds + +LUT function 32.5759 milliseconds +============= ==================== + +We can conclude a couple of things. If possible, use the already made functions of OpenCV (instead reinventing these). The fastest method turns out to be the LUT function. This is because the OpenCV library is multi-thread enabled via Intel Threaded Building Blocks. However, if you need to write a simple image scan prefer the pointer method. The iterator is a safer bet, however quite slower. Using the on-the-fly reference access method for full image scan is the most costly in debug mode. In the release mode it may beat the iterator approach or not, however it surely sacrifices for this the safety trait of iterators. + +Finally, you may watch a sample run of the program on the `video posted `_ on our YouTube channel. + +.. raw:: html + +
+ +
diff --git a/doc/tutorials/core/interoperability_with_OpenCV_1/images/outputInteropOpenCV1.jpg b/doc/tutorials/core/interoperability_with_OpenCV_1/images/outputInteropOpenCV1.jpg new file mode 100644 index 0000000000..b94b0ec927 Binary files /dev/null and b/doc/tutorials/core/interoperability_with_OpenCV_1/images/outputInteropOpenCV1.jpg differ diff --git a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.rst b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.rst new file mode 100644 index 0000000000..f1669f4aef --- /dev/null +++ b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.rst @@ -0,0 +1,132 @@ +.. _InteroperabilityWithOpenCV1: + +Interoperability with OpenCV 1 +****************************** + +Goal +==== + +For the OpenCV developer team it's important to constantly improve the library. We are constantly thinking about methods that will ease your work process, while still maintain the libraries flexibility. The new C++ interface is a development of us that serves this goal. Nevertheless, backward compatibility remains important. We do not want to break your code written for earlier version of the OpenCV library. Therefore, we made sure that we add some functions that deal with this. In the following you'll learn: + +.. container:: enumeratevisibleitemswithsquare + + + What changed with the version 2 of OpenCV in the way you use the library compared to its first version + + How to add some Gaussian noise to an image + + What are lookup tables and why use them? + +General +======= + +When making the switch you first need to learn some about the new data structure for images: :ref:`matTheBasicImageContainer`, this replaces the old *CvMat* and *IplImage* ones. Switching to the new functions is easier. You just need to remember a couple of new things. + +OpenCV 2 received reorganization. No longer are all the functions crammed into a single library. We have many modules, each of them containing data structures and functions relevant to certain tasks. This way you do not need to ship a large library if you use just a subset of OpenCV. This means that you should also include only those headers you will use. For example: + +.. code-block:: cpp + + #include + #include + #include + + +All the OpenCV related stuff is put into the *cv* namespace to avoid name conflicts with other libraries data structures and functions. Therefore, either you need to prepend the *cv::* keyword before everything that comes from OpenCV or after the includes, you just add a directive to use this: + +.. code-block:: cpp + + using namespace cv; // The new C++ interface API is inside this namespace. Import it. + +Because the functions are already in a namespace there is no need for them to contain the *cv* prefix in their name. As such all the new C++ compatible functions don't have this and they follow the camel case naming rule. This means the first letter is small (unless it's a name, like Canny) and the subsequent words start with a capital letter (like *copyMakeBorder*). + +Now, remember that you need to link to your application all the modules you use, and in case you are on Windows using the *DLL* system you will need to add, again, to the path all the binaries. For more in-depth information if you're on Windows read :ref:`Windows_Visual_Studio_How_To` and for Linux an example usage is explained in :ref:`Linux_Eclipse_Usage`. + +Now for converting the *Mat* object you can use either the *IplImage* or the *CvMat* operators. While in the C interface you used to work with pointers here it's no longer the case. In the C++ interface we have mostly *Mat* objects. These objects may be freely converted to both *IplImage* and *CvMat* with simple assignment. For example: + +.. code-block:: cpp + + Mat I; + IplImage pI = I; + CvMat mI = I; + +Now if you want pointers the conversion gets just a little more complicated. The compilers can no longer automatically determinate what you want and as you need to explicitly specify your goal. This is to call the *IplImage* and *CvMat* operators and then get their pointers. For getting the pointer we use the & sign: + +.. code-block:: cpp + + Mat I; + IplImage* pI = &I.operator IplImage(); + CvMat* mI = &I.operator CvMat(); + +One of the biggest complaints of the C interface is that it leaves all the memory management to you. You need to figure out when it is safe to release your unused objects and make sure you do so before the program finishes or you could have troublesome memory leeks. To work around this issue in OpenCV there is introduced a sort of smart pointer. This will automatically release the object when it's no longer in use. To use this declare the pointers as a specialization of the *Ptr* : + +.. code-block:: cpp + + Ptr piI = &I.operator IplImage(); + +Converting from the C data structures to the *Mat* is done by passing these inside its constructor. For example: + +.. code-block:: cpp + + Mat K(piL), L; + L = Mat(pI); + +A case study +============ + +Now that you have the basics done :download:`here's <../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp>` an example that mixes the usage of the C interface with the C++ one. You will also find it in the sample directory of the OpenCV source code library at the :file:`samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` . To further help on seeing the difference the programs supports two modes: one mixed C and C++ and one pure C++. If you define the *DEMO_MIXED_API_USE* you'll end up using the first. The program separates the color planes, does some modifications on them and in the end merge them back together. + + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 1-9, 22-25, 27-44 + +Here you can observe that with the new structure we have no pointer problems, although it is possible to use the old functions and in the end just transform the result to a *Mat* object. + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 46-51 + +Because, we want to mess around with the images luma component we first convert from the default RGB to the YUV color space and then split the result up into separate planes. Here the program splits: in the first example it processes each plane using one of the three major image scanning algorithms in OpenCV (C [] operator, iterator, individual element access). In a second variant we add to the image some Gaussian noise and then mix together the channels according to some formula. + +The scanning version looks like: + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 55-75 + +Here you can observe that we may go through all the pixels of an image in three fashions: an iterator, a C pointer and an individual element access style. You can read a more in-depth description of these in the :ref:`howToScanImagesOpenCV` tutorial. Converting from the old function names is easy. Just remove the cv prefix and use the new *Mat* data structure. Here's an example of this by using the weighted addition function: + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 79-112 + +As you may observe the *planes* variable is of type *Mat*. However, converting from *Mat* to *IplImage* is easy and made automatically with a simple assignment operator. + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 115-127 + +The new *imshow* highgui function accepts both the *Mat* and *IplImage* data structures. Compile and run the program and if the first image below is your input you may get either the first or second as output: + +.. image:: images/outputInteropOpenCV1.jpg + :alt: The output of the sample + :align: center + + +You may observe a runtime instance of this on the `YouTube here `_ and you can :download:`download the source code from here <../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp>` or find it in the :file:`samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` of the OpenCV source code library. + +.. raw:: html + +
+ +
+ + + diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut1.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut1.png new file mode 100644 index 0000000000..414fba4ac7 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut1.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut10.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut10.png new file mode 100644 index 0000000000..425dde830c Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut10.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut11.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut11.png new file mode 100644 index 0000000000..37db1db2bb Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut11.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut12.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut12.png new file mode 100644 index 0000000000..765275374b Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut12.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut13.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut13.png new file mode 100644 index 0000000000..95fece4626 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut13.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut14.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut14.png new file mode 100644 index 0000000000..50bad2a77d Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut14.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut15.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut15.png new file mode 100644 index 0000000000..08514cee48 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut15.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut16.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut16.png new file mode 100644 index 0000000000..1420957136 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut16.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut2.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut2.png new file mode 100644 index 0000000000..0efb6c61f9 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut2.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut3.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut3.png new file mode 100644 index 0000000000..046705f08d Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut3.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut6.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut6.png new file mode 100644 index 0000000000..8e1cf63721 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut6.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut7.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut7.png new file mode 100644 index 0000000000..211595e7a3 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut7.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut8.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut8.png new file mode 100644 index 0000000000..70c3eaa4e0 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut8.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut9.png b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut9.png new file mode 100644 index 0000000000..674712566e Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicContainerOut9.png differ diff --git a/doc/tutorials/core/mat - the basic image container/images/MatBasicImageForComputer.jpg b/doc/tutorials/core/mat - the basic image container/images/MatBasicImageForComputer.jpg new file mode 100644 index 0000000000..0277296808 Binary files /dev/null and b/doc/tutorials/core/mat - the basic image container/images/MatBasicImageForComputer.jpg differ diff --git a/doc/tutorials/core/mat - the basic image container/mat - the basic image container.rst b/doc/tutorials/core/mat - the basic image container/mat - the basic image container.rst new file mode 100644 index 0000000000..b2d20e19ba --- /dev/null +++ b/doc/tutorials/core/mat - the basic image container/mat - the basic image container.rst @@ -0,0 +1,308 @@ +.. _matTheBasicImageContainer: + +Mat - The Basic Image Container +******************************* + +Goal +==== + +We have multiple ways to acquire digital images from the real world: digital cameras, scanners, computed tomography or magnetic resonance imaging to just name a few. In every case what we (humans) see are images. However, when transforming this to our digital devices what we record are numerical values for each of the points of the image. + +.. image:: images/MatBasicImageForComputer.jpg + :alt: A matrix of the mirror of a car + :align: center + +For example in the above image you can see that the mirror of the care is nothing more than a matrix containing all the intensity values of the pixel points. Now, how we get and store the pixels values may vary according to what fits best our need, in the end all images inside a computer world may be reduced to numerical matrices and some other information's describing the matric itself. *OpenCV* is a computer vision library whose main focus is to process and manipulate these information to find out further ones. Therefore, the first thing you need to learn and get accommodated with is how OpenCV stores and handles images. + +*Mat* +===== + +OpenCV has been around ever since 2001. In those days the library was built around a *C* interface. In those days to store the image in the memory they used a C structure entitled *IplImage*. This is the one you'll see in most of the older tutorials and educational materials. The problem with this is that it brings to the table all the minuses of the C language. The biggest issue is the manual management. It builds on the assumption that the user is responsible for taking care of memory allocation and deallocation. While this is no issue in case of smaller programs once your code base start to grove larger and larger it will be more and more a struggle to handle all this rather than focusing on actually solving your development goal. + +Luckily C++ came around and introduced the concept of classes making possible to build another road for the user: automatic memory management (more or less). The good news is that C++ if fully compatible with C so no compatibility issues can arise from making the change. Therefore, OpenCV with its 2.0 version introduced a new C++ interface that by taking advantage of these offers a new way of doing things. A way, in which you do not need to fiddle with memory management; making your code concise (less to write, to achieve more). The only main downside of the C++ interface is that many embedded development systems at the moment support only C. Therefore, unless you are targeting this platform, there's no point on using the *old* methods (unless you're a masochist programmer and you're asking for trouble). + +The first thing you need to know about *Mat* is that you no longer need to manually allocate its size and release it as soon as you do not need it. While doing this is still a possibility, most of the OpenCV functions will allocate its output data manually. As a nice bonus if you pass on an already existing *Mat* object, what already has allocated the required space for the matrix, this will be reused. In other words we use at all times only as much memory as much we must to perform the task. + +*Mat* is basically a class having two data parts: the matrix header (containing information such as the size of the matrix, the method used for storing, at which address is the matrix stored and so on) and a pointer to the matrix containing the pixel values (may take any dimensionality depending on the method chosen for storing) . The matrix header size is constant. However, the size of the matrix itself may vary from image to image and usually is larger by order of magnitudes. Therefore, when you're passing on images in your program and at some point you need to create a copy of the image the big price you will need to build is for the matrix itself rather than its header. OpenCV is an image processing library. It contains a large collection of image processing functions. To solve a computational challenge most of the time you will end up using multiple functions of the library. Due to this passing on images to functions is a common practice. We should not forget that we are talking about image processing algorithms, which tend to be quite computational heavy. The last thing we want to do is to further decrease the speed of your program by making unnecessary copies of potentially *large* images. + +To tackle this issue OpenCV uses a reference counting system. The idea is that each *Mat* object has its own header, however the matrix may be shared between two instance of them by having their matrix pointer point to the same address. Moreover, the copy operators **will only copy the headers**, and as also copy the pointer to the large matrix too, however not the matrix itself. + +.. code-block:: cpp + :linenos: + + Mat A, C; // creates just the header parts + A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // here we'll know the method used (allocate matrix) + + Mat B(A); // Use the copy constructor + + C = A; // Assignment operator + +All the above objects, in the end point to the same single data matrix. Their headers are different, however making any modification using either one of them will affect all the other ones too. In practice the different objects just provide different access method to the same underlying data. Nevertheless, their header parts are different. The real interesting part comes that you can create headers that refer only to a subsection of the full data. For example, to create a region of interest (*ROI*) in an image you just create a new header with the new boundaries: + +.. code-block:: cpp + :linenos: + + Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle + Mat E = A(Range:all(), Range(1,3)); // using row and column boundaries + +Now you may ask if the matrix itself may belong to multiple *Mat* objects who will take responsibility for its cleaning when it's no longer needed. The short answer is: the last object that used it. For this a reference counting mechanism is used. Whenever somebody copies a header of a *Mat* object a counter is increased for the matrix. Whenever a header is cleaned this counter is decreased. When the counter reaches zero the matrix too is freed. Because, sometimes you will still want to copy the matrix itself too, there exists the :basicstructures:`clone() ` or the :basicstructures:`copyTo() ` function. + +.. code-block:: cpp + :linenos: + + Mat F = A.clone(); + Mat G; + A.copyTo(G); + +Now modifying *F* or *G* will not affect the matrix pointed by the *Mat* header. What you need to remember from all this is that: + +.. container:: enumeratevisibleitemswithsquare + + * Output image allocation for OpenCV functions is automatic (unless specified otherwise). + * No need to think about memory freeing with OpenCVs C++ interface. + * The assignment operator and the copy constructor (*ctor*)copies only the header. + * Use the :basicstructures:`clone()` or the :basicstructures:`copyTo() ` function to copy the underlying matrix of an image. + +*Storing* methods +================= + +This is about how you store the pixel values. You can select the color space and the data type used. The color space refers to how we combine color components in order to code a given color. The simplest one is the gray scale. Here the colors at our disposal are black and white. The combination of these allows us to create many shades of gray. + +For *colorful* ways we have a lot more of methods to choose from. However, every one of them breaks it down to three or four basic components and the combination of this will give all others. The most popular one of this is RGB, mainly because this is also how our eye builds up colors in our eyes. Its base colors are red, green and blue. To code the transparency of a color sometimes a fourth element: alpha (A) is added. + +However, they are many color systems each with their own advantages: + +.. container:: enumeratevisibleitemswithsquare + + * RGB is the most common as our eyes use something similar, our display systems also compose colors using these. + * The HSV and HLS decompose colors into their hue, saturation and value/luminance components, which is a more natural way for us to describe colors. Using you may for example dismiss the last component, making your algorithm less sensible to light conditions of the input image. + * YCrCb is used by the popular JPEG image format. + * CIE L*a*b* is a perceptually uniform color space, which comes handy if you need to measure the *distance* of a given color to another color. + +Now each of the building components has their own valid domains. This leads to the data type used. How we store a component defines just how fine control we have over its domain. The smallest data type possible is *char*, which means one byte or 8 bits. This may be signed (so can store values from 0 to 255) or unsigned (values from -127 to +127). Although in case of three components this already gives 16 million possible colors to represent (like in case of RGB) we may acquire an even finer control by using the float (4 byte = 32 bit) or double (8 byte = 64 bit) data types for each component. Nevertheless, remember that increasing the size of a component also increases the size of the whole picture in the memory. + +Creating explicitly a *Mat* object +================================== + +In the :ref:`Load_Save_Image` tutorial you could already see how to write a matrix to an image file by using the :readWriteImageVideo:` imwrite() ` function. However, for debugging purposes it's much more convenient to see the actual values. You can achieve this via the << operator of *Mat*. However, be aware that this only works for two dimensional matrices. + +Although *Mat* is a great class as image container it is also a general matrix class. Therefore, it is possible to create and manipulate multidimensional matrices. You can create a Mat object in multiple ways: + +.. container:: enumeratevisibleitemswithsquare + + + :basicstructures:`Mat() ` Constructor + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 27-28 + + .. image:: images/MatBasicContainerOut1.png + :alt: Demo image of the matrix output + :align: center + + For two dimensional and multichannel images we first define their size: row and column count wise. + + Then we need to specify the data type to use for storing the elements and the number of channels per matrix point. To do this we have multiple definitions made according to the following convention: + + .. code-block:: cpp + + CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number] + + For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has three items of this to form the three channels. This are predefined for up to four channel numbers. The :basicstructures:`Scalar ` is four element short vector. Specify this and you can initialize all matrix points with a custom value. However if you need more you can create the type with the upper macro and putting the channel number in parenthesis as you can see below. + + + Use C\\C++ arrays and initialize via constructor + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 35-36 + + The upper example shows how to create a matrix with more than two dimensions. Specify its dimension, then pass a pointer containing the size for each dimension and the rest remains the same. + + + + Create a header for an already existing IplImage pointer: + + .. code-block:: cpp + + IplImage* img = cvLoadImage("greatwave.png", 1); + Mat mtx(img); // convert IplImage* -> Mat + + + :basicstructures:`Create() ` function: + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 31-32 + + .. image:: images/MatBasicContainerOut2.png + :alt: Demo image of the matrix output + :align: center + + You cannot initialize the matrix values with this construction. It will only reallocate its matrix data memory if the new size will not fit into the old one. + + + MATLAB style initializer: :basicstructures:`zeros() `, :basicstructures:`ones() `, ::basicstructures:`eyes() `. Specify size and data type to use: + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 40-47 + + .. image:: images/MatBasicContainerOut3.png + :alt: Demo image of the matrix output + :align: center + + + For small matrices you may use comma separated initializers: + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 50-51 + + .. image:: images/MatBasicContainerOut6.png + :alt: Demo image of the matrix output + :align: center + + + Create a new header for an existing *Mat* object and :basicstructures:`clone() ` or :basicstructures:`copyTo() ` it. + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 53-54 + + .. image:: images/MatBasicContainerOut7.png + :alt: Demo image of the matrix output + :align: center + +Print out formatting +==================== + +.. note:: + + You can fill out a matrix with random values using the :operationsOnArrays:`randu() ` function. You need to give the lover and upper value between what you want the random values: + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 57-58 + +In the above examples you could see the default formatting option. Nevertheless, OpenCV allows you to format your matrix output format to fit the rules of: + +.. container:: enumeratevisibleitemswithsquare + + + Default + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 61 + + .. image:: images/MatBasicContainerOut8.png + :alt: Default Output + :align: center + + + Python + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 62 + + .. image:: images/MatBasicContainerOut16.png + :alt: Default Output + :align: center + + + Comma separated values (CSV) + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 64 + + .. image:: images/MatBasicContainerOut10.png + :alt: Default Output + :align: center + + + Numpy + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 63 + + .. image:: images/MatBasicContainerOut9.png + :alt: Default Output + :align: center + + + C + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 65 + + .. image:: images/MatBasicContainerOut11.png + :alt: Default Output + :align: center + +Print for other common items +============================ + +OpenCV offers support for print of other common OpenCV data structures too via the << operator like: + +.. container:: enumeratevisibleitemswithsquare + + + 2D Point + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 67-68 + + .. image:: images/MatBasicContainerOut12.png + :alt: Default Output + :align: center + + + + 3D Point + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 70-71 + + .. image:: images/MatBasicContainerOut13.png + :alt: Default Output + :align: center + + + std::vector via cv::Mat + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 74-77 + + .. image:: images/MatBasicContainerOut14.png + :alt: Default Output + :align: center + + + std::vector of points + + .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp + :language: cpp + :tab-width: 4 + :lines: 79-83 + + .. image:: images/MatBasicContainerOut15.png + :alt: Default Output + :align: center + +Most of the samples here have been included into a small console application. You can download it from :download:`here <../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp>` or in the core section of the cpp samples. + +A quick video demonstration of this you can find on `YouTube `_. + +.. raw:: html + +
+ +
diff --git a/doc/tutorials/core/mat-mask-operations/images/resultMatMaskFilter2D.png b/doc/tutorials/core/mat-mask-operations/images/resultMatMaskFilter2D.png new file mode 100644 index 0000000000..cebbb4c33a Binary files /dev/null and b/doc/tutorials/core/mat-mask-operations/images/resultMatMaskFilter2D.png differ diff --git a/doc/tutorials/core/mat-mask-operations/mat-mask-operations.rst b/doc/tutorials/core/mat-mask-operations/mat-mask-operations.rst new file mode 100644 index 0000000000..135a2e4fc9 --- /dev/null +++ b/doc/tutorials/core/mat-mask-operations/mat-mask-operations.rst @@ -0,0 +1,137 @@ +.. _maskOperationsFilter: + +Mask operations on matrices +*************************** + +Mask operations on matrices are quite simple. The idea is that we recalculate each pixels value in an image according to a mask matrix (also known as kernel). This mask holds values that will just how much influence have neighbor pixel values (and the pixel value itself) to the new pixel value. From a mathematical point of view we make a weighted average, with our specified values. + +Our test case +============= + +Let us consider the issue of an image contrast enhancement method. Basically we want to apply for every pixel of the image the following formula: + +.. math:: + + I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)] + + \iff I(i,j)*M, \text{where } + M = \bordermatrix{ _i\backslash ^j & -1 & 0 & -1 \cr + -1 & 0 & -1 & 0 \cr + 0 & -1 & 5 & -1 \cr + +1 & 0 & -1 & 0 \cr + } + +The first notation is by using a formula, while the second is a compacted version of the first by using a mask. You use the mask by putting the center of the mask matrix (in the upper case noted by the zero-zero index) on the pixel you want to calculate and sum up the pixel values multiplicity with the overlapped matrix values. It's the same thing, however in case of large matrices the later notation is a lot easier to look over. + +Now let us see how we can make this happen by using the basic pixel access method or by using the :filtering:`filter2D ` function. + +The Basic Method +================ + +Here's a function that will do this: + +.. code-block:: cpp + + void Sharpen(const Mat& myImage,Mat& Result) + { + CV_Assert(myImage.depth() == CV_8U); // accept only uchar images + + Result.create(myImage.size(),myImage.type()); + const int nChannels = myImage.channels(); + + for(int j = 1 ; j < myImage.rows-1; ++j) + { + const uchar* previous = myImage.ptr(j - 1); + const uchar* current = myImage.ptr(j ); + const uchar* next = myImage.ptr(j + 1); + + uchar* output = Result.ptr(j); + + for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i) + { + *output++ = saturate_cast(5*current[i] + -current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]); + } + } + + Result.row(0).setTo(Scalar(0)); + Result.row(Result.rows-1).setTo(Scalar(0)); + Result.col(0).setTo(Scalar(0)); + Result.col(Result.cols-1).setTo(Scalar(0)); + } + +At first we make sure that the input images data is in unsigned char format. For this we use the :utilitysystemfunctions:`CV_Assert ` function that throws an error when the expression inside it is false. + +.. code-block:: cpp + + CV_Assert(myImage.depth() == CV_8U); // accept only uchar images + +We create an output image with the same size and the same type than our input. As you can see at the :ref:`How_Image_Stored_Memory` section, depending on the number of channels we may have one or more subcolumns. We will iterate through them via pointers so the total number of elements depends from this number. + +.. code-block:: cpp + + Result.create(myImage.size(),myImage.type()); + const int nChannels = myImage.channels(); + +We'll use the plain C [] operator to access pixels. Because we need to access multiple rows at the same time we'll acquire the pointers for each of them (a previous, a current and a next line). We need another pointer to where we're going to save the calculation. Then simply access the right items with the [] operator. For moving the output pointer ahead we simply increase this (with one byte) after each operation: + +.. code-block:: cpp + + for(int j = 1 ; j < myImage.rows-1; ++j) + { + const uchar* previous = myImage.ptr(j - 1); + const uchar* current = myImage.ptr(j ); + const uchar* next = myImage.ptr(j + 1); + + uchar* output = Result.ptr(j); + + for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i) + { + *output++ = saturate_cast(5*current[i] + -current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]); + } + } + +On the borders of the image the upper notation results inexistent pixel locations (like minus one - minus one). In these points our formula is undefined. A simple solution is to do not apply the mask in these points and, for example, maintain the images previous values by copying these values over to these locations: + +.. code-block:: cpp + + Result.row(0).setTo(Scalar(0)); // The top row + Result.row(Result.rows-1).setTo(Scalar(0)); // The left column + Result.col(0).setTo(Scalar(0)); // The right column + Result.col(Result.cols-1).setTo(Scalar(0)); // The bottom row + +The filter2D function +===================== + +Applying such filters are so common in image processing that in OpenCV there exist a function that will take care of applying the mask (also called a kernel in some places). For this you first need to define a *Mat* object that holds the mask: + +.. code-block:: cpp + + Mat kern = (Mat_(3,3) << 0, -1, 0, + -1, 5, -1, + 0, -1, 0); + +Then call the :filtering:`filter2D ` function specifying the input, the output image and the kernell to use: + +.. code-block:: cpp + + filter2D(I, K, I.depth(), kern ); + +The function even has a fifth optional argument to specify the center of the kernel, and a sixth one for determining what to do in the regions where the operation is undefined (borders). Using this function has the advantage that it's shorter, more verbose and that because they are some optimization techniques implemented usually faster than the *hand method*. For example in my while the first one took only 13 milliseconds the second took around 31 milliseconds. Quite some difference. + +For example: + +.. image:: images/resultMatMaskFilter2D.png + :alt: A sample output of the program + :align: center + +You can download this source code from :download:`here <../../../../samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp>` or look in the OpenCV source code libraries sample directory at :file:`samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp`. + +Check out an instance of running the program on our `YouTube channel `_ . + +.. raw:: html + +
+ +
diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.jpg b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..7c66c50d2f Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.png deleted file mode 100644 index 003f44d01d..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_1.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_1.png deleted file mode 100644 index 0334503d6b..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_1.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.jpg b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.jpg new file mode 100644 index 0000000000..81e9313ab2 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.jpg differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.png deleted file mode 100644 index 9287b20e1b..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_2.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.jpg b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.jpg new file mode 100644 index 0000000000..20e274dcfc Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.jpg differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.png deleted file mode 100644 index 482c3bffa5..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_3.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_4.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_4.png deleted file mode 100644 index e0e63812d9..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_4.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.jpg b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.jpg new file mode 100644 index 0000000000..a540fb4259 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.jpg differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.png deleted file mode 100644 index b0482fddf4..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_5.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_6.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_6.png deleted file mode 100644 index 40a079222f..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_6.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.jpg b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.jpg new file mode 100644 index 0000000000..cc38466e23 Binary files /dev/null and b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.jpg differ diff --git a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.png b/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.png deleted file mode 100644 index b47a588811..0000000000 Binary files a/doc/tutorials/core/random_generator_and_text/images/Drawing_2_Tutorial_Result_7.png and /dev/null differ diff --git a/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst b/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst index fda9b04b04..fb487cab71 100644 --- a/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst +++ b/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst @@ -1,7 +1,7 @@ .. _Drawing_2: -Fancy Drawing! -**************** +Random generator and text with OpenCV +************************************* Goals ====== @@ -9,15 +9,15 @@ Goals In this tutorial you will learn how to: * Use the *Random Number generator class* (:rng:`RNG <>`) and how to get a random number from a uniform distribution. -* Display Text on an OpenCV window by using the function :put_text:`putText <>` +* Display text on an OpenCV window by using the function :put_text:`putText <>` Code ===== -* In the previous tutorial we drew diverse geometric figures, giving as input parameters such as coordinates (in the form of :point:`Points <>`), color, thickness, etc. You might have noticed that we gave specific values for these arguments. +* In the previous tutorial (:ref:`Drawing_1`) we drew diverse geometric figures, giving as input parameters such as coordinates (in the form of :point:`Points <>`), color, thickness, etc. You might have noticed that we gave specific values for these arguments. -* In this tutorial, we intend to use *random* values for the drawing parameters. Also, we intend to populate our image with a big number of geometric figures. Since we will be initializing them in a random fashion, this process will be automatic and made by using *loops* +* In this tutorial, we intend to use *random* values for the drawing parameters. Also, we intend to populate our image with a big number of geometric figures. Since we will be initializing them in a random fashion, this process will be automatic and made by using *loops* . -* This code is in your OpenCV sample folder. Otherwise you can grab it from `here `_ +* This code is in your OpenCV sample folder. Otherwise you can grab it from `here `_ . Explanation ============ @@ -81,27 +81,23 @@ Explanation .. code-block:: cpp - /** - * @function Drawing_Random_Lines - */ int Drawing_Random_Lines( Mat image, char* window_name, RNG rng ) { int lineType = 8; Point pt1, pt2; - for( int i = 0; i < NUMBER; i++ ) - { - pt1.x = rng.uniform( x_1, x_2 ); - pt1.y = rng.uniform( y_1, y_2 ); - pt2.x = rng.uniform( x_1, x_2 ); - pt2.y = rng.uniform( y_1, y_2 ); + for( int i = 0; i < NUMBER; i++ ) + { + pt1.x = rng.uniform( x_1, x_2 ); + pt1.y = rng.uniform( y_1, y_2 ); + pt2.x = rng.uniform( x_1, x_2 ); + pt2.y = rng.uniform( y_1, y_2 ); line( image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), 8 ); - imshow( window_name, image ); + imshow( window_name, image ); if( waitKey( DELAY ) >= 0 ) - { return -1; } + { return -1; } } - return 0; } @@ -122,18 +118,18 @@ Explanation * As another observation, we notice that in the :line:`line <>` arguments, for the *color* input we enter: .. code-block:: cpp - - randomColor(rng) - + + randomColor(rng) + Let's check the function implementation: .. code-block:: cpp - static Scalar randomColor( RNG& rng ) - { + static Scalar randomColor( RNG& rng ) + { int icolor = (unsigned) rng; return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 ); - } + } As we can see, the return value is an *Scalar* with 3 randomly initialized values, which are used as the *R*, *G* and *B* parameters for the line color. Hence, the color of the lines will be random too! @@ -192,21 +188,21 @@ Explanation int Displaying_Big_End( Mat image, char* window_name, RNG rng ) { Size textsize = getTextSize("OpenCV forever!", CV_FONT_HERSHEY_COMPLEX, 3, 5, 0); - Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2); - int lineType = 8; + Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2); + int lineType = 8; - Mat image2; + Mat image2; - for( int i = 0; i < 255; i += 2 ) - { - image2 = image - Scalar::all(i); - putText( image2, "OpenCV forever!", org, CV_FONT_HERSHEY_COMPLEX, 3, - Scalar(i, i, 255), 5, lineType ); + for( int i = 0; i < 255; i += 2 ) + { + image2 = image - Scalar::all(i); + putText( image2, "OpenCV forever!", org, CV_FONT_HERSHEY_COMPLEX, 3, + Scalar(i, i, 255), 5, lineType ); - imshow( window_name, image2 ); - if( waitKey(DELAY) >= 0 ) - { return -1; } - } + imshow( window_name, image2 ); + if( waitKey(DELAY) >= 0 ) + { return -1; } + } return 0; } @@ -229,57 +225,36 @@ As you just saw in the Code section, the program will sequentially execute diver #. First a random set of *NUMBER* lines will appear on screen such as it can be seen in this screenshot: - .. image:: images/Drawing_2_Tutorial_Result_0.png - :height: 300px + .. image:: images/Drawing_2_Tutorial_Result_0.jpg :alt: Drawing Tutorial 2 - Final Result 0 :align: center -#. Then, a new set of figures, these time *rectangles* will follow: - - .. image:: images/Drawing_2_Tutorial_Result_1.png - :height: 300px - :alt: Drawing Tutorial 2 - Final Result 1 - :align: center +#. Then, a new set of figures, these time *rectangles* will follow. #. Now some ellipses will appear, each of them with random position, size, thickness and arc length: - .. image:: images/Drawing_2_Tutorial_Result_2.png - :height: 300px + .. image:: images/Drawing_2_Tutorial_Result_2.jpg :alt: Drawing Tutorial 2 - Final Result 2 :align: center #. Now, *polylines* with 03 segments will appear on screen, again in random configurations. - .. image:: images/Drawing_2_Tutorial_Result_3.png - :height: 300px + .. image:: images/Drawing_2_Tutorial_Result_3.jpg :alt: Drawing Tutorial 2 - Final Result 3 :align: center -#. Filled polygons (in this example triangles) will follow: - - .. image:: images/Drawing_2_Tutorial_Result_4.png - :height: 300px - :alt: Drawing Tutorial 2 - Final Result 4 - :align: center +#. Filled polygons (in this example triangles) will follow. #. The last geometric figure to appear: circles! - .. image:: images/Drawing_2_Tutorial_Result_5.png - :height: 300px + .. image:: images/Drawing_2_Tutorial_Result_5.jpg :alt: Drawing Tutorial 2 - Final Result 5 :align: center #. Near the end, the text *"Testing Text Rendering"* will appear in a variety of fonts, sizes, colors and positions. - .. image:: images/Drawing_2_Tutorial_Result_6.png - :height: 300px - :alt: Drawing Tutorial 2 - Final Result 6 - :align: center - #. And the big end (which by the way expresses a big truth too): - .. image:: images/Drawing_2_Tutorial_Result_7.png - :height: 300px + .. image:: images/Drawing_2_Tutorial_Result_7.jpg :alt: Drawing Tutorial 2 - Final Result 7 - :align: center - + :align: center \ No newline at end of file diff --git a/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.jpg b/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..940b54c82f Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.png b/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.png deleted file mode 100644 index e86aee1b37..0000000000 Binary files a/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg b/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..eccf37aa20 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.png b/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.png deleted file mode 100644 index 3d2fcdc9ee..0000000000 Binary files a/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.jpg b/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..05e8f01232 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.png b/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.png deleted file mode 100644 index 9cfbef6002..0000000000 Binary files a/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.jpg b/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.jpg new file mode 100644 index 0000000000..d650c18427 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.png b/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.png deleted file mode 100644 index 2711552b0b..0000000000 Binary files a/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.png and /dev/null differ diff --git a/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.jpg b/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.jpg new file mode 100644 index 0000000000..71509ba5b8 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.png b/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.png deleted file mode 100644 index 2f9b038058..0000000000 Binary files a/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.jpg b/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.jpg new file mode 100644 index 0000000000..c11f2ed024 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.png b/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.png deleted file mode 100644 index 3152ea591e..0000000000 Binary files a/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/core/table_of_content_core/images/discrete_fourier_transform.png b/doc/tutorials/core/table_of_content_core/images/discrete_fourier_transform.png new file mode 100644 index 0000000000..07bd1119f4 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/discrete_fourier_transform.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/file_input_output_with_xml_yml.png b/doc/tutorials/core/table_of_content_core/images/file_input_output_with_xml_yml.png new file mode 100644 index 0000000000..24ae4fdd23 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/file_input_output_with_xml_yml.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/howToScanImages.jpg b/doc/tutorials/core/table_of_content_core/images/howToScanImages.jpg new file mode 100644 index 0000000000..4e0fa26d0d Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/howToScanImages.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/images/interopOpenCV1.png b/doc/tutorials/core/table_of_content_core/images/interopOpenCV1.png new file mode 100644 index 0000000000..040f50a003 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/interopOpenCV1.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/matMaskFilter2DOp.png b/doc/tutorials/core/table_of_content_core/images/matMaskFilter2DOp.png new file mode 100644 index 0000000000..6795921608 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/matMaskFilter2DOp.png differ diff --git a/doc/tutorials/core/table_of_content_core/images/matTheBasicImageStructure.jpg b/doc/tutorials/core/table_of_content_core/images/matTheBasicImageStructure.jpg new file mode 100644 index 0000000000..ab6704a3c9 Binary files /dev/null and b/doc/tutorials/core/table_of_content_core/images/matTheBasicImageStructure.jpg differ diff --git a/doc/tutorials/core/table_of_content_core/table_of_content_core.rst b/doc/tutorials/core/table_of_content_core/table_of_content_core.rst index 54fd5d1549..fe5e43a09c 100644 --- a/doc/tutorials/core/table_of_content_core/table_of_content_core.rst +++ b/doc/tutorials/core/table_of_content_core/table_of_content_core.rst @@ -5,84 +5,217 @@ Here you will learn the about the basic building blocks of the library. A must read and know for understanding how to manipulate the images on a pixel level. +.. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |MatBasicIma| **Title:** :ref:`matTheBasicImageContainer` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will learn how to store images in the memory and how to print out their content to the console. + + =============== ====================================================== + + .. |MatBasicIma| image:: images/matTheBasicImageStructure.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |HowScanImag| **Title:** :ref:`howToScanImagesOpenCV` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You'll find out how to scan images (go through each of the image pixels) with OpenCV. Bonus: time measurement with OpenCV. + + =============== ====================================================== + + .. |HowScanImag| image:: images/howToScanImages.jpg + :height: 90pt + :width: 90pt + + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |HowFilterIm| **Title:** :ref:`maskOperationsFilter` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You'll find out how to scan images with neighbor access and use the :filtering:`filter2D ` function to apply kernel filters on images. + + =============== ====================================================== + + .. |HowFilterIm| image:: images/matMaskFilter2DOp.png + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |Beginners_4| **Title:** :ref:`Adding_Images` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to blend two images! + + =============== ====================================================== + + .. |Beginners_4| image:: images/Adding_Images_Tutorial_Result_0.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ==================================================== + |Bas_Lin_Tran| **Title:** :ref:`Basic_Linear_Transform` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to change our image appearance! + + =============== ==================================================== + + .. |Bas_Lin_Tran| image:: images/Basic_Linear_Transform_Tutorial_Result_0.jpg + :height: 90pt + :width: 90pt + + + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |Beginners_6| **Title:** :ref:`Drawing_1` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to draw simple geometry with OpenCV! + + =============== ====================================================== + + .. |Beginners_6| image:: images/Drawing_1_Tutorial_Result_0.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |Beginners_7| **Title:** :ref:`Drawing_2` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will draw some *fancy-looking* stuff using OpenCV! + + =============== ====================================================== + + .. |Beginners_7| image:: images/Drawing_2_Tutorial_Result_7.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |DiscFourTr| **Title:** :ref:`discretFourierTransform` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will see how and why use the Discrete Fourier transformation with OpenCV. + + =============== ====================================================== + + .. |DiscFourTr| image:: images/discrete_fourier_transform.png + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |FileIOXMLYAML| **Title:** :ref:`fileInputOutputXMLYAML` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will see how to use the :xmlymlpers:`FileStorage ` data structure of OpenCV to write and read data to XML or YAML file format. + + =============== ====================================================== + + .. |FileIOXMLYAML| image:: images/file_input_output_with_xml_yml.png + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |InterOOpenCV1| **Title:** :ref:`InteroperabilityWithOpenCV1` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + Did you used OpenCV before its 2.0 version? Do you wanna know what happened with your library with 2.0? Don't you know how to convert your old OpenCV programs to the new C++ interface? Look here to shed light on all this questions. + + =============== ====================================================== + + .. |InterOOpenCV1| image:: images/interopOpenCV1.png + :height: 90pt + :width: 90pt + + + +.. raw:: latex + + \pagebreak + .. toctree:: :hidden: + ../mat - the basic image container/mat - the basic image container + ../how_to_scan_images/how_to_scan_images + ../mat-mask-operations/mat-mask-operations ../adding_images/adding_images ../basic_linear_transform/basic_linear_transform ../basic_geometric_drawing/basic_geometric_drawing ../random_generator_and_text/random_generator_and_text - -.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n - -* :ref:`Adding_Images` - - =============== ====================================================== - |Beginners_4| *Title:* **Linear Blending** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to blend two images! - - =============== ====================================================== - -.. |Beginners_4| image:: images/Adding_Images_Tutorial_Result_0.png - :height: 100pt - :width: 100pt - -* :ref:`Basic_Linear_Transform` - - =============== ==================================================== - |Bas_Lin_Tran| *Title:* **Changing the contrast and brightness of an image** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to change our image appearance! - - =============== ==================================================== - - .. |Bas_Lin_Tran| image:: images/Basic_Linear_Transform_Tutorial_Result_0.png - :height: 100pt - :width: 100pt - - - -* :ref:`Drawing_1` - - =============== ====================================================== - |Beginners_6| *Title:* **Basic Drawing** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to draw simple geometry with OpenCV! - - =============== ====================================================== - -.. |Beginners_6| image:: images/Drawing_1_Tutorial_Result_0.png - :height: 100pt - :width: 100pt - - -* :ref:`Drawing_2` - - =============== ====================================================== - |Beginners_7| *Title:* **Cool Drawing** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will draw some *fancy-looking* stuff using OpenCV! - - =============== ====================================================== - - .. |Beginners_7| image:: images/Drawing_2_Tutorial_Result_7.png - :height: 100pt - :width: 100pt - + ../discrete_fourier_transform/discrete_fourier_transform + ../file_input_output_with_xml_yml/file_input_output_with_xml_yml + ../interoperability_with_OpenCV_1/interoperability_with_OpenCV_1 \ No newline at end of file diff --git a/doc/tutorials/definitions/README.txt b/doc/tutorials/definitions/README.txt index e69de29bb2..829e27cacb 100644 --- a/doc/tutorials/definitions/README.txt +++ b/doc/tutorials/definitions/README.txt @@ -0,0 +1 @@ +Include in this directory only defintion files. None of the reST files entered here will be parsed by the Sphinx Builder. \ No newline at end of file diff --git a/doc/tutorials/definitions/formatStyleSizeDef.rst b/doc/tutorials/definitions/formatStyleSizeDef.rst new file mode 100644 index 0000000000..c4b8785979 --- /dev/null +++ b/doc/tutorials/definitions/formatStyleSizeDef.rst @@ -0,0 +1,5 @@ +.. |TOC_Image_Width| replace:: 100pt + +.. |TOC_Image_Height| replace:: 100pt + +.. |TOC diff --git a/doc/tutorials/definitions/tocDefinitions.rst b/doc/tutorials/definitions/tocDefinitions.rst new file mode 100644 index 0000000000..2621c58bdb --- /dev/null +++ b/doc/tutorials/definitions/tocDefinitions.rst @@ -0,0 +1,8 @@ +.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n +.. |Author_BernatG| unicode:: Bern U+00E1 t U+0020 G U+00E1 bor +.. |Author_AndreyK| unicode:: Andrey U+0020 Kamaev +.. |Author_LeonidBLB| unicode:: Leonid U+0020 Beynenson +.. |Author_VictorE| unicode:: Victor U+0020 Eruhimov +.. |Author_FernandoI| unicode:: Fernando U+0020 Iglesias U+0020 Garc U+00ED a + + diff --git a/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.rst b/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.rst new file mode 100644 index 0000000000..2345b9e5a8 --- /dev/null +++ b/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.rst @@ -0,0 +1,72 @@ +.. _detectionOfPlanarObjects: + +Detection of planar objects +*************************** + +.. highlight:: cpp + +The goal of this tutorial is to learn how to use *features2d* and *calib3d* modules for detecting known planar objects in scenes. + +*Test data*: use images in your data folder, for instance, ``box.png`` and ``box_in_scene.png``. + +#. + Create a new console project. Read two input images. :: + + Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); + Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE); + +#. + Detect keypoints in both images. :: + + // detecting keypoints + FastFeatureDetector detector(15); + vector keypoints1; + detector.detect(img1, keypoints1); + + ... // do the same for the second image + +#. + Compute descriptors for each of the keypoints. :: + + // computing descriptors + SurfDescriptorExtractor extractor; + Mat descriptors1; + extractor.compute(img1, keypoints1, descriptors1); + + ... // process keypoints from the second image as well + +#. + Now, find the closest matches between descriptors from the first image to the second: :: + + // matching descriptors + BruteForceMatcher > matcher; + vector matches; + matcher.match(descriptors1, descriptors2, matches); + +#. + Visualize the results: :: + + // drawing the results + namedWindow("matches", 1); + Mat img_matches; + drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches); + imshow("matches", img_matches); + waitKey(0); + +#. + Find the homography transformation between two sets of points: :: + + vector points1, points2; + // fill the arrays with the points + .... + Mat H = findHomography(Mat(points1), Mat(points2), CV_RANSAC, ransacReprojThreshold); + + +#. + Create a set of inlier matches and draw them. Use perspectiveTransform function to map points with homography: + + Mat points1Projected; + perspectiveTransform(Mat(points1), points1Projected, H); + +#. + Use ``drawMatches`` for drawing inliers. diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/detection_of_planar_objects.png b/doc/tutorials/features2d/table_of_content_features2d/images/detection_of_planar_objects.png new file mode 100644 index 0000000000..92de70cfdc Binary files /dev/null and b/doc/tutorials/features2d/table_of_content_features2d/images/detection_of_planar_objects.png differ diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg new file mode 100644 index 0000000000..61ec8d1d89 Binary files /dev/null and b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg differ diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg new file mode 100644 index 0000000000..89fc7bef7c Binary files /dev/null and b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg differ diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Harris_Detector_Cover.jpg b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Harris_Detector_Cover.jpg new file mode 100644 index 0000000000..bc4d816e32 Binary files /dev/null and b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Harris_Detector_Cover.jpg differ diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg new file mode 100644 index 0000000000..e0ee608d9c Binary files /dev/null and b/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg differ diff --git a/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst b/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst index 725af28d80..062f03fd70 100644 --- a/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst +++ b/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst @@ -5,4 +5,115 @@ Learn about how to use the feature points detectors, descriptors and matching framework found inside OpenCV. -.. include:: ../../definitions/noContent.rst +.. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |Harris| **Title:** :ref:`harris_detector` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Why is it a good idea to track corners? We learn to use the Harris method to detect corners + + ===================== ============================================== + + .. |Harris| image:: images/trackingmotion/Harris_Detector_Cover.jpg + :height: 90pt + :width: 90pt + + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |ShiTomasi| **Title:** :ref:`good_features_to_track` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we use an improved method to detect corners more accuratelyI + + ===================== ============================================== + + .. |ShiTomasi| image:: images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg + :height: 90pt + :width: 90pt + + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |GenericCorner| **Title:** :ref:`generic_corner_detector` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Here you will learn how to use OpenCV functions to make your personalized corner detector! + + ===================== ============================================== + + .. |GenericCorner| image:: images/trackingmotion/Generic_Corner_Detector_Cover.jpg + :height: 90pt + :width: 90pt + + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |Subpixel| **Title:** :ref:`corner_subpixeles` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Is pixel resolution enough? Here we learn a simple method to improve our accuracy. + + ===================== ============================================== + + .. |Subpixel| image:: images/trackingmotion/Corner_Subpixeles_Cover.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |DetectPlanar| **Title:** :ref:`detectionOfPlanarObjects` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_VictorE| + + You will use *features2d* and *calib3d* modules for detecting known planar objects in scenes. + + ===================== ============================================== + + .. |DetectPlanar| image:: images/detection_of_planar_objects.png + :height: 90pt + :width: 90pt + +.. raw:: latex + + \pagebreak + +.. toctree:: + :hidden: + + ../trackingmotion/harris_detector/harris_detector + ../trackingmotion/good_features_to_track/good_features_to_track.rst + ../trackingmotion/generic_corner_detector/generic_corner_detector + ../trackingmotion/corner_subpixeles/corner_subpixeles + ../detection_of_planar_objects/detection_of_planar_objects \ No newline at end of file diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.rst b/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.rst new file mode 100644 index 0000000000..e3291a8556 --- /dev/null +++ b/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.rst @@ -0,0 +1,138 @@ +.. _corner_subpixeles: + +Detecting corners location in subpixeles +**************************************** + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :corner_sub_pix:`cornerSubPix <>` to find more exact corner positions (more exact than integer pixels). + + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + /// Global variables + Mat src, src_gray; + + int maxCorners = 10; + int maxTrackbar = 25; + + RNG rng(12345); + char* source_window = "Image"; + + /// Function header + void goodFeaturesToTrack_Demo( int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Create Window + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + + /// Create Trackbar to set the number of corners + createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo); + + imshow( source_window, src ); + + goodFeaturesToTrack_Demo( 0, 0 ); + + waitKey(0); + return(0); + } + + /** + * @function goodFeaturesToTrack_Demo.cpp + * @brief Apply Shi-Tomasi corner detector + */ + void goodFeaturesToTrack_Demo( int, void* ) + { + if( maxCorners < 1 ) { maxCorners = 1; } + + /// Parameters for Shi-Tomasi algorithm + vector corners; + double qualityLevel = 0.01; + double minDistance = 10; + int blockSize = 3; + bool useHarrisDetector = false; + double k = 0.04; + + /// Copy the source image + Mat copy; + copy = src.clone(); + + /// Apply corner detection + goodFeaturesToTrack( src_gray, + corners, + maxCorners, + qualityLevel, + minDistance, + Mat(), + blockSize, + useHarrisDetector, + k ); + + + /// Draw corners detected + cout<<"** Number of corners detected: "<` to find the eigenvalues and eigenvectors to determine if a pixel is a corner. + * Use the OpenCV function :corner_min_eigenval:`cornerMinEigenVal <>` to find the minimum eigenvalues for corner detection. + * To implement our own version of the Harris detector as well as the Shi-Tomasi detector, by using the two functions above. + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + /// Global variables + Mat src, src_gray; + Mat myHarris_dst; Mat myHarris_copy; Mat Mc; + Mat myShiTomasi_dst; Mat myShiTomasi_copy; + + int myShiTomasi_qualityLevel = 50; + int myHarris_qualityLevel = 50; + int max_qualityLevel = 100; + + double myHarris_minVal; double myHarris_maxVal; + double myShiTomasi_minVal; double myShiTomasi_maxVal; + + RNG rng(12345); + + char* myHarris_window = "My Harris corner detector"; + char* myShiTomasi_window = "My Shi Tomasi corner detector"; + + /// Function headers + void myShiTomasi_function( int, void* ); + void myHarris_function( int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Set some parameters + int blockSize = 3; int apertureSize = 3; + + /// My Harris matrix -- Using cornerEigenValsAndVecs + myHarris_dst = Mat::zeros( src_gray.size(), CV_32FC(6) ); + Mc = Mat::zeros( src_gray.size(), CV_32FC1 ); + + cornerEigenValsAndVecs( src_gray, myHarris_dst, blockSize, apertureSize, BORDER_DEFAULT ); + + /* calculate Mc */ + for( int j = 0; j < src_gray.rows; j++ ) + { for( int i = 0; i < src_gray.cols; i++ ) + { + float lambda_1 = myHarris_dst.at( j, i, 0 ); + float lambda_2 = myHarris_dst.at( j, i, 1 ); + Mc.at(j,i) = lambda_1*lambda_2 - 0.04*pow( ( lambda_1 + lambda_2 ), 2 ); + } + } + + minMaxLoc( Mc, &myHarris_minVal, &myHarris_maxVal, 0, 0, Mat() ); + + /* Create Window and Trackbar */ + namedWindow( myHarris_window, CV_WINDOW_AUTOSIZE ); + createTrackbar( " Quality Level:", myHarris_window, &myHarris_qualityLevel, max_qualityLevel, + myHarris_function ); + myHarris_function( 0, 0 ); + + /// My Shi-Tomasi -- Using cornerMinEigenVal + myShiTomasi_dst = Mat::zeros( src_gray.size(), CV_32FC1 ); + cornerMinEigenVal( src_gray, myShiTomasi_dst, blockSize, apertureSize, BORDER_DEFAULT ); + + minMaxLoc( myShiTomasi_dst, &myShiTomasi_minVal, &myShiTomasi_maxVal, 0, 0, Mat() ); + + /* Create Window and Trackbar */ + namedWindow( myShiTomasi_window, CV_WINDOW_AUTOSIZE ); + createTrackbar( " Quality Level:", myShiTomasi_window, &myShiTomasi_qualityLevel, max_qualityLevel, + myShiTomasi_function ); + myShiTomasi_function( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function myShiTomasi_function */ + void myShiTomasi_function( int, void* ) + { + myShiTomasi_copy = src.clone(); + + if( myShiTomasi_qualityLevel < 1 ) { myShiTomasi_qualityLevel = 1; } + + for( int j = 0; j < src_gray.rows; j++ ) + { for( int i = 0; i < src_gray.cols; i++ ) + { + if( myShiTomasi_dst.at(j,i) > myShiTomasi_minVal + ( myShiTomasi_maxVal - + myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel ) + { circle( myShiTomasi_copy, Point(i,j), 4, Scalar( rng.uniform(0,255), + rng.uniform(0,255), rng.uniform(0,255) ), -1, 8, 0 ); } + } + } + imshow( myShiTomasi_window, myShiTomasi_copy ); + } + + /** @function myHarris_function */ + void myHarris_function( int, void* ) + { + myHarris_copy = src.clone(); + + if( myHarris_qualityLevel < 1 ) { myHarris_qualityLevel = 1; } + + for( int j = 0; j < src_gray.rows; j++ ) + { for( int i = 0; i < src_gray.cols; i++ ) + { + if( Mc.at(j,i) > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal ) + *myHarris_qualityLevel/max_qualityLevel ) + { circle( myHarris_copy, Point(i,j), 4, Scalar( rng.uniform(0,255), rng.uniform(0,255), + rng.uniform(0,255) ), -1, 8, 0 ); } + } + } + imshow( myHarris_window, myHarris_copy ); + } + + + +Explanation +============ + +Result +====== + +.. image:: images/My_Harris_corner_detector_Result.jpg + :align: center + + +.. image:: images/My_Shi_Tomasi_corner_detector_Result.jpg + :align: center + diff --git a/doc/tutorials/features2d/trackingmotion/generic_corner_detector/images/My_Harris_corner_detector_Result.jpg b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/images/My_Harris_corner_detector_Result.jpg new file mode 100644 index 0000000000..d2ef409b19 Binary files /dev/null and b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/images/My_Harris_corner_detector_Result.jpg differ diff --git a/doc/tutorials/features2d/trackingmotion/generic_corner_detector/images/My_Shi_Tomasi_corner_detector_Result.jpg b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/images/My_Shi_Tomasi_corner_detector_Result.jpg new file mode 100644 index 0000000000..0cca430d8c Binary files /dev/null and b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/images/My_Shi_Tomasi_corner_detector_Result.jpg differ diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.rst b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.rst new file mode 100644 index 0000000000..00782364b2 --- /dev/null +++ b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.rst @@ -0,0 +1,122 @@ +.. _good_features_to_track: + +Shi-Tomasi corner detector +************************** + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the function :good_features_to_track:`goodFeaturesToTrack <>` to detect corners using the Shi-Tomasi method. + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + /// Global variables + Mat src, src_gray; + + int maxCorners = 23; + int maxTrackbar = 100; + + RNG rng(12345); + char* source_window = "Image"; + + /// Function header + void goodFeaturesToTrack_Demo( int, void* ); + + /** + * @function main + */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Create Window + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + + /// Create Trackbar to set the number of corners + createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo ); + + imshow( source_window, src ); + + goodFeaturesToTrack_Demo( 0, 0 ); + + waitKey(0); + return(0); + } + + /** + * @function goodFeaturesToTrack_Demo.cpp + * @brief Apply Shi-Tomasi corner detector + */ + void goodFeaturesToTrack_Demo( int, void* ) + { + if( maxCorners < 1 ) { maxCorners = 1; } + + /// Parameters for Shi-Tomasi algorithm + vector corners; + double qualityLevel = 0.01; + double minDistance = 10; + int blockSize = 3; + bool useHarrisDetector = false; + double k = 0.04; + + /// Copy the source image + Mat copy; + copy = src.clone(); + + /// Apply corner detection + goodFeaturesToTrack( src_gray, + corners, + maxCorners, + qualityLevel, + minDistance, + Mat(), + blockSize, + useHarrisDetector, + k ); + + + /// Draw corners detected + cout<<"** Number of corners detected: "<` to detect corners using the Harris-Stephens method. + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + /// Global variables + Mat src, src_gray; + int thresh = 200; + int max_thresh = 255; + + char* source_window = "Source image"; + char* corners_window = "Corners detected"; + + /// Function header + void cornerHarris_demo( int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Create a window and a trackbar + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo ); + imshow( source_window, src ); + + cornerHarris_demo( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function cornerHarris_demo */ + void cornerHarris_demo( int, void* ) + { + + Mat dst, dst_norm, dst_norm_scaled; + dst = Mat::zeros( src.size(), CV_32FC1 ); + + /// Detector parameters + int blockSize = 2; + int apertureSize = 3; + double k = 0.04; + + /// Detecting corners + cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT ); + + /// Normalizing + normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); + convertScaleAbs( dst_norm, dst_norm_scaled ); + + /// Drawing a circle around corners + for( int j = 0; j < dst_norm.rows ; j++ ) + { for( int i = 0; i < dst_norm.cols; i++ ) + { + if( (int) dst_norm.at(j,i) > thresh ) + { + circle( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 ); + } + } + } + /// Showing the result + namedWindow( corners_window, CV_WINDOW_AUTOSIZE ); + imshow( corners_window, dst_norm_scaled ); + } + + +Explanation +============ + +Result +====== + +The original image: + +.. image:: images/Harris_Detector_Original_Image.jpg + :align: center + +The detected corners are surrounded by a small black circle + +.. image:: images/Harris_Detector_Result.jpg + :align: center + + diff --git a/doc/tutorials/features2d/trackingmotion/harris_detector/images/Harris_Detector_Original_Image.jpg b/doc/tutorials/features2d/trackingmotion/harris_detector/images/Harris_Detector_Original_Image.jpg new file mode 100644 index 0000000000..4dd0778b9e Binary files /dev/null and b/doc/tutorials/features2d/trackingmotion/harris_detector/images/Harris_Detector_Original_Image.jpg differ diff --git a/doc/tutorials/features2d/trackingmotion/harris_detector/images/Harris_Detector_Result.jpg b/doc/tutorials/features2d/trackingmotion/harris_detector/images/Harris_Detector_Result.jpg new file mode 100644 index 0000000000..189f318118 Binary files /dev/null and b/doc/tutorials/features2d/trackingmotion/harris_detector/images/Harris_Detector_Result.jpg differ diff --git a/doc/tutorials/general/table_of_content_general/table_of_content_general.rst b/doc/tutorials/general/table_of_content_general/table_of_content_general.rst index 36dbac2b60..2a6d57ffb9 100644 --- a/doc/tutorials/general/table_of_content_general/table_of_content_general.rst +++ b/doc/tutorials/general/table_of_content_general/table_of_content_general.rst @@ -6,3 +6,8 @@ General tutorials These tutorials are the bottom of the iceberg as they link together multiple of the modules presented above in order to solve complex problems. .. include:: ../../definitions/noContent.rst + +.. raw:: latex + + \pagebreak + diff --git a/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst b/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst index 1c2e91d9e4..cadbcfd384 100644 --- a/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst +++ b/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst @@ -6,3 +6,7 @@ Squeeze out every little computation power from your system by using the power of your video card to run the OpenCV algorithms. .. include:: ../../definitions/noContent.rst + +.. raw:: latex + + \pagebreak diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.jpg b/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.jpg new file mode 100644 index 0000000000..e914cab1d5 Binary files /dev/null and b/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.png b/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.png deleted file mode 100644 index d3b85ba523..0000000000 Binary files a/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/video-input-psnr-ssim.png b/doc/tutorials/highgui/table_of_content_highgui/images/video-input-psnr-ssim.png new file mode 100644 index 0000000000..de8c2835a6 Binary files /dev/null and b/doc/tutorials/highgui/table_of_content_highgui/images/video-input-psnr-ssim.png differ diff --git a/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst b/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst index 56f80ce49e..b03f1a66c7 100644 --- a/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst +++ b/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst @@ -5,22 +5,52 @@ This section contains valuable tutorials about how to read/save your image/video files and how to use the built-in graphical user interface of the library. +.. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |Beginners_5| *Title:* :ref:`Adding_Trackbars` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to add a Trackbar to our applications + + =============== ====================================================== + + .. |Beginners_5| image:: images/Adding_Trackbars_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |hVideoInput| *Title:* :ref:`videoInputPSNRMSSIM` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will learn how to read video streams, and how to calculate similarity values such as PSNR or SSIM. + + =============== ====================================================== + + .. |hVideoInput| image:: images/video-input-psnr-ssim.png + :height: 90pt + :width: 90pt + +.. raw:: latex + + \pagebreak + .. toctree:: :hidden: - + ../trackbar/trackbar - -* :ref:`Adding_Trackbars` - - =============== ====================================================== - |Beginners_5| *Title:* **Creating Trackbars** - - *Compatibility:* > OpenCV 2.0 - - We will learn how to add a Trackbar to our applications - - =============== ====================================================== - - .. |Beginners_5| image:: images/Adding_Trackbars_Tutorial_Cover.png - :height: 100pt - :width: 100pt + ../video-input-psnr-ssim/video-input-psnr-ssim diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Cover.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Cover.png deleted file mode 100644 index 8dfab5ba73..0000000000 Binary files a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.jpg b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..d18529711b Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.png deleted file mode 100644 index 29149f0253..0000000000 Binary files a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_0.png and /dev/null differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.jpg b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.jpg new file mode 100644 index 0000000000..a1ef11f9c6 Binary files /dev/null and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.jpg differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.png deleted file mode 100644 index 4c8aba3ce2..0000000000 Binary files a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1.png and /dev/null differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1a.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1a.png deleted file mode 100644 index feec159437..0000000000 Binary files a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1a.png and /dev/null differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1b.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1b.png deleted file mode 100644 index 5873859e31..0000000000 Binary files a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Result_1b.png and /dev/null differ diff --git a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png index a74327f8aa..16a6feec5a 100644 Binary files a/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png and b/doc/tutorials/highgui/trackbar/images/Adding_Trackbars_Tutorial_Trackbar.png differ diff --git a/doc/tutorials/highgui/trackbar/trackbar.rst b/doc/tutorials/highgui/trackbar/trackbar.rst index c5b77abed1..21f8b3687c 100644 --- a/doc/tutorials/highgui/trackbar/trackbar.rst +++ b/doc/tutorials/highgui/trackbar/trackbar.rst @@ -145,15 +145,14 @@ Result * Our program produces the following output: - .. image:: images/Adding_Trackbars_Tutorial_Result_0.png + .. image:: images/Adding_Trackbars_Tutorial_Result_0.jpg :alt: Adding Trackbars - Windows Linux :align: center * As a manner of practice, you can also add 02 trackbars for the program made in :ref:`Basic_Linear_Transform`. One trackbar to set :math:`\alpha` and another for :math:`\beta`. The output might look like: - .. image:: images/Adding_Trackbars_Tutorial_Result_1.png + .. image:: images/Adding_Trackbars_Tutorial_Result_1.jpg :alt: Adding Trackbars - Lena - :height: 500px :align: center diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png b/doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png new file mode 100644 index 0000000000..7df9235d71 Binary files /dev/null and b/doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png differ diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.rst b/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.rst new file mode 100644 index 0000000000..4bde0be6bb --- /dev/null +++ b/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.rst @@ -0,0 +1,216 @@ +.. _videoInputPSNRMSSIM: + +Video Input with OpenCV and similarity measurement +************************************************** + +Goal +==== + +Today it is common to have a digital video recording system at your disposal. Therefore, you will eventually come to the situation that you no longer process a batch of images, but video streams. These may be of two kinds: real-time image feed (in the case of a webcam) or prerecorded and hard disk drive stored files. Luckily OpenCV threats these two in the same manner, with the same C++ class. So here's what you'll learn in this tutorial: + +.. container:: enumeratevisibleitemswithsquare + + + How to open and read video streams + + Two ways for checking image similarity: PSNR and SSIM + +The source code +=============== + +As a test case where to show off these using OpenCV I've created a small program that reads in two video files and performs a similarity check between them. This is something you could use to check just how well a new video compressing algorithms works. Let there be a reference (original) video like :download:`this small Megamind clip <../../../../samples/cpp/tutorial_code/highgui/video-input-psnr-ssim/video/Megamind.avi>` and :download:`a compressed version of it <../../../../samples/cpp/tutorial_code/highgui/video-input-psnr-ssim/video/Megamind_bugy.avi>`. You may also find the source code and these video file in the :file:`samples/cpp/tutorial_code/highgui/video-input-psnr-ssim/` folder of the OpenCV source library. + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/HighGUI\video-input-psnr-ssim\video-input-psnr-ssim.cpp + :language: cpp + :linenos: + :tab-width: 4 + :lines: 1-14, 28-29, 31-205 + +How to read a video stream (online-camera or offline-file)? +=========================================================== + +Essentially, all the functionalities required for video manipulation is integrated in the :huivideo:`VideoCapture ` C++ class. This on itself builds on the FFmpeg open source library. This is a basic dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession of images, we refer to these in the literature as frames. In case of a video file there is a *frame rate* specifying just how long is between two frames. While for the video cameras usually there is a limit of just how many frames they can digitalize per second, this property is less important as at any time the camera sees the current snapshot of the world. + +The first task you need to do is to assign to a :huivideo:`VideoCapture ` class its source. You can do this either via the :huivideo:`constructor ` or its :huivideo:`open ` function. If this argument is an integer then you will bind the class to a camera, a device. The number passed here is the ID of the device, assigned by the operating system. If you have a single camera attached to your system its ID will probably be zero and further ones increasing from there. If the parameter passed to these is a string it will refer to a video file, and the string points to the location and name of the file. For example, to the upper source code a valid command line is: + +.. code-block:: bash + + video/Megamind.avi video/Megamind_bug.avi 35 10 + +We do a similarity check. This requires a reference and a test case video file. The first two arguments refer to this. Here we use a relative address. This means that the application will look into its current working directory and open the video folder and try to find inside this the *Megamind.avi* and the *Megamind_bug.avi*. + +.. code-block:: cpp + + const string sourceReference = argv[1],sourceCompareWith = argv[2]; + + VideoCapture captRefrnc(sourceReference); + // or + VideoCapture captUndTst; + captUndTst.open(sourceCompareWith); + +To check if the binding of the class to a video source was successful or not use the :huivideo:`isOpened ` function: + +.. code-block:: cpp + + if ( !captRefrnc.isOpened()) + { + cout << "Could not open reference " << sourceReference << endl; + return -1; + } + +Closing the video is automatic when the objects destructor is called. However, if you want to close it before this you need to call its :huivideo:`release ` function. The frames of the video are just simple images. Therefore, we just need to extract them from the :huivideo:`VideoCapture ` object and put them inside a *Mat* one. The video streams are sequential. You may get the frames one after another by the :huivideo:`read ` or the overloaded >> operator: + +.. code-block:: cpp + + Mat frameReference, frameUnderTest; + captRefrnc >> frameReference; + captUndTst.open(frameUnderTest); + +The upper read operations will leave empty the *Mat* objects if no frame could be acquired (either cause the video stream was closed or you got to the end of the video file). We can check this with a simple if: + +.. code-block:: cpp + + if( frameReference.empty() || frameUnderTest.empty()) + { + // exit the program + } + +A read method is made of a frame grab and a decoding applied on that. You may call explicitly these two by using the :huivideo:`grab ` and then the :huivideo:`retrieve ` functions. + +Videos have many-many information attached to them besides the content of the frames. These are usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to this to acquire these information there is a general function named :huivideo:`get ` that returns double values containing these properties. Use bitwise operations to decode the characters from a double type and conversions where valid values are only integers. Its single argument is the ID of the queried property. For example, here we get the size of the frames in the reference and test case video file; plus the number of frames inside the reference. + +.. code-block:: cpp + + Size refS = Size((int) captRefrnc.get(CV_CAP_PROP_FRAME_WIDTH), + (int) captRefrnc.get(CV_CAP_PROP_FRAME_HEIGHT)), + + cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height + << " of nr#: " << captRefrnc.get(CV_CAP_PROP_FRAME_COUNT) << endl; + +When you are working with videos you may often want to control these values yourself. To do this there is a :huivideo:`set ` function. Its first argument remains the name of the property you want to change and there is a second of double type containing the value to be set. It will return true if it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time or frame: + +.. code-block:: cpp + + captRefrnc.set(CV_CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video + captRefrnc.set(CV_CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video + // now a read operation would read the frame at the set position + +For properties you can read and change look into the documentation of the :huivideo:`get ` and :huivideo:`set ` functions. + + +Image similarity - PSNR and SSIM +================================ + +We want to check just how imperceptible our video converting operation went, therefore we need a system to check frame by frame the similarity or differences. The most common algorithm used for this is the PSNR (aka **Peak signal-to-noise ratio**). The simplest definition of this starts out from the *mean squad error*. Let there be two images: I1 and I2; with a two dimensional size i and j, composed of c number of channels. + +.. math:: + + MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2} + +Then the PSNR is expressed as: + +.. math:: + + PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right) + +Here the :math:`MAX_I^2` is the maximum valid value for a pixel. In case of the simple single byte image per pixel per channel this is 255. When two images are the same the MSE will give zero, resulting in an invalid divide by zero operation in the PSNR formula. In this case the PSNR is undefined and as we'll need to handle this case separately. The transition to a logarithmic scale is made because the pixel values have a very wide dynamic range. All this translated to OpenCV and a C++ function looks like: + +.. code-block:: cpp + + double getPSNR(const Mat& I1, const Mat& I2) + { + Mat s1; + absdiff(I1, I2, s1); // |I1 - I2| + s1.convertTo(s1, CV_32F); // cannot make a square on 8 bits + s1 = s1.mul(s1); // |I1 - I2|^2 + + Scalar s = sum(s1); // sum elements per channel + + double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels + + if( sse <= 1e-10) // for small values return zero + return 0; + else + { + double mse =sse /(double)(I1.channels() * I1.total()); + double psnr = 10.0*log10((255*255)/mse); + return psnr; + } + } + +Typically result values are anywhere between 30 and 50 for video compression, where higher is better. If the images significantly differ you'll get much lower ones like 15 and so. This similarity check is easy and fast to calculate, however in practice it may turn out somewhat inconsistent with human eye perception. The **structural similarity** algorithm aims to correct this. + +Describing the methods goes well beyond the purpose of this tutorial. For that I invite you to read the article introducing it. Nevertheless, you can get a good image of it by looking at the OpenCV implementation below. + +.. seealso:: + + SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article. + +.. code-block:: cpp + + Scalar getMSSIM( const Mat& i1, const Mat& i2) + { + const double C1 = 6.5025, C2 = 58.5225; + /***************************** INITS **********************************/ + int d = CV_32F; + + Mat I1, I2; + i1.convertTo(I1, d); // cannot calculate on one byte large values + i2.convertTo(I2, d); + + Mat I2_2 = I2.mul(I2); // I2^2 + Mat I1_2 = I1.mul(I1); // I1^2 + Mat I1_I2 = I1.mul(I2); // I1 * I2 + + /***********************PRELIMINARY COMPUTING ******************************/ + + Mat mu1, mu2; // + GaussianBlur(I1, mu1, Size(11, 11), 1.5); + GaussianBlur(I2, mu2, Size(11, 11), 1.5); + + Mat mu1_2 = mu1.mul(mu1); + Mat mu2_2 = mu2.mul(mu2); + Mat mu1_mu2 = mu1.mul(mu2); + + Mat sigma1_2, sigma2_2, sigma12; + + GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5); + sigma1_2 -= mu1_2; + + GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5); + sigma2_2 -= mu2_2; + + GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5); + sigma12 -= mu1_mu2; + + ///////////////////////////////// FORMULA //////////////////////////////// + Mat t1, t2, t3; + + t1 = 2 * mu1_mu2 + C1; + t2 = 2 * sigma12 + C2; + t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2)) + + t1 = mu1_2 + mu2_2 + C1; + t2 = sigma1_2 + sigma2_2 + C2; + t1 = t1.mul(t2); // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2)) + + Mat ssim_map; + divide(t3, t1, ssim_map); // ssim_map = t3./t1; + + Scalar mssim = mean( ssim_map ); // mssim = average of ssim map + return mssim; + } + +This will return a similarity index for each channel of the image. This value is between zero and one, where one corresponds to perfect fit. Unfortunately, the many Gaussian blurring is quite costly, so while the PSNR may work in a real time like environment (24 frame per second) this will take significantly more than to accomplish similar performance results. + +Therefore, the source code presented at the start of the tutorial will perform the PSNR measurement for each frame, and the SSIM only for the frames where the PSNR falls below an input value. For visualization purpose we show both images in an OpenCV window and print the PSNR and MSSIM values to the console. Expect to see something like: + +.. image:: images/outputVideoInput.png + :alt: A sample output + :align: center + +You may observe a runtime instance of this on the `YouTube here `_. + +.. raw:: html + +
+ +
diff --git a/doc/tutorials/images/calib3d.jpg b/doc/tutorials/images/calib3d.jpg new file mode 100644 index 0000000000..c5226a9a1d Binary files /dev/null and b/doc/tutorials/images/calib3d.jpg differ diff --git a/doc/tutorials/images/calib3d.png b/doc/tutorials/images/calib3d.png deleted file mode 100644 index 89c84a8bdf..0000000000 Binary files a/doc/tutorials/images/calib3d.png and /dev/null differ diff --git a/doc/tutorials/images/core.jpg b/doc/tutorials/images/core.jpg new file mode 100644 index 0000000000..6fe819bd52 Binary files /dev/null and b/doc/tutorials/images/core.jpg differ diff --git a/doc/tutorials/images/core.png b/doc/tutorials/images/core.png deleted file mode 100644 index 9e43df01ff..0000000000 Binary files a/doc/tutorials/images/core.png and /dev/null differ diff --git a/doc/tutorials/images/feature2D.jpg b/doc/tutorials/images/feature2D.jpg new file mode 100644 index 0000000000..6744de0610 Binary files /dev/null and b/doc/tutorials/images/feature2D.jpg differ diff --git a/doc/tutorials/images/feature2D.png b/doc/tutorials/images/feature2D.png deleted file mode 100644 index 429b493b0a..0000000000 Binary files a/doc/tutorials/images/feature2D.png and /dev/null differ diff --git a/doc/tutorials/images/general.jpg b/doc/tutorials/images/general.jpg new file mode 100644 index 0000000000..95829d9c64 Binary files /dev/null and b/doc/tutorials/images/general.jpg differ diff --git a/doc/tutorials/images/general.png b/doc/tutorials/images/general.png deleted file mode 100644 index 1910b7aff6..0000000000 Binary files a/doc/tutorials/images/general.png and /dev/null differ diff --git a/doc/tutorials/images/gpu.jpg b/doc/tutorials/images/gpu.jpg new file mode 100644 index 0000000000..4cc053895c Binary files /dev/null and b/doc/tutorials/images/gpu.jpg differ diff --git a/doc/tutorials/images/gpu.png b/doc/tutorials/images/gpu.png deleted file mode 100644 index 0ad228439f..0000000000 Binary files a/doc/tutorials/images/gpu.png and /dev/null differ diff --git a/doc/tutorials/images/highgui.jpg b/doc/tutorials/images/highgui.jpg new file mode 100644 index 0000000000..ada65fcb03 Binary files /dev/null and b/doc/tutorials/images/highgui.jpg differ diff --git a/doc/tutorials/images/highgui.png b/doc/tutorials/images/highgui.png deleted file mode 100644 index 9dcf3446f8..0000000000 Binary files a/doc/tutorials/images/highgui.png and /dev/null differ diff --git a/doc/tutorials/images/imgproc.jpg b/doc/tutorials/images/imgproc.jpg new file mode 100644 index 0000000000..ad7dafb0b7 Binary files /dev/null and b/doc/tutorials/images/imgproc.jpg differ diff --git a/doc/tutorials/images/imgproc.png b/doc/tutorials/images/imgproc.png deleted file mode 100644 index 598a2c8952..0000000000 Binary files a/doc/tutorials/images/imgproc.png and /dev/null differ diff --git a/doc/tutorials/images/introduction.jpg b/doc/tutorials/images/introduction.jpg new file mode 100644 index 0000000000..19a9284785 Binary files /dev/null and b/doc/tutorials/images/introduction.jpg differ diff --git a/doc/tutorials/images/introduction.png b/doc/tutorials/images/introduction.png deleted file mode 100644 index 6fcc6a5883..0000000000 Binary files a/doc/tutorials/images/introduction.png and /dev/null differ diff --git a/doc/tutorials/images/ml.jpg b/doc/tutorials/images/ml.jpg new file mode 100644 index 0000000000..40acfcfbfd Binary files /dev/null and b/doc/tutorials/images/ml.jpg differ diff --git a/doc/tutorials/images/ml.png b/doc/tutorials/images/ml.png deleted file mode 100644 index d99497f2f1..0000000000 Binary files a/doc/tutorials/images/ml.png and /dev/null differ diff --git a/doc/tutorials/images/objdetect.jpg b/doc/tutorials/images/objdetect.jpg new file mode 100644 index 0000000000..c811f348f5 Binary files /dev/null and b/doc/tutorials/images/objdetect.jpg differ diff --git a/doc/tutorials/images/objdetect.png b/doc/tutorials/images/objdetect.png deleted file mode 100644 index 03112694e3..0000000000 Binary files a/doc/tutorials/images/objdetect.png and /dev/null differ diff --git a/doc/tutorials/images/video.jpg b/doc/tutorials/images/video.jpg new file mode 100644 index 0000000000..dd5d0c4ed2 Binary files /dev/null and b/doc/tutorials/images/video.jpg differ diff --git a/doc/tutorials/images/video.png b/doc/tutorials/images/video.png deleted file mode 100644 index 69a925f31e..0000000000 Binary files a/doc/tutorials/images/video.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst index aa7b7b30bd..601abb893b 100644 --- a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst +++ b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst @@ -36,7 +36,6 @@ Morphological Operations .. image:: images/Morphology_1_Tutorial_Theory_Original_Image.png :alt: Original image - :height: 100px :align: center Dilation @@ -50,7 +49,6 @@ Dilation .. image:: images/Morphology_1_Tutorial_Theory_Dilation.png :alt: Dilation result - Theory example - :height: 100px :align: center The background (bright) dilates around the black regions of the letter. @@ -66,7 +64,6 @@ Erosion .. image:: images/Morphology_1_Tutorial_Theory_Erosion.png :alt: Erosion result - Theory example - :height: 100px :align: center @@ -266,15 +263,12 @@ Results * Compile the code above and execute it with an image as argument. For instance, using this image: - .. image:: images/Morphology_1_Tutorial_Original_Image.png + .. image:: images/Morphology_1_Tutorial_Original_Image.jpg :alt: Original image - :height: 200px :align: center We get the results below. Varying the indices in the Trackbars give different output images, naturally. Try them out! You can even try to add a third Trackbar to control the number of iterations. - .. image:: images/Morphology_1_Tutorial_Cover.png + .. image:: images/Morphology_1_Tutorial_Cover.jpg :alt: Dilation and Erosion application - :height: 400px - :align: center - + :align: center \ No newline at end of file diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.jpg b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.jpg new file mode 100644 index 0000000000..64de099f70 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.png deleted file mode 100644 index 90e8c22c96..0000000000 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.jpg b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.jpg new file mode 100644 index 0000000000..f5dcfcca0f Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.jpg differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.png deleted file mode 100644 index 9c86e5fc9e..0000000000 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Dilation_Result.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.jpg b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.jpg new file mode 100644 index 0000000000..bda78a60e7 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.jpg differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.png deleted file mode 100644 index 501f7f84b1..0000000000 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Erosion_Result.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..5b61a95527 Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.png deleted file mode 100644 index fafe56c249..0000000000 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Original_Image.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png index 475d9c72b6..dae930ec1e 100644 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png index da734dfb13..755561023f 100644 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png index ed04720860..d7e8a9a429 100644 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png differ diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst index 6fc7012979..ef8500880b 100644 --- a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst +++ b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst @@ -6,77 +6,82 @@ Smoothing Images Goal ===== -In this tutorial you will learn how to: +In this tutorial you will learn how to apply diverse linear filters to smooth images using OpenCV functions such as: -* Apply diverse linear filters to smooth images using OpenCV functions such as: +.. container:: enumeratevisibleitemswithsquare - * :blur:`blur <>` - * :gaussian_blur:`GaussianBlur <>` - * :median_blur:`medianBlur <>` - * :bilateral_filter:`bilateralFilter <>` + * :blur:`blur <>` + * :gaussian_blur:`GaussianBlur <>` + * :median_blur:`medianBlur <>` + * :bilateral_filter:`bilateralFilter <>` -Cool Theory -============ +Theory +====== .. note:: The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski and to *LearningOpenCV* -* *Smoothing*, also called *blurring*, is a simple and frequently used image processing operation. +.. container:: enumeratevisibleitemswithsquare -* There are many reasons for smoothing. In this tutorial we will focus on smoothing in order to reduce noise (other uses will be seen in the following tutorials). + * *Smoothing*, also called *blurring*, is a simple and frequently used image processing operation. -* To perform a smoothing operation we will apply a *filter* to our image. The most common type of filters are *linear*, in which an output pixel's value (i.e. :math:`g(i,j)`) is determined as a weighted sum of input pixel values (i.e. :math:`f(i+k,j+l)`) : + * There are many reasons for smoothing. In this tutorial we will focus on smoothing in order to reduce noise (other uses will be seen in the following tutorials). - .. math:: - g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l) + * To perform a smoothing operation we will apply a *filter* to our image. The most common type of filters are *linear*, in which an output pixel's value (i.e. :math:`g(i,j)`) is determined as a weighted sum of input pixel values (i.e. :math:`f(i+k,j+l)`) : - :math:`h(k,l)` is called the *kernel*, which is nothing more than the coefficients of the filter. + .. math:: + g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l) + + :math:`h(k,l)` is called the *kernel*, which is nothing more than the coefficients of the filter. - It helps to visualize a *filter* as a window of coefficients sliding across the image. + It helps to visualize a *filter* as a window of coefficients sliding across the image. -* There are many kind of filters, here we will mention the most used: + * There are many kind of filters, here we will mention the most used: Normalized Box Filter ----------------------- -* This filter is the simplest of all! Each output pixel is the *mean* of its kernel neighbors ( all of them contribute with equal weights) +.. container:: enumeratevisibleitemswithsquare -* Just in case, the kernel is below: + * This filter is the simplest of all! Each output pixel is the *mean* of its kernel neighbors ( all of them contribute with equal weights) -.. math:: + * The kernel is below: + + .. math:: - K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix} - 1 & 1 & 1 & ... & 1 \\ - 1 & 1 & 1 & ... & 1 \\ - . & . & . & ... & 1 \\ - . & . & . & ... & 1 \\ - 1 & 1 & 1 & ... & 1 - \end{bmatrix} + K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix} + 1 & 1 & 1 & ... & 1 \\ + 1 & 1 & 1 & ... & 1 \\ + . & . & . & ... & 1 \\ + . & . & . & ... & 1 \\ + 1 & 1 & 1 & ... & 1 + \end{bmatrix} Gaussian Filter --------------- -* Probably the most useful filter (although not the fastest). Gaussian filtering is done by convolving each point in the input array with a *Gaussian kernel* and then summing them all to produce the output array. -* Just to make the picture clearer, remember how a 1D Gaussian kernel look like? +.. container:: enumeratevisibleitemswithsquare - .. image:: images/Smoothing_Tutorial_theory_gaussian_0.jpg - :height: 200px - :align: center + * Probably the most useful filter (although not the fastest). Gaussian filtering is done by convolving each point in the input array with a *Gaussian kernel* and then summing them all to produce the output array. - Assuming that an image is 1D, you can notice that the pixel located in the middle would have the biggest weight. The weight of its neighbors decreases as the spatial distance between them and the center pixel increases. + * Just to make the picture clearer, remember how a 1D Gaussian kernel look like? + + .. image:: images/Smoothing_Tutorial_theory_gaussian_0.jpg + :align: center + + Assuming that an image is 1D, you can notice that the pixel located in the middle would have the biggest weight. The weight of its neighbors decreases as the spatial distance between them and the center pixel increases. .. note:: - * Remember that a 2D Gaussian can be represented as : + Remember that a 2D Gaussian can be represented as : - .. math:: + .. math:: - G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } - - where :math:`\mu` is the mean (the peak) and :math:`\sigma` represents the variance (per each of the variables :math:`x` and :math:`y`) + G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } + where :math:`\mu` is the mean (the peak) and :math:`\sigma` represents the variance (per each of the variables :math:`x` and :math:`y`) Median Filter @@ -88,19 +93,32 @@ The median filter run through each element of the signal (in this case the image Bilateral Filter ----------------- -* So far, we have explained some filters which main goal is to *smooth* an input image. However, sometimes the filters do not only dissolve the noise, but also smooth away the *edges*. To avoid this (at certain extent at least), we can use a bilateral filter. +.. container:: enumeratevisibleitemswithsquare -* In an analogous way as the Gaussian filter, the bilateral filter also considers the neighboring pixels with weights assigned to each of them. These weights have two components, the first of which is the same weighting used by the Gaussian filter. The second component takes into account the difference in intensity between the neighboring pixels and the evaluated one. - -* For a more detailed explanation you can check `this link `_ + * So far, we have explained some filters which main goal is to *smooth* an input image. However, sometimes the filters do not only dissolve the noise, but also smooth away the *edges*. To avoid this (at certain extent at least), we can use a bilateral filter. + * In an analogous way as the Gaussian filter, the bilateral filter also considers the neighboring pixels with weights assigned to each of them. These weights have two components, the first of which is the same weighting used by the Gaussian filter. The second component takes into account the difference in intensity between the neighboring pixels and the evaluated one. + * For a more detailed explanation you can check `this link `_ Code ====== -This tutorial code's is shown lines below. You can also download it from `here `_ +.. container:: enumeratevisibleitemswithsquare + + * **What does this program do?** + + .. container:: enumeratevisibleitemswithsquare + + * Loads an image + * Applies 4 different kinds of filters (explained in Theory) and show the filtered images sequentially + + * **Downloadable code**: + Click `here `_ + + * **Code at glance:** + .. code-block:: cpp @@ -130,7 +148,7 @@ This tutorial code's is shown lines below. You can also download it from `here < namedWindow( window_name, CV_WINDOW_AUTOSIZE ); /// Load the source image - src = imread( "../images/lena.png", 1 ); + src = imread( "../images/lena.jpg", 1 ); if( display_caption( "Original Image" ) != 0 ) { return 0; } @@ -198,7 +216,7 @@ This tutorial code's is shown lines below. You can also download it from `here < Explanation ============= -#. Let's check the OpenCV functions that involve only the smoothing procedure, since the rest is already known by now. +#. Let's check the OpenCV functions that involve only the smoothing procedure, since the rest is already known by now. #. **Normalized Block Filter:** @@ -213,13 +231,15 @@ Explanation We specify 4 arguments (more details, check the Reference): - * *src*: Source image + .. container:: enumeratevisibleitemswithsquare - * *dst*: Destination image + + *src*: Source image - * *Size( w,h )*: Defines the size of the kernel to be used ( of width *w* pixels and height *h* pixels) + + *dst*: Destination image - * *Point(-1, -1)*: Indicates where the anchor point (the pixel evaluated) is located with respect to the neighborhood. If there is a negative value, then the center of the kernel is considered the anchor point. + + *Size( w,h )*: Defines the size of the kernel to be used ( of width *w* pixels and height *h* pixels) + + + *Point(-1, -1)*: Indicates where the anchor point (the pixel evaluated) is located with respect to the neighborhood. If there is a negative value, then the center of the kernel is considered the anchor point. #. **Gaussian Filter:** @@ -233,15 +253,17 @@ Explanation Here we use 4 arguments (more details, check the OpenCV reference): - * *src*: Source image + .. container:: enumeratevisibleitemswithsquare - * *dst*: Destination image + + *src*: Source image - * *Size(w, h)*: The size of the kernel to be used (the neighbors to be considered). :math:`w` and :math:`h` have to be odd and positive numbers otherwise thi size will be calculated using the :math:`\sigma_{x}` and :math:`\sigma_{y}` arguments. + + *dst*: Destination image - * :math:`\sigma_{x}`: The standard deviation in x. Writing :math:`0` implies that :math:`\sigma_{x}` is calculated using kernel size. + + *Size(w, h)*: The size of the kernel to be used (the neighbors to be considered). :math:`w` and :math:`h` have to be odd and positive numbers otherwise thi size will be calculated using the :math:`\sigma_{x}` and :math:`\sigma_{y}` arguments. + + + :math:`\sigma_{x}`: The standard deviation in x. Writing :math:`0` implies that :math:`\sigma_{x}` is calculated using kernel size. - * :math:`\sigma_{y}`: The standard deviation in y. Writing :math:`0` implies that :math:`\sigma_{y}` is calculated using kernel size. + + :math:`\sigma_{y}`: The standard deviation in y. Writing :math:`0` implies that :math:`\sigma_{y}` is calculated using kernel size. #. **Median Filter:** @@ -256,11 +278,13 @@ Explanation We use three arguments: - * *src*: Source image + .. container:: enumeratevisibleitemswithsquare - * *dst*: Destination image, must be the same type as *src* + + *src*: Source image + + + *dst*: Destination image, must be the same type as *src* - * *i*: Size of the kernel (only one because we use a square window). Must be odd. + + *i*: Size of the kernel (only one because we use a square window). Must be odd. #. **Bilateral Filter** @@ -275,24 +299,28 @@ Explanation We use 5 arguments: - * *src*: Source image + .. container:: enumeratevisibleitemswithsquare - * *dst*: Destination image + + *src*: Source image - * *d*: The diameter of each pixel neighborhood. + + *dst*: Destination image + + + *d*: The diameter of each pixel neighborhood. - * :math:`\sigma_{Color}`: Standard deviation in the color space. + + :math:`\sigma_{Color}`: Standard deviation in the color space. - * :math:`\sigma_{Space}`: Standard deviation in the coordinate space (in pixel terms) + + :math:`\sigma_{Space}`: Standard deviation in the coordinate space (in pixel terms) Results ======== -* The code opens an image (in this case *lena.png*) and display it under the effects of the 4 filters explained. +.. container:: enumeratevisibleitemswithsquare -* Here is a snapshot of the image smoothed using *medianBlur*: + * The code opens an image (in this case *lena.jpg*) and display it under the effects of the 4 filters explained. - .. image:: images/Smoothing_Tutorial_Result_Median_Filter.png - :alt: Smoothing with a median filter - :align: center + * Here is a snapshot of the image smoothed using *medianBlur*: + + .. image:: images/Smoothing_Tutorial_Result_Median_Filter.jpg + :alt: Smoothing with a median filter + :align: center diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Cover.png b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Cover.png deleted file mode 100644 index 45406171bf..0000000000 Binary files a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.jpg b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.jpg new file mode 100644 index 0000000000..da5f1bac00 Binary files /dev/null and b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.jpg differ diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.png b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.png deleted file mode 100644 index b8cf7ca224..0000000000 Binary files a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/images/Smoothing_Tutorial_Result_Median_Filter.png and /dev/null differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/back_projection.rst b/doc/tutorials/imgproc/histograms/back_projection/back_projection.rst new file mode 100644 index 0000000000..f6512f6c29 --- /dev/null +++ b/doc/tutorials/imgproc/histograms/back_projection/back_projection.rst @@ -0,0 +1,305 @@ +.. _back_projection: + +Back Projection +**************** + + +Goal +==== + +In this tutorial you will learn: + +.. container:: enumeratevisibleitemswithsquare + + * What is Back Projection and why it is useful + + * How to use the OpenCV function :calc_back_project:`calcBackProject <>` to calculate Back Projection + + * How to mix different channels of an image by using the OpenCV function :mix_channels:`mixChannels <>` + + +Theory +====== + +What is Back Projection? +--------------------------- + +.. container:: enumeratevisibleitemswithsquare + + * Back Projection is a way of recording how well the pixels of a given image fit the distribution of pixels in a histogram model. + + * To make it simpler: For Back Projection, you calculate the histogram model of a feature and then use it to find this feature in an image. + + * Application example: If you have a histogram of flesh color (say, a Hue-Saturation histogram ), then you can use it to find flesh color areas in an image: + + +How does it work? +------------------ + +.. container:: enumeratevisibleitemswithsquare + + * We explain this by using the skin example: + + * Let's say you have gotten a skin histogram (Hue-Saturation) based on the image below. The histogram besides is going to be our *model histogram* (which we know represents a sample of skin tonality). You applied some mask to capture only the histogram of the skin area: + + ====== ====== + |T0| |T1| + ====== ====== + + .. |T0| image:: images/Back_Projection_Theory0.jpg + :align: middle + + .. |T1| image:: images/Back_Projection_Theory1.jpg + :align: middle + + + * Now, let's imagine that you get another hand image (Test Image) like the one below: (with its respective histogram): + + ====== ====== + |T2| |T3| + ====== ====== + + .. |T2| image:: images/Back_Projection_Theory2.jpg + :align: middle + + .. |T3| image:: images/Back_Projection_Theory3.jpg + :align: middle + + + * What we want to do is to use our *model histogram* (that we know represents a skin tonality) to detect skin areas in our Test Image. Here are the steps + + a. In each pixel of our Test Image (i.e. :math:`p(i,j)` ), collect the data and find the correspondent bin location for that pixel (i.e. :math:`( h_{i,j}, s_{i,j} )` ). + + b. Lookup the *model histogram* in the correspondent bin - :math:`( h_{i,j}, s_{i,j} )` - and read the bin value. + + c. Store this bin value in a new image (*BackProjection*). Also, you may consider to normalize the *model histogram* first, so the output for the Test Image can be visible for you. + + d. Applying the steps above, we get the following BackProjection image for our Test Image: + + .. image:: images/Back_Projection_Theory4.jpg + :align: center + + e. In terms of statistics, the values stored in *BackProjection* represent the *probability* that a pixel in *Test Image* belongs to a skin area, based on the *model histogram* that we use. For instance in our Test image, the brighter areas are more probable to be skin area (as they actually are), whereas the darker areas have less probability (notice that these "dark" areas belong to surfaces that have some shadow on it, which in turns affects the detection). + + +Code +==== + +.. container:: enumeratevisibleitemswithsquare + + * **What does this program do?** + + .. container:: enumeratevisibleitemswithsquare + + * Loads an image + * Convert the original to HSV format and separate only *Hue* channel to be used for the Histogram (using the OpenCV function :mix_channels:`mixChannels <>`) + * Let the user to enter the number of bins to be used in the calculation of the histogram. + * Calculate the histogram (and update it if the bins change) and the backprojection of the same image. + * Display the backprojection and the histogram in windows. + + * **Downloadable code**: + + a. Click `here `_ for the basic version (explained in this tutorial). + b. For stuff slightly fancier (using H-S histograms and floodFill to define a mask for the skin area) you can check the `improved demo `_ + c. ...or you can always check out the classical `camshiftdemo `_ in samples. + + * **Code at glance:** + +.. code-block:: cpp + + #include "opencv2/imgproc/imgproc.hpp" + #include "opencv2/highgui/highgui.hpp" + + #include + + using namespace cv; + using namespace std; + + /// Global Variables + Mat src; Mat hsv; Mat hue; + int bins = 25; + + /// Function Headers + void Hist_and_Backproj(int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Read the image + src = imread( argv[1], 1 ); + /// Transform it to HSV + cvtColor( src, hsv, CV_BGR2HSV ); + + /// Use only the Hue value + hue.create( hsv.size(), hsv.depth() ); + int ch[] = { 0, 0 }; + mixChannels( &hsv, 1, &hue, 1, ch, 1 ); + + /// Create Trackbar to enter the number of bins + char* window_image = "Source image"; + namedWindow( window_image, CV_WINDOW_AUTOSIZE ); + createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj ); + Hist_and_Backproj(0, 0); + + /// Show the image + imshow( window_image, src ); + + /// Wait until user exits the program + waitKey(0); + return 0; + } + + + /** + * @function Hist_and_Backproj + * @brief Callback to Trackbar + */ + void Hist_and_Backproj(int, void* ) + { + MatND hist; + int histSize = MAX( bins, 2 ); + float hue_range[] = { 0, 180 }; + const float* ranges = { hue_range }; + + /// Get the Histogram and normalize it + calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false ); + normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() ); + + /// Get Backprojection + MatND backproj; + calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true ); + + /// Draw the backproj + imshow( "BackProj", backproj ); + + /// Draw the histogram + int w = 400; int h = 400; + int bin_w = cvRound( (double) w / histSize ); + Mat histImg = Mat::zeros( w, h, CV_8UC3 ); + + for( int i = 0; i < bins; i ++ ) + { rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at(i)*h/255.0 ) ), Scalar( 0, 0, 255 ), -1 ); } + + imshow( "Histogram", histImg ); + } + +Explanation +=========== + +#. Declare the matrices to store our images and initialize the number of bins to be used by our histogram: + + .. code-block:: cpp + + Mat src; Mat hsv; Mat hue; + int bins = 25; + +#. Read the input image and transform it to HSV format: + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + cvtColor( src, hsv, CV_BGR2HSV ); + +#. For this tutorial, we will use only the Hue value for our 1-D histogram (check out the fancier code in the links above if you want to use the more standard H-S histogram, which yields better results): + + .. code-block:: cpp + + hue.create( hsv.size(), hsv.depth() ); + int ch[] = { 0, 0 }; + mixChannels( &hsv, 1, &hue, 1, ch, 1 ); + + as you see, we use the function :mix_channels:`mixChannels` to get only the channel 0 (Hue) from the hsv image. It gets the following parameters: + + .. container:: enumeratevisibleitemswithsquare + + + **&hsv:** The source array from which the channels will be copied + + **1:** The number of source arrays + + **&hue:** The destination array of the copied channels + + **1:** The number of destination arrays + + **ch[] = {0,0}:** The array of index pairs indicating how the channels are copied. In this case, the Hue(0) channel of &hsv is being copied to the 0 channel of &hue (1-channel) + + **1:** Number of index pairs + +#. Create a Trackbar for the user to enter the bin values. Any change on the Trackbar means a call to the **Hist_and_Backproj** callback function. + + .. code-block:: cpp + + char* window_image = "Source image"; + namedWindow( window_image, CV_WINDOW_AUTOSIZE ); + createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj ); + Hist_and_Backproj(0, 0); + +#. Show the image and wait for the user to exit the program: + + .. code-block:: cpp + + imshow( window_image, src ); + + waitKey(0); + return 0; + +#. **Hist_and_Backproj function:** Initialize the arguments needed for :calc_hist:`calcHist <>`. The number of bins comes from the Trackbar: + + + .. code-block:: cpp + + void Hist_and_Backproj(int, void* ) + { + MatND hist; + int histSize = MAX( bins, 2 ); + float hue_range[] = { 0, 180 }; + const float* ranges = { hue_range }; + +#. Calculate the Histogram and normalize it to the range :math:`[0,255]` + + .. code-block:: cpp + + calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false ); + normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() ); + +#. Get the Backprojection of the same image by calling the function :calc_back_project:`calcBackProject <>` + + .. code-block:: cpp + + MatND backproj; + calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true ); + + all the arguments are known (the same as used to calculate the histogram), only we add the backproj matrix, which will store the backprojection of the source image (&hue) + +#. Display backproj: + + .. code-block:: cpp + + imshow( "BackProj", backproj ); + +#. Draw the 1-D Hue histogram of the image: + + .. code-block:: cpp + + int w = 400; int h = 400; + int bin_w = cvRound( (double) w / histSize ); + Mat histImg = Mat::zeros( w, h, CV_8UC3 ); + + for( int i = 0; i < bins; i ++ ) + { rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at(i)*h/255.0 ) ), Scalar( 0, 0, 255 ), -1 ); } + + imshow( "Histogram", histImg ); + + + +Results +======= + +#. Here are the output by using a sample image ( guess what? Another hand ). You can play with the bin values and you will observe how it affects the results: + + ====== ====== ====== + |R0| |R1| |R2| + ====== ====== ====== + + .. |R0| image:: images/Back_Projection1_Source_Image.jpg + :align: middle + + .. |R1| image:: images/Back_Projection1_Histogram.jpg + :align: middle + + .. |R2| image:: images/Back_Projection1_BackProj.jpg + :align: middle diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_BackProj.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_BackProj.jpg new file mode 100644 index 0000000000..baf9cc28ec Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_BackProj.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_Histogram.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_Histogram.jpg new file mode 100644 index 0000000000..b2d6a2dfbe Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_Histogram.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_Source_Image.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_Source_Image.jpg new file mode 100644 index 0000000000..21ed375fcf Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection1_Source_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_BackProj.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_BackProj.jpg new file mode 100644 index 0000000000..5f3824ccfb Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_BackProj.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_Mask.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_Mask.jpg new file mode 100644 index 0000000000..38cd4c8251 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_Mask.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_Source_Image.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_Source_Image.jpg new file mode 100644 index 0000000000..0c5c6f91d1 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection2_Source_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory0.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory0.jpg new file mode 100644 index 0000000000..8d0ac9e4ab Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory0.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory1.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory1.jpg new file mode 100644 index 0000000000..4107e5e976 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory1.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory2.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory2.jpg new file mode 100644 index 0000000000..5f2b2f23dd Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory2.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory3.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory3.jpg new file mode 100644 index 0000000000..cca1e81fda Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory3.jpg differ diff --git a/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory4.jpg b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory4.jpg new file mode 100644 index 0000000000..55ca013ba7 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/back_projection/images/Back_Projection_Theory4.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.rst b/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.rst new file mode 100644 index 0000000000..e8eb67f214 --- /dev/null +++ b/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.rst @@ -0,0 +1,331 @@ +.. _histogram_calculation: + +Histogram Calculation +********************* + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :split:`split <>` to divide an image into its correspondent planes. + + * To calculate histograms of arrays of images by using the OpenCV function :calc_hist:`calcHist <>` + + * To normalize an array by using the function :normalize:`normalize <>` + + +.. note:: + In the last tutorial (:ref:`histogram_equalization`) we talked about a particular kind of histogram called *Image histogram*. Now we will considerate it in its more general concept. Read on! + + +What are histograms? +-------------------- + +.. container:: enumeratevisibleitemswithsquare + + * Histograms are collected *counts* of data organized into a set of predefined *bins* + + * When we say *data* we are not restricting it to be intensity values (as we saw in the previous Tutorial). The data collected can be whatever feature you find useful to describe your image. + + * Let's see an example. Imagine that a Matrix contains information of an image (i.e. intensity in the range :math:`0-255`): + + + .. image:: images/Histogram_Calculation_Theory_Hist0.jpg + :align: center + + * What happens if we want to *count* this data in an organized way? Since we know that the *range* of information value for this case is 256 values, we can segment our range in subparts (called **bins**) like: + + .. math:: + \begin{array}{l} + [0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\ + range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} } + \end{array} + + and we can keep count of the number of pixels that fall in the range of each :math:`bin_{i}`. Applying this to the example above we get the image below ( axis x represents the bins and axis y the number of pixels in each of them). + + + .. image:: images/Histogram_Calculation_Theory_Hist1.jpg + :align: center + + * This was just a simple example of how an histogram works and why it is useful. An histogram can keep count not only of color intensities, but of whatever image features that we want to measure (i.e. gradients, directions, etc). + + * Let's identify some parts of the histogram: + + a. **dims**: The number of parameters you want to collect data of. In our example, **dims = 1** because we are only counting the intensity values of each pixel (in a greyscale image). + b. **bins**: It is the number of **subdivisions** in each dim. In our example, **bins = 16** + c. **range**: The limits for the values to be measured. In this case: **range = [0,255]** + + * What if you want to count two features? In this case your resulting histogram would be a 3D plot (in which x and y would be :math:`bin_{x}` and :math:`bin_{y}` for each feature and z would be the number of counts for each combination of :math:`(bin_{x}, bin_{y})`. The same would apply for more features (of course it gets trickier). + + +What OpenCV offers you +----------------------- + +For simple purposes, OpenCV implements the function :calc_hist:`calcHist <>`, which calculates the histogram of a set of arrays (usually images or image planes). It can operate with up to 32 dimensions. We will see it in the code below! + + +Code +==== + +.. container:: enumeratevisibleitemswithsquare + + * **What does this program do?** + + .. container:: enumeratevisibleitemswithsquare + + * Loads an image + * Splits the image into its R, G and B planes using the function :split:`split <>` + * Calculate the Histogram of each 1-channel plane by calling the function :calc_hist:`calcHist <>` + * Plot the three histograms in a window + + * **Downloadable code**: + Click `here `_ + + * **Code at glance:** + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace std; + using namespace cv; + + /** @function main */ + int main( int argc, char** argv ) + { + Mat src, dst; + + /// Load image + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + + /// Separate the image in 3 places ( R, G and B ) + vector rgb_planes; + split( src, rgb_planes ); + + /// Establish the number of bins + int histSize = 255; + + /// Set the ranges ( for R,G,B) ) + float range[] = { 0, 255 } ; + const float* histRange = { range }; + + bool uniform = true; bool accumulate = false; + + Mat r_hist, g_hist, b_hist; + + /// Compute the histograms: + calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); + calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate ); + calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate ); + + // Draw the histograms for R, G and B + int hist_w = 400; int hist_h = 400; + int bin_w = cvRound( (double) hist_w/histSize ); + + Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) ); + + /// Normalize the result to [ 0, histImage.rows ] + normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); + normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); + normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); + + /// Draw for each channel + for( int i = 1; i < histSize; i++ ) + { + line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) , + Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ), + Scalar( 0, 0, 255), 2, 8, 0 ); + line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) , + Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ), + Scalar( 0, 255, 0), 2, 8, 0 ); + line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) , + Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ), + Scalar( 255, 0, 0), 2, 8, 0 ); + } + + /// Display + namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE ); + imshow("calcHist Demo", histImage ); + + waitKey(0); + + return 0; + + } + +Explanation +=========== + +#. Create the necessary matrices: + + .. code-block:: cpp + + Mat src, dst; + +#. Load the source image + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + +#. Separate the source image in its three R,G and B planes. For this we use the OpenCV function :split:`split <>`: + + .. code-block:: cpp + + vector rgb_planes; + split( src, rgb_planes ); + + our input is the image to be divided (this case with three channels) and the output is a vector of Mat ) + +#. Now we are ready to start configuring the **histograms** for each plane. Since we are working with the R, G and B planes, we know that our values will range in the interval :math:`[0,255]` + + a. Establish number of bins (5, 10...): + + .. code-block:: cpp + + int histSize = 255; + + b. Set the range of values (as we said, between 0 and 255 ) + + .. code-block:: cpp + + /// Set the ranges ( for R,G,B) ) + float range[] = { 0, 255 } ; + const float* histRange = { range }; + + c. We want our bins to have the same size (uniform) and to clear the histograms in the beginning, so: + + .. code-block:: cpp + + bool uniform = true; bool accumulate = false; + + d. Finally, we create the Mat objects to save our histograms. Creating 3 (one for each plane): + + .. code-block:: cpp + + Mat r_hist, g_hist, b_hist; + + e. We proceed to calculate the histograms by using the OpenCV function :calc_hist:`calcHist <>`: + + .. code-block:: cpp + + /// Compute the histograms: + calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); + calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate ); + calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate ); + + where the arguments are: + + .. container:: enumeratevisibleitemswithsquare + + + **&rgb_planes[0]:** The source array(s) + + **1**: The number of source arrays (in this case we are using 1. We can enter here also a list of arrays ) + + **0**: The channel (*dim*) to be measured. In this case it is just the intensity (each array is single-channel) so we just write 0. + + **Mat()**: A mask to be used on the source array ( zeros indicating pixels to be ignored ). If not defined it is not used + + **r_hist**: The Mat object where the histogram will be stored + + **1**: The histogram dimensionality. + + **histSize:** The number of bins per each used dimension + + **histRange:** The range of values to be measured per each dimension + + **uniform** and **accumulate**: The bin sizes are the same and the histogram is cleared at the beginning. + + +#. Create an image to display the histograms: + + .. code-block:: cpp + + // Draw the histograms for R, G and B + int hist_w = 400; int hist_h = 400; + int bin_w = cvRound( (double) hist_w/histSize ); + + Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) ); + +#. Notice that before drawing, we first :normalize:`normalize <>` the histogram so its values fall in the range indicated by the parameters entered: + + .. code-block:: cpp + + /// Normalize the result to [ 0, histImage.rows ] + normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); + normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); + normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); + + this function receives these arguments: + + .. container:: enumeratevisibleitemswithsquare + + + **r_hist:** Input array + + **r_hist:** Output normalized array (can be the same) + + **0** and**histImage.rows**: For this example, they are the lower and upper limits to normalize the values of **r_hist** + + **NORM_MINMAX:** Argument that indicates the type of normalization (as described above, it adjusts the values between the two limits set before) + + **-1:** Implies that the output normalized array will be the same type as the input + + **Mat():** Optional mask + +#. Finally, observe that to access the bin (in this case in this 1D-Histogram): + + .. code-block:: cpp + + /// Draw for each channel + for( int i = 1; i < histSize; i++ ) + { + line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) , + Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ), + Scalar( 0, 0, 255), 2, 8, 0 ); + line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) , + Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ), + Scalar( 0, 255, 0), 2, 8, 0 ); + line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) , + Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ), + Scalar( 255, 0, 0), 2, 8, 0 ); + } + + + we use the expression: + + .. code-block:: cpp + + r_hist.at(i) + + + where :math:`i` indicates the dimension. If it were a 2D-histogram we would use something like: + + .. code-block:: cpp + + r_hist.at( i, j ) + + +#. Finally we display our histograms and wait for the user to exit: + + .. code-block:: cpp + + namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE ); + imshow("calcHist Demo", histImage ); + + waitKey(0); + + return 0; + + +Result +====== + +#. Using as input argument an image like the shown below: + + .. image:: images/Histogram_Calculation_Original_Image.jpg + :align: center + +#. Produces the following histogram: + + .. image:: images/Histogram_Calculation_Result.jpg + :align: center + diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Original_Image.jpg b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Original_Image.jpg new file mode 100644 index 0000000000..d9da998b5c Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Result.jpg b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Result.jpg new file mode 100644 index 0000000000..07b7e320d1 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Result.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Theory_Hist0.jpg b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Theory_Hist0.jpg new file mode 100644 index 0000000000..07ba95dbbe Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Theory_Hist0.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Theory_Hist1.jpg b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Theory_Hist1.jpg new file mode 100644 index 0000000000..7e420ba13b Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_calculation/images/Histogram_Calculation_Theory_Hist1.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.rst b/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.rst new file mode 100644 index 0000000000..5dbae046d3 --- /dev/null +++ b/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.rst @@ -0,0 +1,299 @@ +.. _histogram_comparison: + +Histogram Comparison +******************** + +Goal +==== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the function :compare_hist:`compareHist <>` to get a numerical parameter that express how well two histograms match with each other. + * Use different metrics to compare histograms + + +Theory +====== + +.. container:: enumeratevisibleitemswithsquare + + * To compare two histograms ( :math:`H_{1}` and :math:`H_{2}` ), first we have to choose a *metric* (:math:`d(H_{1}, H_{2})`) to express how well both histograms match. + + * OpenCV implements the function :compare_hist:`compareHist <>` to perform a comparison. It also offers 4 different metrics to compute the matching: + + + a. **Correlation ( CV\_COMP\_CORREL )** + + .. math:: + + d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}} + + where + + .. math:: + + \bar{H_k} = \frac{1}{N} \sum _J H_k(J) + + + and :math:`N` is the total number of histogram bins. + + + + b. **Chi-Square ( CV\_COMP\_CHISQR )** + + .. math:: + + d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)+H_2(I)} + + + c. **Intersection ( method=CV\_COMP\_INTERSECT )** + + .. math:: + + d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I)) + + + d. **Bhattacharyya distance ( CV\_COMP\_BHATTACHARYYA )** + + .. math:: + + d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}} + + + +Code +==== + +.. container:: enumeratevisibleitemswithsquare + + * **What does this program do?** + + .. container:: enumeratevisibleitemswithsquare + + * Loads a *base image* and 2 *test images* to be compared with it. + * Generate 1 image that is the lower half of the *base image* + * Convert the images to HSV format + * Calculate the H-S histogram for all the images and normalize them in order to compare them. + * Compare the histogram of the *base image* with respect to the 2 test histograms, the histogram of the lower half base image and with the same base image histogram. + * Display the numerical matching parameters obtained. + + * **Downloadable code**: + Click `here `_ + + * **Code at glance:** + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace std; + using namespace cv; + + /** @function main */ + int main( int argc, char** argv ) + { + Mat src_base, hsv_base; + Mat src_test1, hsv_test1; + Mat src_test2, hsv_test2; + Mat hsv_half_down; + + /// Load three images with different environment settings + if( argc < 4 ) + { printf("** Error. Usage: ./compareHist_Demo \n"); + return -1; + } + + src_base = imread( argv[1], 1 ); + src_test1 = imread( argv[2], 1 ); + src_test2 = imread( argv[3], 1 ); + + /// Convert to HSV + cvtColor( src_base, hsv_base, CV_BGR2HSV ); + cvtColor( src_test1, hsv_test1, CV_BGR2HSV ); + cvtColor( src_test2, hsv_test2, CV_BGR2HSV ); + + hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) ); + + /// Using 30 bins for hue and 32 for saturation + int h_bins = 50; int s_bins = 60; + int histSize[] = { h_bins, s_bins }; + + // hue varies from 0 to 256, saturation from 0 to 180 + float h_ranges[] = { 0, 256 }; + float s_ranges[] = { 0, 180 }; + + const float* ranges[] = { h_ranges, s_ranges }; + + // Use the o-th and 1-st channels + int channels[] = { 0, 1 }; + + /// Histograms + MatND hist_base; + MatND hist_half_down; + MatND hist_test1; + MatND hist_test2; + + /// Calculate the histograms for the HSV images + calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false ); + normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() ); + + calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false ); + normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() ); + + calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false ); + normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() ); + + calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false ); + normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() ); + + /// Apply the histogram comparison methods + for( int i = 0; i < 4; i++ ) + { int compare_method = i; + double base_base = compareHist( hist_base, hist_base, compare_method ); + double base_half = compareHist( hist_base, hist_half_down, compare_method ); + double base_test1 = compareHist( hist_base, hist_test1, compare_method ); + double base_test2 = compareHist( hist_base, hist_test2, compare_method ); + + printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 ); + } + + printf( "Done \n" ); + + return 0; + } + + +Explanation +=========== + +#. Declare variables such as the matrices to store the base image and the two other images to compare ( RGB and HSV ) + + .. code-block:: cpp + + Mat src_base, hsv_base; + Mat src_test1, hsv_test1; + Mat src_test2, hsv_test2; + Mat hsv_half_down; + +#. Load the base image (src\_base) and the other two test images: + + .. code-block:: cpp + + if( argc < 4 ) + { printf("** Error. Usage: ./compareHist_Demo \n"); + return -1; + } + + src_base = imread( argv[1], 1 ); + src_test1 = imread( argv[2], 1 ); + src_test2 = imread( argv[3], 1 ); + +#. Convert them to HSV format: + + .. code-block:: cpp + + cvtColor( src_base, hsv_base, CV_BGR2HSV ); + cvtColor( src_test1, hsv_test1, CV_BGR2HSV ); + cvtColor( src_test2, hsv_test2, CV_BGR2HSV ); + +#. Also, create an image of half the base image (in HSV format): + + .. code-block:: cpp + + hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) ); + +#. Initialize the arguments to calculate the histograms (bins, ranges and channels H and S ). + + .. code-block:: cpp + + int h_bins = 50; int s_bins = 32; + int histSize[] = { h_bins, s_bins }; + + float h_ranges[] = { 0, 256 }; + float s_ranges[] = { 0, 180 }; + + const float* ranges[] = { h_ranges, s_ranges }; + + int channels[] = { 0, 1 }; + +#. Create the MatND objects to store the histograms: + + .. code-block:: cpp + + MatND hist_base; + MatND hist_half_down; + MatND hist_test1; + MatND hist_test2; + +#. Calculate the Histograms for the base image, the 2 test images and the half-down base image: + + .. code-block:: cpp + + calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false ); + normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() ); + + calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false ); + normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() ); + + calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false ); + normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() ); + + calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false ); + normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() ); + + +#. Apply sequentially the 4 comparison methods between the histogram of the base image (hist\_base) and the other histograms: + + .. code-block:: cpp + + for( int i = 0; i < 4; i++ ) + { int compare_method = i; + double base_base = compareHist( hist_base, hist_base, compare_method ); + double base_half = compareHist( hist_base, hist_half_down, compare_method ); + double base_test1 = compareHist( hist_base, hist_test1, compare_method ); + double base_test2 = compareHist( hist_base, hist_test2, compare_method ); + + printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 ); + } + + +Results +======== + +#. We use as input the following images: + + ============ ============ ============ + |Base_0| |Test_1| |Test_2| + ============ ============ ============ + + .. |Base_0| image:: images/Histogram_Comparison_Source_0.jpg + :align: middle + + .. |Test_1| image:: images/Histogram_Comparison_Source_1.jpg + :align: middle + + .. |Test_2| image:: images/Histogram_Comparison_Source_2.jpg + :align: middle + + where the first one is the base (to be compared to the others), the other 2 are the test images. We will also compare the first image with respect to itself and with respect of half the base image. + +#. We should expect a perfect match when we compare the base image histogram with itself. Also, compared with the histogram of half the base image, it should present a high match since both are from the same source. For the other two test images, we can observe that they have very different lighting conditions, so the matching should not be very good: + +#. Here the numeric results: + + =============== =============== =============== =============== =============== + *Method* Base - Base Base - Half Base - Test 1 Base - Test 2 + =============== =============== =============== =============== =============== + *Correlation* 1.000000 0.930766 0.182073 0.120447 + *Chi-square* 0.000000 4.940466 21.184536 49.273437 + *Intersection* 24.391548 14.959809 3.889029 5.775088 + *Bhattacharyya* 0.000000 0.222609 0.646576 0.801869 + =============== =============== =============== =============== =============== + + + For the *Correlation* and *Intersection* methods, the higher the metric, the more accurate the match. As we can see, the match *base-base* is the highest of all as expected. Also we can observe that the match *base-half* is the second best match (as we predicted). For the other two metrics, the less the result, the better the match. We can observe that the matches between the test 1 and test 2 with respect to the base are worse, which again, was expected. diff --git a/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_0.jpg b/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_0.jpg new file mode 100644 index 0000000000..8d0ac9e4ab Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_0.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_1.jpg b/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_1.jpg new file mode 100644 index 0000000000..2cafdaa48d Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_1.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_2.jpg b/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_2.jpg new file mode 100644 index 0000000000..2b783930eb Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_comparison/images/Histogram_Comparison_Source_2.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.rst b/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.rst new file mode 100644 index 0000000000..857002e8f7 --- /dev/null +++ b/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.rst @@ -0,0 +1,217 @@ +.. _histogram_equalization: + +Histogram Equalization +********************** + +Goal +==== + +In this tutorial you will learn: + +.. container:: enumeratevisibleitemswithsquare + + * What an image histogram is and why it is useful + + * To equalize histograms of images by using the OpenCV function:equalize_hist:`equalizeHist <>` + + + +Theory +====== + +What is an Image Histogram? +--------------------------- + +.. container:: enumeratevisibleitemswithsquare + + * It is a graphical representation of the intensity distribution of an image. + + * It quantifies the number of pixels for each intensity value considered. + +.. image:: images/Histogram_Equalization_Theory_0.jpg + :align: center + + +What is Histogram Equalization? +------------------------------- + +.. container:: enumeratevisibleitemswithsquare + + * It is a method that improves the contrast in an image, in order to stretch out the intensity range. + + * To make it clearer, from the image above, you can see that the pixels seem clustered around the middle of the available range of intensities. What Histogram Equalization does is to *stretch out* this range. Take a look at the figure below: The green circles indicate the *underpopulated* intensities. After applying the equalization, we get an histogram like the figure in the center. The resulting image is shown in the picture at right. + +.. image:: images/Histogram_Equalization_Theory_1.jpg + :align: center + +How does it work? +----------------- + +.. container:: enumeratevisibleitemswithsquare + + * Equalization implies *mapping* one distribution (the given histogram) to another distribution (a wider and more uniform distribution of intensity values) so the intensity values are spreaded over the whole range. + + * To accomplish the equalization effect, the remapping should be the *cumulative distribution function (cdf)* (more details, refer to *Learning OpenCV*). For the histogram :math:`H(i)`, its *cumulative distribution* :math:`H^{'}(i)` is: + + .. math:: + + H^{'}(i) = \sum_{0 \le j < i} H(j) + + To use this as a remapping function, we have to normalize :math:`H^{'}(i)` such that the maximum value is 255 ( or the maximum value for the intensity of the image ). From the example above, the cumulative function is: + + .. image:: images/Histogram_Equalization_Theory_2.jpg + :align: center + + * Finally, we use a simple remapping procedure to obtain the intensity values of the equalized image: + + .. math:: + + equalized( x, y ) = H^{'}( src(x,y) ) + +Code +==== + +.. container:: enumeratevisibleitemswithsquare + + * **What does this program do?** + + .. container:: enumeratevisibleitemswithsquare + + * Loads an image + * Convert the original image to grayscale + * Equalize the Histogram by using the OpenCV function :equalize_hist:`EqualizeHist <>` + * Display the source and equalized images in a window. + + * **Downloadable code**: + Click `here `_ + + * **Code at glance:** + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace cv; + using namespace std; + + /** @function main */ + int main( int argc, char** argv ) + { + Mat src, dst; + + char* source_window = "Source image"; + char* equalized_window = "Equalized Image"; + + /// Load image + src = imread( argv[1], 1 ); + + if( !src.data ) + { cout<<"Usage: ./Histogram_Demo "<"<` : + + .. code-block:: cpp + + equalizeHist( src, dst ); + + As it can be easily seen, the only arguments are the original image and the output (equalized) image. + +#. Display both images (original and equalized) : + + .. code-block:: cpp + + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + namedWindow( equalized_window, CV_WINDOW_AUTOSIZE ); + + imshow( source_window, src ); + imshow( equalized_window, dst ); + +#. Wait until user exists the program + + .. code-block:: cpp + + waitKey(0); + return 0; + + +Results +======= + +#. To appreciate better the results of equalization, let's introduce an image with not much contrast, such as: + + .. image:: images/Histogram_Equalization_Original_Image.jpg + :align: center + + which, by the way, has this histogram: + + .. image:: images/Histogram_Equalization_Original_Histogram.jpg + :align: center + + notice that the pixels are clustered around the center of the histogram. + +#. After applying the equalization with our program, we get this result: + + .. image:: images/Histogram_Equalization_Equalized_Image.jpg + :align: center + + this image has certainly more contrast. Check out its new histogram like this: + + .. image:: images/Histogram_Equalization_Equalized_Histogram.jpg + :align: center + + Notice how the number of pixels is more distributed through the intensity range. + + +.. note:: + Are you wondering how did we draw the Histogram figures shown above? Check out the following tutorial! diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Equalized_Histogram.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Equalized_Histogram.jpg new file mode 100644 index 0000000000..aa80cfa994 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Equalized_Histogram.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Equalized_Image.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Equalized_Image.jpg new file mode 100644 index 0000000000..70f885daf1 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Equalized_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Original_Histogram.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Original_Histogram.jpg new file mode 100644 index 0000000000..a10e660b34 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Original_Histogram.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Original_Image.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Original_Image.jpg new file mode 100644 index 0000000000..cf5ddca8c5 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_0.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_0.jpg new file mode 100644 index 0000000000..4f6257961e Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_1.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_1.jpg new file mode 100644 index 0000000000..64b285ad85 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_1.jpg differ diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_2.jpg b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_2.jpg new file mode 100644 index 0000000000..0a5695841e Binary files /dev/null and b/doc/tutorials/imgproc/histograms/histogram_equalization/images/Histogram_Equalization_Theory_2.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_0.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_0.jpg new file mode 100644 index 0000000000..30b65ea923 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_0.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_1.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_1.jpg new file mode 100644 index 0000000000..3e2128b8dd Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_1.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_2.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_2.jpg new file mode 100644 index 0000000000..5427448699 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_2.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_3.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_3.jpg new file mode 100644 index 0000000000..61e4a62f3e Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_3.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_4.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_4.jpg new file mode 100644 index 0000000000..642764ed98 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_4.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_5.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_5.jpg new file mode 100644 index 0000000000..845a4a91a0 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Correl_Result_5.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Image_Result.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Image_Result.jpg new file mode 100644 index 0000000000..7eed84e5bc Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Image_Result.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Original_Image.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Original_Image.jpg new file mode 100644 index 0000000000..7411ccb968 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Image.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Image.jpg new file mode 100644 index 0000000000..5f0da4f06e Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Image.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Result.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Result.jpg new file mode 100644 index 0000000000..c81afa1c3f Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Result.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Sliding.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Sliding.jpg new file mode 100644 index 0000000000..7afeb00d7a Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Sliding.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Summary.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Summary.jpg new file mode 100644 index 0000000000..ebb5ddb1d0 Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Template_Theory_Summary.jpg differ diff --git a/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst b/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst new file mode 100644 index 0000000000..5d760bd217 --- /dev/null +++ b/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst @@ -0,0 +1,372 @@ +.. _template_matching: + +Template Matching +***************** + +Goal +==== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :match_template:`matchTemplate <>` to search for matches between an image patch and an input image + * Use the OpenCV function :min_max_loc:`minMaxLoc <>` to find the maximum and minimum values (as well as their positions) in a given array. + +Theory +====== + +What is template matching? +-------------------------- + +.. container:: enumeratevisibleitemswithsquare + + Template matching is a technique for finding areas of an image that match (are similar) to a template image (patch). + + +How does it work? +------------------ + +.. container:: enumeratevisibleitemswithsquare + + * We need two primary components: + + a. **Source image (I):** The image in which we expect to find a match to the template image + b. **Template image (T):** The patch image which will be compared to the template image + + our goal is to detect the highest matching area: + + .. image:: images/Template_Matching_Template_Theory_Summary.jpg + :align: center + + * To identify the matching area, we have to *compare* the template image against the source image by sliding it: + + .. image:: images/Template_Matching_Template_Theory_Sliding.jpg + :align: center + + * By **sliding**, we mean moving the patch one pixel at a time (left to right, up to down). At each location, a metric is calculated so it represents how "good" or "bad" the match at that location is (or how similar the patch is to that particular area of the source image). + + * For each location of **T** over **I**, you *store* the metric in the *result matrix* **(R)**. Each location :math:`(x,y)` in **R** contains the match metric: + + .. image:: images/Template_Matching_Template_Theory_Result.jpg + :align: center + + the image above is the result **R** of sliding the patch with a metric **TM_CCORR_NORMED**. The brightest locations indicate the highest matches. As you can see, the location marked by the red circle is probably the one with the highest value, so that location (the rectangle formed by that point as a corner and width and height equal to the patch image) is considered the match. + + * In practice, we use the function :min_max_loc:`minMaxLoc <>` to locate the highest value (or lower, depending of the type of matching method) in the *R* matrix. + +Which are the matching methods available in OpenCV? +---------------------------------------------------- + +Good question. OpenCV implements Template matching in the function :match_template:`matchTemplate <>`. The available methods are 6: + +a. **method=CV\_TM\_SQDIFF** + + .. math:: + + R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2 + + +b. **method=CV\_TM\_SQDIFF\_NORMED** + + .. math:: + + R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} + + +c. **method=CV\_TM\_CCORR** + + .. math:: + + R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y')) + + +d. **method=CV\_TM\_CCORR\_NORMED** + + .. math:: + + R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I'(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} + + +e. **method=CV\_TM\_CCOEFF** + + .. math:: + + R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I(x+x',y+y')) + + where + + .. math:: + + \begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array} + + +f. **method=CV\_TM\_CCOEFF\_NORMED** + + .. math:: + + R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} } + + +Code +==== + + +.. container:: enumeratevisibleitemswithsquare + + * **What does this program do?** + + .. container:: enumeratevisibleitemswithsquare + + * Loads an input image and a image patch (*template*) + * Perform a template matching procedure by using the OpenCV function :match_template:`matchTemplate <>` with any of the 6 matching methods described before. The user can choose the method by entering its selection in the Trackbar. + * Normalize the output of the matching procedure + * Localize the location with higher matching probability + * Draw a rectangle around the area corresponding to the highest match + + * **Downloadable code**: + Click `here `_ + + * **Code at glance:** + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace std; + using namespace cv; + + /// Global Variables + Mat img; Mat templ; Mat result; + char* image_window = "Source Image"; + char* result_window = "Result window"; + + int match_method; + int max_Trackbar = 5; + + /// Function Headers + void MatchingMethod( int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load image and template + img = imread( argv[1], 1 ); + templ = imread( argv[2], 1 ); + + /// Create windows + namedWindow( image_window, CV_WINDOW_AUTOSIZE ); + namedWindow( result_window, CV_WINDOW_AUTOSIZE ); + + /// Create Trackbar + char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; + createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod ); + + MatchingMethod( 0, 0 ); + + waitKey(0); + return 0; + } + + /** + * @function MatchingMethod + * @brief Trackbar callback + */ + void MatchingMethod( int, void* ) + { + /// Source image to display + Mat img_display; + img.copyTo( img_display ); + + /// Create the result matrix + int result_cols = img.cols - templ.cols + 1; + int result_rows = img.rows - templ.rows + 1; + + result.create( result_cols, result_rows, CV_32FC1 ); + + /// Do the Matching and Normalize + matchTemplate( img, templ, result, match_method ); + normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); + + /// Localizing the best match with minMaxLoc + double minVal; double maxVal; Point minLoc; Point maxLoc; + Point matchLoc; + + minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); + + /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better + if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED ) + { matchLoc = minLoc; } + else + { matchLoc = maxLoc; } + + /// Show me what you got + rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); + rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); + + imshow( image_window, img_display ); + imshow( result_window, result ); + + return; + } + +Explanation +=========== + +#. Declare some global variables, such as the image, template and result matrices, as well as the match method and the window names: + + .. code-block:: cpp + + Mat img; Mat templ; Mat result; + char* image_window = "Source Image"; + char* result_window = "Result window"; + + int match_method; + int max_Trackbar = 5; + + +#. Load the source image and template: + + .. code-block:: cpp + + img = imread( argv[1], 1 ); + templ = imread( argv[2], 1 ); + +#. Create the windows to show the results: + + .. code-block:: cpp + + namedWindow( image_window, CV_WINDOW_AUTOSIZE ); + namedWindow( result_window, CV_WINDOW_AUTOSIZE ); + +#. Create the Trackbar to enter the kind of matching method to be used. When a change is detected the callback function **MatchingMethod** is called. + + .. code-block:: cpp + + char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; + createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod ); + +#. Wait until user exits the program. + + .. code-block:: cpp + + waitKey(0); + return 0; + +#. Let's check out the callback function. First, it makes a copy of the source image: + + .. code-block:: cpp + + Mat img_display; + img.copyTo( img_display ); + + +#. Next, it creates the result matrix that will store the matching results for each template location. Observe in detail the size of the result matrix (which matches all possible locations for it) + + .. code-block:: cpp + + int result_cols = img.cols - templ.cols + 1; + int result_rows = img.rows - templ.rows + 1; + + result.create( result_cols, result_rows, CV_32FC1 ); + +#. Perform the template matching operation: + + .. code-block:: cpp + + matchTemplate( img, templ, result, match_method ); + + the arguments are naturally the input image **I**, the template **T**, the result **R** and the match_method (given by the Trackbar) + +#. We normalize the results: + + .. code-block:: cpp + + normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); + +#. We localize the minimum and maximum values in the result matrix **R** by using :min_max_loc:`minMaxLoc <>`. + + .. code-block:: cpp + + double minVal; double maxVal; Point minLoc; Point maxLoc; + Point matchLoc; + + minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); + + the function calls as arguments: + + .. container:: enumeratevisibleitemswithsquare + + + **result:** The source array + + **&minVal** and **&maxVal:** Variables to save the minimum and maximum values in **result** + + **&minLoc** and **&maxLoc:** The Point locations of the minimum and maximum values in the array. + + **Mat():** Optional mask + + +#. For the first two methods ( CV\_SQDIFF and CV\_SQDIFF\_NORMED ) the best match are the lowest values. For all the others, higher values represent better matches. So, we save the corresponding value in the **matchLoc** variable: + + .. code-block:: cpp + + if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED ) + { matchLoc = minLoc; } + else + { matchLoc = maxLoc; } + +#. Display the source image and the result matrix. Draw a rectangle around the highest possible matching area: + + .. code-block:: cpp + + rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); + rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); + + imshow( image_window, img_display ); + imshow( result_window, result ); + + +Results +======= + +#. Testing our program with an input image such as: + + .. image:: images/Template_Matching_Original_Image.jpg + :align: center + + and a template image: + + .. image:: images/Template_Matching_Template_Image.jpg + :align: center + +#. Generate the following result matrices (first row are the standard methods SQDIFF, CCORR and CCOEFF, second row are the same methods in its normalized version). In the first column, the darkest is the better match, for the other two columns, the brighter a location, the higher the match. + + ============ ============ ============ + |Result_0| |Result_2| |Result_4| + ============ ============ ============ + |Result_1| |Result_3| |Result_5| + ============ ============ ============ + + .. |Result_0| image:: images/Template_Matching_Correl_Result_0.jpg + :align: middle + + .. |Result_1| image:: images/Template_Matching_Correl_Result_1.jpg + :align: middle + + .. |Result_2| image:: images/Template_Matching_Correl_Result_2.jpg + :align: middle + + .. |Result_3| image:: images/Template_Matching_Correl_Result_3.jpg + :align: middle + + .. |Result_4| image:: images/Template_Matching_Correl_Result_4.jpg + :align: middle + + .. |Result_5| image:: images/Template_Matching_Correl_Result_5.jpg + :align: middle + +#. The right match is shown below (black rectangle around the face of the guy at the right). Notice that CCORR and CCDEFF gave erroneous best matches, however their normalized version did it right, this may be due to the fact that we are only considering the "highest match" and not the other possible high matches. + + .. image:: images/Template_Matching_Image_Result.jpg + :align: center + diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst index 1741111275..73a25382f6 100644 --- a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst +++ b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst @@ -27,12 +27,12 @@ Steps .. math:: K = \dfrac{1}{159}\begin{bmatrix} - 2 & 4 & 5 & 4 & 2 \\ - 4 & 9 & 12 & 9 & 4 \\ - 5 & 12 & 15 & 12 & 5 \\ - 4 & 9 & 12 & 9 & 4 \\ - 2 & 4 & 5 & 4 & 2 - \end{bmatrix} + 2 & 4 & 5 & 4 & 2 \\ + 4 & 9 & 12 & 9 & 4 \\ + 5 & 12 & 15 & 12 & 5 \\ + 4 & 9 & 12 & 9 & 4 \\ + 2 & 4 & 5 & 4 & 2 + \end{bmatrix} #. Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel: @@ -206,7 +206,8 @@ Explanation #. Create a window to display the results .. code-block:: cpp - namedWindow( window_name, CV_WINDOW_AUTOSIZE ); + + namedWindow( window_name, CV_WINDOW_AUTOSIZE ); #. Create a Trackbar for the user to enter the lower threshold for our Canny detector: diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg index b4545669fd..bf448f3c0f 100644 Binary files a/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg and b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg index bbddc716f6..21c8e1b35f 100644 Binary files a/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg and b/doc/tutorials/imgproc/imgtrans/canny_detector/images/Canny_Detector_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst index a475dfb0da..5558b35013 100644 --- a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst +++ b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst @@ -1,4 +1,4 @@ -.. _copyMakeBorder: +.. _copyMakeBorderTutorial: Adding borders to your images ****************************** diff --git a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg index 1c83dcb4c7..10c6c54159 100644 Binary files a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg and b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/images/CopyMakeBorder_Tutorial_Results.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst index 03e9148cf4..7fad4b56a7 100644 --- a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst +++ b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst @@ -132,6 +132,7 @@ Code return 0; } + Explanation ============= @@ -193,6 +194,6 @@ Results #. After compiling the code above, you can execute it giving as argument the path of an image. The result should be a window that shows an image blurred by a normalized filter. Each 0.5 seconds the kernel size should change, as can be seen in the series of snapshots below: - .. image:: images/filter_2d_tutorial_result.png + .. image:: images/filter_2d_tutorial_result.jpg :alt: kernel example :align: center diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png index 70d4e2d210..4105288e64 100644 Binary files a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png and b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_kernel_theory.png differ diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.jpg b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.jpg new file mode 100644 index 0000000000..2cf9f5c16b Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.png b/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.png deleted file mode 100644 index 416d84d98c..0000000000 Binary files a/doc/tutorials/imgproc/imgtrans/filter_2d/images/filter_2d_tutorial_result.png and /dev/null differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst index 43f7cd0d74..bd90c0930e 100644 --- a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst +++ b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst @@ -1,178 +1,182 @@ -.. _hough_circle: - -Hough Circle Transform -*********************** - -Goal -===== -In this tutorial you will learn how to: - -* Use the OpenCV function :hough_circles:`HoughCircles <>` to detect circles in an image. - -Theory -======= - -Hough Circle Transform ------------------------- - -* The Hough Circle Transform works in a *roughly* analogous way to the Hough Line Transform explained in the previous tutorial. -* In the line detection case, a line was defined by two parameters :math:`(r, \theta)`. In the circle case, we need three parameters to define a circle: - - .. math:: - - C : ( x_{center}, y_{center}, r ) - - where :math:`(x_{center}, y_{center})` define the center position (gree point) and :math:`r` is the radius, which allows us to completely define a circle, as it can be seen below: - - .. image:: images/Hough_Circle_Tutorial_Theory_0.jpg - :alt: Result of detecting circles with Hough Transform - :height: 200pt - :align: center - -* For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard Hough Transform: *The Hough gradient method*. For more details, please check the book *Learning OpenCV* or your favorite Computer Vision bibliography - -Code -====== - -#. **What does this program do?** - - * Loads an image and blur it to reduce the noise - * Applies the *Hough Circle Transform* to the blurred image . - * Display the detected circle in a window. - -#. The sample code that we will explain can be downloaded from `here `_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui/highgui.hpp" - #include "opencv2/imgproc/imgproc.hpp" - #include - #include - - using namespace cv; - - /** @function main */ - int main(int argc, char** argv) - { - Mat src, src_gray; - - /// Read the image - src = imread( argv[1], 1 ); - - if( !src.data ) - { return -1; } - - /// Convert it to gray - cvtColor( src, src_gray, CV_BGR2GRAY ); - - /// Reduce the noise so we avoid false circle detection - GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); - - vector circles; - - /// Apply the Hough Transform to find the circles - HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); - - /// Draw the circles detected - for( size_t i = 0; i < circles.size(); i++ ) - { - Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); - int radius = cvRound(circles[i][2]); - // circle center - circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); - // circle outline - circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); - } - - /// Show your results - namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); - imshow( "Hough Circle Transform Demo", src ); - - waitKey(0); - return 0; - } - - -Explanation -============ - - -#. Load an image - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - - if( !src.data ) - { return -1; } - -#. Convert it to grayscale: - - .. code-block:: cpp - - cvtColor( src, src_gray, CV_BGR2GRAY ); - -#. Apply a Gaussian blur to reduce noise and avoid false circle detection: - - .. code-block:: cpp - - GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); - -#. Proceed to apply Hough Circle Transform: - - .. code-block:: cpp - - vector circles; - - HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); - - with the arguments: - - * *src_gray*: Input image (grayscale) - * *circles*: A vector that stores sets of 3 values: :math:`x_{c}, y_{c}, r` for each detected circle. - * *CV_HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in OpenCV - * *dp = 1*: The inverse ratio of resolution - * *min_dist = src_gray.rows/8*: Minimum distance between detected centers - * *param_1 = 200*: Upper threshold for the internal Canny edge detector - * *param_2* = 100*: Threshold for center detection. - * *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default. - * *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default - -#. Draw the detected circles: - - .. code-block:: cpp - - for( size_t i = 0; i < circles.size(); i++ ) - { - Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); - int radius = cvRound(circles[i][2]); - // circle center - circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); - // circle outline - circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); - } - - You can see that we will draw the circle(s) on red and the center(s) with a small green dot - -#. Display the detected circle(s): - - .. code-block:: cpp - - namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); - imshow( "Hough Circle Transform Demo", src ); - -#. Wait for the user to exit the program - - .. code-block:: cpp - - waitKey(0); - - -Result -======= - -The result of running the code above with a test image is shown below: - -.. image:: images/Hough_Circle_Tutorial_Result.jpg - :alt: Result of detecting circles with Hough Transform - :align: center +.. _hough_circle: + +Hough Circle Transform +*********************** + +Goal +===== +In this tutorial you will learn how to: + +* Use the OpenCV function :hough_circles:`HoughCircles <>` to detect circles in an image. + +Theory +======= + +Hough Circle Transform +------------------------ + +* The Hough Circle Transform works in a *roughly* analogous way to the Hough Line Transform explained in the previous tutorial. +* In the line detection case, a line was defined by two parameters :math:`(r, \theta)`. In the circle case, we need three parameters to define a circle: + + .. math:: + + C : ( x_{center}, y_{center}, r ) + + where :math:`(x_{center}, y_{center})` define the center position (gree point) and :math:`r` is the radius, which allows us to completely define a circle, as it can be seen below: + + .. image:: images/Hough_Circle_Tutorial_Theory_0.jpg + :alt: Result of detecting circles with Hough Transform + :align: center + +* For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard Hough Transform: *The Hough gradient method*. For more details, please check the book *Learning OpenCV* or your favorite Computer Vision bibliography + +Code +====== + +#. **What does this program do?** + + * Loads an image and blur it to reduce the noise + * Applies the *Hough Circle Transform* to the blurred image . + * Display the detected circle in a window. + + .. |TutorialHoughCirclesSimpleDownload| replace:: here + .. _TutorialHoughCirclesSimpleDownload: https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/houghlines.cpp + .. |TutorialHoughCirclesFancyDownload| replace:: here + .. _TutorialHoughCirclesFancyDownload: https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp + +#. The sample code that we will explain can be downloaded from |TutorialHoughCirclesSimpleDownload|_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found |TutorialHoughCirclesFancyDownload|_. + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace cv; + + /** @function main */ + int main(int argc, char** argv) + { + Mat src, src_gray; + + /// Read the image + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + + /// Convert it to gray + cvtColor( src, src_gray, CV_BGR2GRAY ); + + /// Reduce the noise so we avoid false circle detection + GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); + + vector circles; + + /// Apply the Hough Transform to find the circles + HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); + + /// Draw the circles detected + for( size_t i = 0; i < circles.size(); i++ ) + { + Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); + int radius = cvRound(circles[i][2]); + // circle center + circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); + // circle outline + circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); + } + + /// Show your results + namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); + imshow( "Hough Circle Transform Demo", src ); + + waitKey(0); + return 0; + } + + +Explanation +============ + + +#. Load an image + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + +#. Convert it to grayscale: + + .. code-block:: cpp + + cvtColor( src, src_gray, CV_BGR2GRAY ); + +#. Apply a Gaussian blur to reduce noise and avoid false circle detection: + + .. code-block:: cpp + + GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); + +#. Proceed to apply Hough Circle Transform: + + .. code-block:: cpp + + vector circles; + + HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); + + with the arguments: + + * *src_gray*: Input image (grayscale) + * *circles*: A vector that stores sets of 3 values: :math:`x_{c}, y_{c}, r` for each detected circle. + * *CV_HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in OpenCV + * *dp = 1*: The inverse ratio of resolution + * *min_dist = src_gray.rows/8*: Minimum distance between detected centers + * *param_1 = 200*: Upper threshold for the internal Canny edge detector + * *param_2* = 100*: Threshold for center detection. + * *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default. + * *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default + +#. Draw the detected circles: + + .. code-block:: cpp + + for( size_t i = 0; i < circles.size(); i++ ) + { + Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); + int radius = cvRound(circles[i][2]); + // circle center + circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); + // circle outline + circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); + } + + You can see that we will draw the circle(s) on red and the center(s) with a small green dot + +#. Display the detected circle(s): + + .. code-block:: cpp + + namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); + imshow( "Hough Circle Transform Demo", src ); + +#. Wait for the user to exit the program + + .. code-block:: cpp + + waitKey(0); + + +Result +======= + +The result of running the code above with a test image is shown below: + +.. image:: images/Hough_Circle_Tutorial_Result.jpg + :alt: Result of detecting circles with Hough Transform + :align: center diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg index 2a599fc6ca..b05618478e 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg and b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg index 8b729ca2fd..a09c46e1ea 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg and b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst index 9a717344f2..3d29793161 100644 --- a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst +++ b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst @@ -30,9 +30,8 @@ How does it work? b. In the **Polar coordinate system:** Parameters: :math:`(r,\theta)` .. image:: images/Hough_Lines_Tutorial_Theory_0.jpg - :alt: Line variables - :height: 200pt - :align: center + :alt: Line variables + :align: center For Hough Transforms, we will express lines in the *Polar system*. Hence, a line equation can be written as: @@ -53,18 +52,17 @@ How does it work? #. If for a given :math:`(x_{0}, y_{0})` we plot the family of lines that goes through it, we get a sinusoid. For instance, for :math:`x_{0} = 8` and :math:`y_{0} = 6` we get the following plot (in a plane :math:`\theta` - :math:`r`): .. image:: images/Hough_Lines_Tutorial_Theory_1.jpg - :alt: Polar plot of a the family of lines of a point - :height: 200pt - :align: center + :alt: Polar plot of a the family of lines of a point + :align: center We consider only points such that :math:`r > 0` and :math:`0< \theta < 2 \pi`. #. We can do the same operation above for all the points in an image. If the curves of two different points intersect in the plane :math:`\theta` - :math:`r`, that means that both points belong to a same line. For instance, following with the example above and drawing the plot for two more points: :math:`x_{1} = 9`, :math:`y_{1} = 4` and :math:`x_{2} = 12`, :math:`y_{2} = 3`, we get: .. image:: images/Hough_Lines_Tutorial_Theory_2.jpg - :alt: Polar plot of the family of lines for three points - :height: 200pt - :align: center + :alt: Polar plot of the family of lines for three points + :align: center + The three plots intersect in one single point :math:`(0.925, 9.6)`, these coordinates are the parameters (:math:`\theta, r`) or the line in which :math:`(x_{0}, y_{0})`, :math:`(x_{1}, y_{1})` and :math:`(x_{2}, y_{2})` lay. #. What does all the stuff above mean? It means that in general, a line can be *detected* by finding the number of intersections between curves.The more curves intersecting means that the line represented by that intersection have more points. In general, we can define a *threshold* of the minimum number of intersections needed to *detect* a line. @@ -90,13 +88,19 @@ b. **The Probabilistic Hough Line Transform** Code ====== +.. |TutorialHoughLinesSimpleDownload| replace:: here +.. _TutorialHoughLinesSimpleDownload: https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/houghlines.cpp +.. |TutorialHoughLinesFancyDownload| replace:: here +.. _TutorialHoughLinesFancyDownload: https://code.ros.org/svn/opencv/trunk/opencv/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp + + #. **What does this program do?** * Loads an image * Applies either a *Standard Hough Line Transform* or a *Probabilistic Line Transform*. * Display the original image and the detected line in two windows. -#. The sample code that we will explain can be downloaded from `here `_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found `here `_ +#. The sample code that we will explain can be downloaded from |TutorialHoughLinesSimpleDownload|_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found |TutorialHoughLinesFancyDownload|_. .. code-block:: cpp @@ -112,12 +116,12 @@ Code { cout << "\nThis program demonstrates line finding with the Hough transform.\n" "Usage:\n" - "./houghlines , Default is pic1.png\n" << endl; + "./houghlines , Default is pic1.jpg\n" << endl; } int main(int argc, char** argv) { - const char* filename = argc >= 2 ? argv[1] : "pic1.png"; + const char* filename = argc >= 2 ? argv[1] : "pic1.jpg"; Mat src = imread(filename, 0); if(src.empty()) @@ -276,14 +280,14 @@ Result Using an input image such as: .. image:: images/Hough_Lines_Tutorial_Original_Image.jpg - :alt: Result of detecting lines with Hough Transform - :align: center + :alt: Result of detecting lines with Hough Transform + :align: center We get the following result by using the Probabilistic Hough Line Transform: .. image:: images/Hough_Lines_Tutorial_Result.jpg - :alt: Result of detecting lines with Hough Transform - :align: center + :alt: Result of detecting lines with Hough Transform + :align: center You may observe that the number of lines detected vary while you change the *threshold*. The explanation is sort of evident: If you establish a higher threshold, fewer lines will be detected (since you will need more points to declare a line detected). diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg index 2e6211dbd3..ec75831989 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg index a6107b02b5..125437d8e8 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg index e8111eb42e..0e0ff22ca1 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg index 0f297046c5..edbbcf65c8 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_1.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg index ae0dc05122..996f7c6e50 100644 Binary files a/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg and b/doc/tutorials/imgproc/imgtrans/hough_lines/images/Hough_Lines_Tutorial_Theory_2.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg index 2369ba57ce..beb114c7b5 100644 Binary files a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg index 2354d9a5db..9cba13315b 100644 Binary files a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg index 1d5a29d8ba..6a16926e39 100644 Binary files a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_Previous.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg index 7bc1768b0a..67d95d237a 100644 Binary files a/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg and b/doc/tutorials/imgproc/imgtrans/laplace_operator/images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst index b7a8ee7519..99bb326ac5 100644 --- a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst +++ b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst @@ -19,14 +19,12 @@ Theory .. image:: images/Laplace_Operator_Tutorial_Theory_Previous.jpg :alt: Previous theory - :height: 200pt :align: center #. And...what happens if we take the second derivative? .. image:: images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg :alt: Second derivative - :height: 200pt :align: center You can observe that the second derivative is zero! So, we can also use this criterion to attempt to detect edges in an image. However, note that zeros will not only appear in edges (they can actually appear in other meaningless locations); this can be solved by applying filtering where needed. diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..422ce19dbb Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_0.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_0.jpg new file mode 100644 index 0000000000..5020931d86 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_1.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_1.jpg new file mode 100644 index 0000000000..e601fdfe57 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_1.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_2.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_2.jpg new file mode 100644 index 0000000000..f597d49292 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_2.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_3.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_3.jpg new file mode 100644 index 0000000000..fabfaf0569 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Result_3.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Theory_0.jpg new file mode 100644 index 0000000000..e58669623e Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Theory_1.jpg b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Theory_1.jpg new file mode 100644 index 0000000000..7195da79c3 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/remap/images/Remap_Tutorial_Theory_1.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/remap/remap.rst b/doc/tutorials/imgproc/imgtrans/remap/remap.rst new file mode 100644 index 0000000000..61e7048ea2 --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/remap/remap.rst @@ -0,0 +1,314 @@ +.. _remap: + +Remapping +********* + +Goal +==== + +In this tutorial you will learn how to: + +a. Use the OpenCV function :remap:`remap <>` to implement simple remapping routines. + +Theory +====== + +What is remapping? +------------------ + +* It is the process of taking pixels from one place in the image and locating them in another position in a new image. + +* To accomplish the mapping process, it might be necessary to do some interpolation for non-integer pixel locations, since there will not always be a one-to-one-pixel correspondence between source and destination images. + +* We can express the remap for every pixel location :math:`(x,y)` as: + + .. math:: + + g(x,y) = f ( h(x,y) ) + + where :math:`g()` is the remapped image, :math:`f()` the source image and :math:`h(x,y)` is the mapping function that operates on :math:`(x,y)`. + +* Let's think in a quick example. Imagine that we have an image :math:`I` and, say, we want to do a remap such that: + + .. math:: + + h(x,y) = (I.cols - x, y ) + + What would happen? It is easily seen that the image would flip in the :math:`x` direction. For instance, consider the input image: + + .. image:: images/Remap_Tutorial_Theory_0.jpg + :alt: Original test image + :width: 120pt + :align: center + + observe how the red circle changes positions with respect to x (considering :math:`x` the horizontal direction): + + .. image:: images/Remap_Tutorial_Theory_1.jpg + :alt: Original test image + :width: 120pt + :align: center + +* In OpenCV, the function :remap:`remap <>` offers a simple remapping implementation. + +Code +==== + +#. **What does this program do?** + + * Loads an image + * Each second, apply 1 of 4 different remapping processes to the image and display them indefinitely in a window. + * Wait for the user to exit the program + +#. The tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace cv; + + /// Global variables + Mat src, dst; + Mat map_x, map_y; + char* remap_window = "Remap demo"; + int ind = 0; + + /// Function Headers + void update_map( void ); + + /** + * @function main + */ + int main( int argc, char** argv ) + { + /// Load the image + src = imread( argv[1], 1 ); + + /// Create dst, map_x and map_y with the same size as src: + dst.create( src.size(), src.type() ); + map_x.create( src.size(), CV_32FC1 ); + map_y.create( src.size(), CV_32FC1 ); + + /// Create window + namedWindow( remap_window, CV_WINDOW_AUTOSIZE ); + + /// Loop + while( true ) + { + /// Each 1 sec. Press ESC to exit the program + int c = waitKey( 1000 ); + + if( (char)c == 27 ) + { break; } + + /// Update map_x & map_y. Then apply remap + update_map(); + remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) ); + + /// Display results + imshow( remap_window, dst ); + } + return 0; + } + + /** + * @function update_map + * @brief Fill the map_x and map_y matrices with 4 types of mappings + */ + void update_map( void ) + { + ind = ind%4; + + for( int j = 0; j < src.rows; j++ ) + { for( int i = 0; i < src.cols; i++ ) + { + switch( ind ) + { + case 0: + if( i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 ) + { + map_x.at(j,i) = 2*( i - src.cols*0.25 ) + 0.5 ; + map_y.at(j,i) = 2*( j - src.rows*0.25 ) + 0.5 ; + } + else + { map_x.at(j,i) = 0 ; + map_y.at(j,i) = 0 ; + } + break; + case 1: + map_x.at(j,i) = i ; + map_y.at(j,i) = src.rows - j ; + break; + case 2: + map_x.at(j,i) = src.cols - i ; + map_y.at(j,i) = j ; + break; + case 3: + map_x.at(j,i) = src.cols - i ; + map_y.at(j,i) = src.rows - j ; + break; + } // end of switch + } + } + ind++; + } + +Explanation +=========== + +#. Create some variables we will use: + + .. code-block:: cpp + + Mat src, dst; + Mat map_x, map_y; + char* remap_window = "Remap demo"; + int ind = 0; + +#. Load an image: + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + +#. Create the destination image and the two mapping matrices (for x and y ) + + .. code-block:: cpp + + dst.create( src.size(), src.type() ); + map_x.create( src.size(), CV_32FC1 ); + map_y.create( src.size(), CV_32FC1 ); + +#. Create a window to display results + + .. code-block:: cpp + + namedWindow( remap_window, CV_WINDOW_AUTOSIZE ); + +#. Establish a loop. Each 1000 ms we update our mapping matrices (*mat_x* and *mat_y*) and apply them to our source image: + + .. code-block:: cpp + + while( true ) + { + /// Each 1 sec. Press ESC to exit the program + int c = waitKey( 1000 ); + + if( (char)c == 27 ) + { break; } + + /// Update map_x & map_y. Then apply remap + update_map(); + remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) ); + + /// Display results + imshow( remap_window, dst ); + } + + The function that applies the remapping is :remap:`remap <>`. We give the following arguments: + + * **src**: Source image + * **dst**: Destination image of same size as *src* + * **map_x**: The mapping function in the x direction. It is equivalent to the first component of :math:`h(i,j)` + * **map_y**: Same as above, but in y direction. Note that *map_y* and *map_x* are both of the same size as *src* + * **CV_INTER_LINEAR**: The type of interpolation to use for non-integer pixels. This is by default. + * **BORDER_CONSTANT**: Default + + How do we update our mapping matrices *mat_x* and *mat_y*? Go on reading: + +#. **Updating the mapping matrices:** We are going to perform 4 different mappings: + + a. Reduce the picture to half its size and will display it in the middle: + + .. math:: + + h(i,j) = ( 2*i - src.cols/2 + 0.5, 2*j - src.rows/2 + 0.5) + + for all pairs :math:`(i,j)` such that: :math:`\dfrac{src.cols}{4} src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 ) + { + map_x.at(j,i) = 2*( i - src.cols*0.25 ) + 0.5 ; + map_y.at(j,i) = 2*( j - src.rows*0.25 ) + 0.5 ; + } + else + { map_x.at(j,i) = 0 ; + map_y.at(j,i) = 0 ; + } + break; + case 1: + map_x.at(j,i) = i ; + map_y.at(j,i) = src.rows - j ; + break; + case 2: + map_x.at(j,i) = src.cols - i ; + map_y.at(j,i) = j ; + break; + case 3: + map_x.at(j,i) = src.cols - i ; + map_y.at(j,i) = src.rows - j ; + break; + } // end of switch + } + } + ind++; + } + + +Result +====== + +#. After compiling the code above, you can execute it giving as argument an image path. For instance, by using the following image: + + .. image:: images/Remap_Tutorial_Original_Image.jpg + :alt: Original test image + :width: 250pt + :align: center + +#. This is the result of reducing it to half the size and centering it: + + .. image:: images/Remap_Tutorial_Result_0.jpg + :alt: Result 0 for remapping + :width: 250pt + :align: center + +#. Turning it upside down: + + .. image:: images/Remap_Tutorial_Result_1.jpg + :alt: Result 0 for remapping + :width: 250pt + :align: center + +#. Reflecting it in the x direction: + + .. image:: images/Remap_Tutorial_Result_2.jpg + :alt: Result 0 for remapping + :width: 250pt + :align: center + +#. Reflecting it in both directions: + +.. image:: images/Remap_Tutorial_Result_3.jpg + :alt: Result 0 for remapping + :width: 250pt + :align: center + diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg index ead594e5eb..45f44b8cd5 100644 Binary files a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Result.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg index c79d50634a..2c84310632 100644 Binary files a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg index bd77398107..adaab86673 100644 Binary files a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg index ce43af116c..3a5b13a3f9 100644 Binary files a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg index 7bc1768b0a..3fae177233 100644 Binary files a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg and b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/images/Sobel_Derivatives_Tutorial_Theory_ddIntensity_Function.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst index 4b504a8c20..d544b109cd 100644 --- a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst +++ b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst @@ -26,7 +26,6 @@ Theory .. image:: images/Sobel_Derivatives_Tutorial_Theory_0.jpg :alt: How intensity changes in an edge - :height: 200pt :align: center You can easily notice that in an *edge*, the pixel intensity *changes* in a notorious way. A good way to express *changes* is by using *derivatives*. A high change in gradient indicates a major change in the image. @@ -35,14 +34,12 @@ Theory .. image:: images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg :alt: Intensity Plot for an edge - :height: 200pt :align: center #. The edge "jump" can be seen more easily if we take the first derivative (actually, here appears as a maximum) .. image:: images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg :alt: First derivative of Intensity - Plot for an edge - :height: 200pt :align: center #. So, from the explanation above, we can deduce that a method to detect edges in an image can be performed by locating pixel locations where the gradient is higher than its neighbors (or to generalize, higher than a threshold). @@ -231,6 +228,7 @@ Explanation Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); /// Gradient Y Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); + The function takes the following arguments: * *src_gray*: In our example, the input image. Here it is *CV_8U* diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..6c1c77341b Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Result_Warp.jpg b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Result_Warp.jpg new file mode 100644 index 0000000000..8fa7d65c4c Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Result_Warp.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg new file mode 100644 index 0000000000..1f828309ff Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Theory_0.jpg new file mode 100644 index 0000000000..8294823bd8 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/warp_affine/images/Warp_Affine_Tutorial_Theory_0.jpg differ diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.rst b/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.rst new file mode 100644 index 0000000000..774ef281ed --- /dev/null +++ b/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.rst @@ -0,0 +1,309 @@ +.. _warp_affine: + +Affine Transformations +********************** + + +Goal +==== + +In this tutorial you will learn how to: + +a. Use the OpenCV function :warp_affine:`warpAffine <>` to implement simple remapping routines. +b. Use the OpenCV function :get_rotation_matrix_2d:`getRotationMatrix2D <>` to obtain a :math:`2 \times 3` rotation matrix + + +Theory +====== + +What is an Affine Transformation? +---------------------------------- + +#. It is any transformation that can be expressed in the form of a *matrix multiplication* (linear transformation) followed by a *vector addition* (translation). + +#. From the above, We can use an Affine Transformation to express: + + a. Rotations (linear transformation) + b. Translations (vector addition) + c. Scale operations (linear transformation) + + you can see that, in essence, an Affine Transformation represents a **relation** between two images. + +#. The usual way to represent an Affine Transform is by using a :math:`2 \times 3` matrix. + + .. math:: + + A = \begin{bmatrix} + a_{00} & a_{01} \\ + a_{10} & a_{11} + \end{bmatrix}_{2 \times 2} + B = \begin{bmatrix} + b_{00} \\ + b_{10} + \end{bmatrix}_{2 \times 1} + + M = \begin{bmatrix} + A & B + \end{bmatrix} + = + \begin{bmatrix} + a_{00} & a_{01} & b_{00} \\ + a_{10} & a_{11} & b_{10} + \end{bmatrix}_{2 \times 3} + + Considering that we want to transform a 2D vector :math:`X = \begin{bmatrix}x \\ y\end{bmatrix}` by using :math:`A` and :math:`B`, we can do it equivalently with: + + + :math:`T = A \cdot \begin{bmatrix}x \\ y\end{bmatrix} + B` or :math:`T = M \cdot [x, y, 1]^{T}` + + .. math:: + + T = \begin{bmatrix} + a_{00}x + a_{01}y + b_{00} \\ + a_{10}x + a_{11}y + b_{10} + \end{bmatrix} + + +How do we get an Affine Transformation? +--------------------------------------- + +1. Excellent question. We mentioned that an Affine Transformation is basically a **relation** between two images. The information about this relation can come, roughly, in two ways: + + a. We know both :math:`X` and `T` and we also know that they are related. Then our job is to find :math:`M` + + b. We know :math:`M` and :math:'X`. To obtain :math:`T` we only need to apply :math:`T = M \cdot X`. Our information for :math:`M` may be explicit (i.e. have the 2-by-3 matrix) or it can come as a geometric relation between points. + +2. Let's explain a little bit better (b). Since :math:`M` relates 02 images, we can analyze the simplest case in which it relates three points in both images. Look at the figure below: + + .. image:: images/Warp_Affine_Tutorial_Theory_0.jpg + :alt: Theory of Warp Affine + :width: 350pt + :align: center + + the points 1, 2 and 3 (forming a triangle in image 1) are mapped into image 2, still forming a triangle, but now they have changed notoriously. If we find the Affine Transformation with these 3 points (you can choose them as you like), then we can apply this found relation to the whole pixels in the image. + + +Code +==== + +#. **What does this program do?** + + * Loads an image + * Applies an Affine Transform to the image. This Transform is obtained from the relation between three points. We use the function :warp_affine:`warpAffine <>` for that purpose. + * Applies a Rotation to the image after being transformed. This rotation is with respect to the image center + * Waits until the user exits the program + +#. The tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + + using namespace cv; + using namespace std; + + /// Global variables + char* source_window = "Source image"; + char* warp_window = "Warp"; + char* warp_rotate_window = "Warp + Rotate"; + + /** @function main */ + int main( int argc, char** argv ) + { + Point2f srcTri[3]; + Point2f dstTri[3]; + + Mat rot_mat( 2, 3, CV_32FC1 ); + Mat warp_mat( 2, 3, CV_32FC1 ); + Mat src, warp_dst, warp_rotate_dst; + + /// Load the image + src = imread( argv[1], 1 ); + + /// Set the dst image the same type and size as src + warp_dst = Mat::zeros( src.rows, src.cols, src.type() ); + + /// Set your 3 points to calculate the Affine Transform + srcTri[0] = Point2f( 0,0 ); + srcTri[1] = Point2f( src.cols - 1, 0 ); + srcTri[2] = Point2f( 0, src.rows - 1 ); + + dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 ); + dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 ); + dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 ); + + /// Get the Affine Transform + warp_mat = getAffineTransform( srcTri, dstTri ); + + /// Apply the Affine Transform just found to the src image + warpAffine( src, warp_dst, warp_mat, warp_dst.size() ); + + /** Rotating the image after Warp */ + + /// Compute a rotation matrix with respect to the center of the image + Point center = Point( warp_dst.cols/2, warp_dst.rows/2 ); + double angle = -50.0; + double scale = 0.6; + + /// Get the rotation matrix with the specifications above + rot_mat = getRotationMatrix2D( center, angle, scale ); + + /// Rotate the warped image + warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() ); + + /// Show what you got + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + namedWindow( warp_window, CV_WINDOW_AUTOSIZE ); + imshow( warp_window, warp_dst ); + + namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE ); + imshow( warp_rotate_window, warp_rotate_dst ); + + /// Wait until user exits the program + waitKey(0); + + return 0; + } + +Explanation +=========== + +#. Declare some variables we will use, such as the matrices to store our results and 2 arrays of points to store the 2D points that define our Affine Transform. + + .. code-block:: cpp + + Point2f srcTri[3]; + Point2f dstTri[3]; + + Mat rot_mat( 2, 3, CV_32FC1 ); + Mat warp_mat( 2, 3, CV_32FC1 ); + Mat src, warp_dst, warp_rotate_dst; + +#. Load an image: + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + +#. Initialize the destination image as having the same size and type as the source: + + .. code-block:: cpp + + warp_dst = Mat::zeros( src.rows, src.cols, src.type() ); + +#. **Affine Transform:** As we explained lines above, we need two sets of 3 points to derive the affine transform relation. Take a look: + + .. code-block:: cpp + + srcTri[0] = Point2f( 0,0 ); + srcTri[1] = Point2f( src.cols - 1, 0 ); + srcTri[2] = Point2f( 0, src.rows - 1 ); + + dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 ); + dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 ); + dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 ); + + You may want to draw the points to make a better idea of how they change. Their locations are approximately the same as the ones depicted in the example figure (in the Theory section). You may note that the size and orientation of the triangle defined by the 3 points change. + +#. Armed with both sets of points, we calculate the Affine Transform by using OpenCV function :get_affine_transform:`getAffineTransform <>`: + + .. code-block:: cpp + + warp_mat = getAffineTransform( srcTri, dstTri ); + + + We get as an output a :math:`2 \times 3` matrix (in this case **warp_mat**) + +#. We apply the Affine Transform just found to the src image + + .. code-block:: cpp + + warpAffine( src, warp_dst, warp_mat, warp_dst.size() ); + + with the following arguments: + + * **src**: Input image + * **warp_dst**: Output image + * **warp_mat**: Affine transform + * **warp_dst.size()**: The desired size of the output image + + We just got our first transformed image! We will display it in one bit. Before that, we also want to rotate it... + +#. **Rotate:** + To rotate an image, we need to know two things: + + a. The center with respect to which the image will rotate + b. The angle to be rotated. In OpenCV a positive angle is counter-clockwise + c. *Optional:* A scale factor + + We define these parameters with the following snippet: + + .. code-block:: cpp + + Point center = Point( warp_dst.cols/2, warp_dst.rows/2 ); + double angle = -50.0; + double scale = 0.6; + +#. We generate the rotation matrix with the OpenCV function :get_rotation_matrix_2d:`getRotationMatrix2D <>`, which returns a :math:`2 \times 3` matrix (in this case *rot_mat*) + + .. code-block:: cpp + + rot_mat = getRotationMatrix2D( center, angle, scale ); + +#. We now apply the found rotation to the output of our previous Transformation. + + .. code-block:: cpp + + warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() ); + +#. Finally, we display our results in two windows plus the original image for good measure: + + .. code-block:: cpp + + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + namedWindow( warp_window, CV_WINDOW_AUTOSIZE ); + imshow( warp_window, warp_dst ); + + namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE ); + imshow( warp_rotate_window, warp_rotate_dst ); + + +#. We just have to wait until the user exits the program + + .. code-block:: cpp + + waitKey(0); + + + +Result +====== + +#. After compiling the code above, we can give it the path of an image as argument. For instance, for a picture like: + + .. image:: images/Warp_Affine_Tutorial_Original_Image.jpg + :alt: Original image + :width: 250pt + :align: center + + after applying the first Affine Transform we obtain: + + .. image:: images/Warp_Affine_Tutorial_Result_Warp.jpg + :alt: Original image + :width: 250pt + :align: center + + and finally, after applying a negative rotation (remember negative means clockwise) and a scale factor, we get: + + .. image:: images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg + :alt: Original image + :width: 250pt + :align: center + diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.jpg b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.jpg new file mode 100644 index 0000000000..dc2d1e7486 Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.png deleted file mode 100644 index 5a7ba1194f..0000000000 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg index 2f98d8359b..8aa7ff2bc0 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png index ceb4e6ebc1..ce6ff35550 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png index faa7859fd9..f112bfef11 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png index 7de2bc386a..5d8077f0d2 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png index d40b9bba16..7b8b0850fd 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png index 98d0a92e9a..ca22789b03 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst index 896a564da8..40b06a5ea5 100644 --- a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst +++ b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst @@ -44,7 +44,6 @@ Opening * For instance, check out the example below. The image at the left is the original and the image at the right is the result after applying the opening transformation. We can observe that the small spaces in the corners of the letter tend to dissapear. .. image:: images/Morphology_2_Tutorial_Theory_Opening.png - :height: 150pt :alt: Opening :align: center @@ -60,7 +59,6 @@ Closing * Useful to remove small holes (dark regions). .. image:: images/Morphology_2_Tutorial_Theory_Closing.png - :height: 150pt :alt: Closing example :align: center @@ -77,7 +75,6 @@ Morphological Gradient * It is useful for finding the outline of an object as can be seen below: .. image:: images/Morphology_2_Tutorial_Theory_Gradient.png - :height: 150pt :alt: Gradient :align: center @@ -92,7 +89,6 @@ Top Hat dst = tophat( src, element ) = src - open( src, element ) .. image:: images/Morphology_2_Tutorial_Theory_TopHat.png - :height: 150pt :alt: Top Hat :align: center @@ -106,7 +102,6 @@ Black Hat dst = blackhat( src, element ) = close( src, element ) - src .. image:: images/Morphology_2_Tutorial_Theory_BlackHat.png - :height: 150pt :alt: Black Hat :align: center @@ -270,17 +265,15 @@ Explanation Results ======== -* After compiling the code above we can execute it giving an image path as an argument. For this tutorial we use as input the image: **baboon.jpg**: +* After compiling the code above we can execute it giving an image path as an argument. For this tutorial we use as input the image: **baboon.png**: .. image:: images/Morphology_2_Tutorial_Original_Image.jpg - :height: 200pt :alt: Morphology 2: Original image :align: center * And here are two snapshots of the display window. The first picture shows the output after using the operator **Opening** with a cross kernel. The second picture (right side, shows the result of using a **Blackhat** operator with an ellipse kernel. - .. image:: images/Morphology_2_Tutorial_Cover.png - :height: 300pt + .. image:: images/Morphology_2_Tutorial_Cover.jpg :alt: Morphology 2: Result sample :align: center diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Cover.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Cover.png deleted file mode 100644 index 2a6058508d..0000000000 Binary files a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..2a4fc40d24 Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.png deleted file mode 100644 index ddf66816f5..0000000000 Binary files a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_Original_Image.png and /dev/null differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.jpg b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.jpg new file mode 100644 index 0000000000..69382aae2d Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.jpg differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.png deleted file mode 100644 index ab34b72ace..0000000000 Binary files a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrDown_Result.png and /dev/null differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.jpg b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.jpg new file mode 100644 index 0000000000..76a3b81f95 Binary files /dev/null and b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.jpg differ diff --git a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.png b/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.png deleted file mode 100644 index 17f5e18cdc..0000000000 Binary files a/doc/tutorials/imgproc/pyramids/images/Pyramids_Tutorial_PyrUp_Result.png and /dev/null differ diff --git a/doc/tutorials/imgproc/pyramids/pyramids.rst b/doc/tutorials/imgproc/pyramids/pyramids.rst index 764463f8ba..41c734742f 100644 --- a/doc/tutorials/imgproc/pyramids/pyramids.rst +++ b/doc/tutorials/imgproc/pyramids/pyramids.rst @@ -103,7 +103,7 @@ This tutorial code's is shown lines below. You can also download it from `here < printf( " * [ESC] -> Close program \n \n" ); /// Test image - Make sure it s divisible by 2^{n} - src = imread( "../images/chicky_512.png" ); + src = imread( "../images/chicky_512.jpg" ); if( !src.data ) { printf(" No data! -- Exiting the program \n"); return -1; } @@ -148,7 +148,7 @@ Explanation .. code-block:: cpp /// Test image - Make sure it s divisible by 2^{n} - src = imread( "../images/chicky_512.png" ); + src = imread( "../images/chicky_512.jpg" ); if( !src.data ) { printf(" No data! -- Exiting the program \n"); return -1; } @@ -235,21 +235,21 @@ Explanation Results ======== -* After compiling the code above we can test it. The program calls an image **chicky_512.png** that comes in the *tutorial_code/image* folder. Notice that this image is :math:`512 \times 512`, hence a downsample won't generate any error (:math:`512 = 2^{9}`). The original image is shown below: +* After compiling the code above we can test it. The program calls an image **chicky_512.jpg** that comes in the *tutorial_code/image* folder. Notice that this image is :math:`512 \times 512`, hence a downsample won't generate any error (:math:`512 = 2^{9}`). The original image is shown below: - .. image:: images/Pyramids_Tutorial_Original_Image.png + .. image:: images/Pyramids_Tutorial_Original_Image.jpg :alt: Pyramids: Original image :align: center * First we apply two successive :pyr_down:`pyrDown <>` operations by pressing 'd'. Our output is: - .. image:: images/Pyramids_Tutorial_PyrDown_Result.png + .. image:: images/Pyramids_Tutorial_PyrDown_Result.jpg :alt: Pyramids: PyrDown Result :align: center * Note that we should have lost some resolution due to the fact that we are diminishing the size of the image. This is evident after we apply :pyr_up:`pyrUp <>` twice (by pressing 'u'). Our output is now: - .. image:: images/Pyramids_Tutorial_PyrUp_Result.png + .. image:: images/Pyramids_Tutorial_PyrUp_Result.jpg :alt: Pyramids: PyrUp Result :align: center diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.rst b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.rst new file mode 100644 index 0000000000..1d7e1f2642 --- /dev/null +++ b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.rst @@ -0,0 +1,124 @@ +.. _bounding_rects_circles: + + +Creating Bounding boxes and circles for contours +************************************************* + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :bounding_rect:`boundingRect <>` + * Use the OpenCV function :min_enclosing_circle:`minEnclosingCircle <>` + + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + Mat src; Mat src_gray; + int thresh = 100; + int max_thresh = 255; + RNG rng(12345); + + /// Function header + void thresh_callback(int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + + /// Convert image to gray and blur it + cvtColor( src, src_gray, CV_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); + + /// Create Window + char* source_window = "Source"; + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function thresh_callback */ + void thresh_callback(int, void* ) + { + Mat threshold_output; + vector > contours; + vector hierarchy; + + /// Detect edges using Threshold + threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); + /// Find contours + findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); + + /// Approximate contours to polygons + get bounding rects and circles + vector > contours_poly( contours.size() ); + vector boundRect( contours.size() ); + vectorcenter( contours.size() ); + vectorradius( contours.size() ); + + for( int i = 0; i < contours.size(); i++ ) + { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true ); + boundRect[i] = boundingRect( Mat(contours_poly[i]) ); + minEnclosingCircle( contours_poly[i], center[i], radius[i] ); + } + + + /// Draw polygonal contour + bonding rects + circles + Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); + for( int i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + drawContours( drawing, contours_poly, i, color, 1, 8, vector(), 0, Point() ); + rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 ); + circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 ); + } + + /// Show in a window + namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); + imshow( "Contours", drawing ); + } + +Explanation +============ + +Result +====== + +#. Here it is: + + ========== ========== + |BRC_0| |BRC_1| + ========== ========== + + .. |BRC_0| image:: images/Bounding_Rects_Circles_Source_Image.jpg + :align: middle + + .. |BRC_1| image:: images/Bounding_Rects_Circles_Result.jpg + :align: middle + diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/images/Bounding_Rects_Circles_Result.jpg b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/images/Bounding_Rects_Circles_Result.jpg new file mode 100644 index 0000000000..d13234543d Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/images/Bounding_Rects_Circles_Result.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/images/Bounding_Rects_Circles_Source_Image.jpg b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/images/Bounding_Rects_Circles_Source_Image.jpg new file mode 100644 index 0000000000..3c08c13161 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/images/Bounding_Rects_Circles_Source_Image.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.rst b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.rst new file mode 100644 index 0000000000..1e679ea397 --- /dev/null +++ b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.rst @@ -0,0 +1,126 @@ +.. _bounding_rotated_ellipses: + + +Creating Bounding rotated boxes and ellipses for contours +********************************************************** + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :min_area_rect:`minAreaRect <>` + * Use the OpenCV function :fit_ellipse:`fitEllipse <>` + + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + Mat src; Mat src_gray; + int thresh = 100; + int max_thresh = 255; + RNG rng(12345); + + /// Function header + void thresh_callback(int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + + /// Convert image to gray and blur it + cvtColor( src, src_gray, CV_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); + + /// Create Window + char* source_window = "Source"; + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function thresh_callback */ + void thresh_callback(int, void* ) + { + Mat threshold_output; + vector > contours; + vector hierarchy; + + /// Detect edges using Threshold + threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); + /// Find contours + findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); + + /// Find the rotated rectangles and ellipses for each contour + vector minRect( contours.size() ); + vector minEllipse( contours.size() ); + + for( int i = 0; i < contours.size(); i++ ) + { minRect[i] = minAreaRect( Mat(contours[i]) ); + if( contours[i].size() > 5 ) + { minEllipse[i] = fitEllipse( Mat(contours[i]) ); } + } + + /// Draw contours + rotated rects + ellipses + Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); + for( int i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + // contour + drawContours( drawing, contours, i, color, 1, 8, vector(), 0, Point() ); + // ellipse + ellipse( drawing, minEllipse[i], color, 2, 8 ); + // rotated rectangle + Point2f rect_points[4]; minRect[i].points( rect_points ); + for( int j = 0; j < 4; j++ ) + line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 ); + } + + /// Show in a window + namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); + imshow( "Contours", drawing ); + } + +Explanation +============ + +Result +====== + +#. Here it is: + + ========== ========== + |BRE_0| |BRE_1| + ========== ========== + + .. |BRE_0| image:: images/Bounding_Rotated_Ellipses_Source_Image.jpg + :align: middle + + .. |BRE_1| image:: images/Bounding_Rotated_Ellipses_Result.jpg + :align: middle + diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/images/Bounding_Rotated_Ellipses_Result.jpg b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/images/Bounding_Rotated_Ellipses_Result.jpg new file mode 100644 index 0000000000..cc869fd808 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/images/Bounding_Rotated_Ellipses_Result.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/images/Bounding_Rotated_Ellipses_Source_Image.jpg b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/images/Bounding_Rotated_Ellipses_Source_Image.jpg new file mode 100644 index 0000000000..c475ebd221 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/images/Bounding_Rotated_Ellipses_Source_Image.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.rst b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.rst new file mode 100644 index 0000000000..fa46610d94 --- /dev/null +++ b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.rst @@ -0,0 +1,107 @@ +.. _find_contours: + +Finding contours in your image +****************************** + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :find_contours:`findContours <>` + * Use the OpenCV function :draw_contours:`drawContours <>` + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + Mat src; Mat src_gray; + int thresh = 100; + int max_thresh = 255; + RNG rng(12345); + + /// Function header + void thresh_callback(int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + + /// Convert image to gray and blur it + cvtColor( src, src_gray, CV_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); + + /// Create Window + char* source_window = "Source"; + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function thresh_callback */ + void thresh_callback(int, void* ) + { + Mat canny_output; + vector > contours; + vector hierarchy; + + /// Detect edges using canny + Canny( src_gray, canny_output, thresh, thresh*2, 3 ); + /// Find contours + findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); + + /// Draw contours + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + for( int i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); + } + + /// Show in a window + namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); + imshow( "Contours", drawing ); + } + +Explanation +============ + +Result +====== + +#. Here it is: + + ============= ============= + |contour_0| |contour_1| + ============= ============= + + .. |contour_0| image:: images/Find_Contours_Original_Image.jpg + :align: middle + + .. |contour_1| image:: images/Find_Contours_Result.jpg + :align: middle + diff --git a/doc/tutorials/imgproc/shapedescriptors/find_contours/images/Find_Contours_Original_Image.jpg b/doc/tutorials/imgproc/shapedescriptors/find_contours/images/Find_Contours_Original_Image.jpg new file mode 100644 index 0000000000..0372edad81 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/find_contours/images/Find_Contours_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/find_contours/images/Find_Contours_Result.jpg b/doc/tutorials/imgproc/shapedescriptors/find_contours/images/Find_Contours_Result.jpg new file mode 100644 index 0000000000..953eeabf92 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/find_contours/images/Find_Contours_Result.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/hull/hull.rst b/doc/tutorials/imgproc/shapedescriptors/hull/hull.rst new file mode 100644 index 0000000000..b47125a24b --- /dev/null +++ b/doc/tutorials/imgproc/shapedescriptors/hull/hull.rst @@ -0,0 +1,116 @@ +.. _hull: + +Convex Hull +*********** + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :convex_hull:`convexHull <>` + + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + Mat src; Mat src_gray; + int thresh = 100; + int max_thresh = 255; + RNG rng(12345); + + /// Function header + void thresh_callback(int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + + /// Convert image to gray and blur it + cvtColor( src, src_gray, CV_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); + + /// Create Window + char* source_window = "Source"; + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function thresh_callback */ + void thresh_callback(int, void* ) + { + Mat src_copy = src.clone(); + Mat threshold_output; + vector > contours; + vector hierarchy; + + /// Detect edges using Threshold + threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); + + /// Find contours + findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); + + /// Find the convex hull object for each contour + vector >hull( contours.size() ); + for( int i = 0; i < contours.size(); i++ ) + { convexHull( Mat(contours[i]), hull[i], false ); } + + /// Draw contours + hull results + Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); + for( int i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + drawContours( drawing, contours, i, color, 1, 8, vector(), 0, Point() ); + drawContours( drawing, hull, i, color, 1, 8, vector(), 0, Point() ); + } + + /// Show in a window + namedWindow( "Hull demo", CV_WINDOW_AUTOSIZE ); + imshow( "Hull demo", drawing ); + } + + +Explanation +============ + +Result +====== + +#. Here it is: + + ========== ========== + |Hull_0| |Hull_1| + ========== ========== + + .. |Hull_0| image:: images/Hull_Original_Image.jpg + :align: middle + + .. |Hull_1| image:: images/Hull_Result.jpg + :align: middle + diff --git a/doc/tutorials/imgproc/shapedescriptors/hull/images/Hull_Original_Image.jpg b/doc/tutorials/imgproc/shapedescriptors/hull/images/Hull_Original_Image.jpg new file mode 100644 index 0000000000..8b3f0d34a2 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/hull/images/Hull_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/hull/images/Hull_Result.jpg b/doc/tutorials/imgproc/shapedescriptors/hull/images/Hull_Result.jpg new file mode 100644 index 0000000000..16ca49c01d Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/hull/images/Hull_Result.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Result1.jpg b/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Result1.jpg new file mode 100644 index 0000000000..1e8112a3fb Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Result1.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Result2.jpg b/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Result2.jpg new file mode 100644 index 0000000000..d63de9a099 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Result2.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Source_Image.jpg b/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Source_Image.jpg new file mode 100644 index 0000000000..f285fdbfd3 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/moments/images/Moments_Source_Image.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/moments.rst b/doc/tutorials/imgproc/shapedescriptors/moments/moments.rst new file mode 100644 index 0000000000..8224a08e1a --- /dev/null +++ b/doc/tutorials/imgproc/shapedescriptors/moments/moments.rst @@ -0,0 +1,136 @@ +.. _moments: + + +Image Moments +************** + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :moments:`moments <>` + * Use the OpenCV function :contour_area:`contourArea <>` + * Use the OpenCV function :arc_length:`arcLength <>` + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + Mat src; Mat src_gray; + int thresh = 100; + int max_thresh = 255; + RNG rng(12345); + + /// Function header + void thresh_callback(int, void* ); + + /** @function main */ + int main( int argc, char** argv ) + { + /// Load source image and convert it to gray + src = imread( argv[1], 1 ); + + /// Convert image to gray and blur it + cvtColor( src, src_gray, CV_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); + + /// Create Window + char* source_window = "Source"; + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + + createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); + + waitKey(0); + return(0); + } + + /** @function thresh_callback */ + void thresh_callback(int, void* ) + { + Mat canny_output; + vector > contours; + vector hierarchy; + + /// Detect edges using canny + Canny( src_gray, canny_output, thresh, thresh*2, 3 ); + /// Find contours + findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); + + /// Get the moments + vector mu(contours.size() ); + for( int i = 0; i < contours.size(); i++ ) + { mu[i] = moments( contours[i], false ); } + + /// Get the mass centers: + vector mc( contours.size() ); + for( int i = 0; i < contours.size(); i++ ) + { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); } + + /// Draw contours + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + for( int i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); + circle( drawing, mc[i], 4, color, -1, 8, 0 ); + } + + /// Show in a window + namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); + imshow( "Contours", drawing ); + + /// Calculate the area with the moments 00 and compare with the result of the OpenCV function + printf("\t Info: Area and Contour Length \n"); + for( int i = 0; i< contours.size(); i++ ) + { + printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) ); + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); + circle( drawing, mc[i], 4, color, -1, 8, 0 ); + } + } + +Explanation +============ + +Result +====== + +#. Here it is: + + ========== ========== ========== + |MU_0| |MU_1| |MU_2| + ========== ========== ========== + + .. |MU_0| image:: images/Moments_Source_Image.jpg + :width: 250pt + :align: middle + + .. |MU_1| image:: images/Moments_Result1.jpg + :width: 250pt + :align: middle + + .. |MU_2| image:: images/Moments_Result2.jpg + :width: 250pt + :align: middle + diff --git a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/images/Point_Polygon_Test_Result.jpg b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/images/Point_Polygon_Test_Result.jpg new file mode 100644 index 0000000000..e420f472ea Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/images/Point_Polygon_Test_Result.jpg differ diff --git a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/images/Point_Polygon_Test_Source_Image.png b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/images/Point_Polygon_Test_Source_Image.png new file mode 100644 index 0000000000..87bf5d2100 Binary files /dev/null and b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/images/Point_Polygon_Test_Source_Image.png differ diff --git a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.rst b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.rst new file mode 100644 index 0000000000..f3fa84c542 --- /dev/null +++ b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.rst @@ -0,0 +1,117 @@ +.. _point_polygon_test: + +Point Polygon Test +******************* + +Goal +===== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + * Use the OpenCV function :point_polygon_test:`pointPolygonTest <>` + + +Theory +====== + +Code +==== + +This tutorial code's is shown lines below. You can also download it from `here `_ + +.. code-block:: cpp + + #include "opencv2/highgui/highgui.hpp" + #include "opencv2/imgproc/imgproc.hpp" + #include + #include + #include + + using namespace cv; + using namespace std; + + /** @function main */ + int main( int argc, char** argv ) + { + /// Create an image + const int r = 100; + Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8UC1 ); + + /// Create a sequence of points to make a contour: + vector vert(6); + + vert[0] = Point( 1.5*r, 1.34*r ); + vert[1] = Point( 1*r, 2*r ); + vert[2] = Point( 1.5*r, 2.866*r ); + vert[3] = Point( 2.5*r, 2.866*r ); + vert[4] = Point( 3*r, 2*r ); + vert[5] = Point( 2.5*r, 1.34*r ); + + /// Draw it in src + for( int j = 0; j < 6; j++ ) + { line( src, vert[j], vert[(j+1)%6], Scalar( 255 ), 3, 8 ); } + + /// Get the contours + vector > contours; vector hierarchy; + Mat src_copy = src.clone(); + + findContours( src_copy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); + + /// Calculate the distances to the contour + Mat raw_dist( src.size(), CV_32FC1 ); + + for( int j = 0; j < src.rows; j++ ) + { for( int i = 0; i < src.cols; i++ ) + { raw_dist.at(j,i) = pointPolygonTest( contours[0], Point2f(i,j), true ); } + } + + double minVal; double maxVal; + minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() ); + minVal = abs(minVal); maxVal = abs(maxVal); + + /// Depicting the distances graphically + Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); + + for( int j = 0; j < src.rows; j++ ) + { for( int i = 0; i < src.cols; i++ ) + { + if( raw_dist.at(j,i) < 0 ) + { drawing.at(j,i)[0] = 255 - (int) abs(raw_dist.at(j,i))*255/minVal; } + else if( raw_dist.at(j,i) > 0 ) + { drawing.at(j,i)[2] = 255 - (int) raw_dist.at(j,i)*255/maxVal; } + else + { drawing.at(j,i)[0] = 255; drawing.at(j,i)[1] = 255; drawing.at(j,i)[2] = 255; } + } + } + + /// Create Window and show your results + char* source_window = "Source"; + namedWindow( source_window, CV_WINDOW_AUTOSIZE ); + imshow( source_window, src ); + namedWindow( "Distance", CV_WINDOW_AUTOSIZE ); + imshow( "Distance", drawing ); + + waitKey(0); + return(0); + } + +Explanation +============ + +Result +====== + +#. Here it is: + + ========== ========== + |PPT_0| |PPT_1| + ========== ========== + + .. |PPT_0| image:: images/Point_Polygon_Test_Source_Image.png + :align: middle + + .. |PPT_1| image:: images/Point_Polygon_Test_Result.jpg + :align: middle + diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.jpg new file mode 100644 index 0000000000..67da3a5ac0 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.png deleted file mode 100644 index 2f9b038058..0000000000 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.jpg new file mode 100644 index 0000000000..b3a1c55659 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.png deleted file mode 100644 index 6e6aed9aa2..0000000000 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.jpg new file mode 100644 index 0000000000..0851cab278 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.png deleted file mode 100644 index 2fbee16bef..0000000000 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.jpg new file mode 100644 index 0000000000..67656ab4b3 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.png deleted file mode 100644 index f05676b4bf..0000000000 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.jpg new file mode 100644 index 0000000000..6b115d88f5 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.png b/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.png deleted file mode 100644 index 015e8c330b..0000000000 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg new file mode 100644 index 0000000000..013bdf6f2f Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg new file mode 100644 index 0000000000..32d09e37e8 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg new file mode 100644 index 0000000000..7538a7203d Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg new file mode 100644 index 0000000000..fbc5866835 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg new file mode 100644 index 0000000000..e84f52119a Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg index bbddc716f6..bcd9ff9ace 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg index 5e91f407fa..f241ff2238 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg index eb02934d38..c2f5809108 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg index 2a599fc6ca..175180ae81 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg index a6107b02b5..4211ee2629 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg index 2354d9a5db..14373f25b1 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg new file mode 100644 index 0000000000..bfb55dbdac Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg index ead594e5eb..fbe17c8978 100644 Binary files a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg new file mode 100644 index 0000000000..5655789bd6 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg new file mode 100644 index 0000000000..be2ae57d40 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg new file mode 100644 index 0000000000..b7330592b5 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg new file mode 100644 index 0000000000..82888a1ba9 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg new file mode 100644 index 0000000000..a7a1b6ebeb Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg new file mode 100644 index 0000000000..1e865eb371 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg new file mode 100644 index 0000000000..9980df8421 Binary files /dev/null and b/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst b/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst index ded5264c02..80ee5b7055 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst +++ b/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst @@ -5,57 +5,54 @@ In this section you will learn about the image processing (manipulation) functions inside OpenCV. -.. toctree:: - :hidden: - - ../gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter - ../erosion_dilatation/erosion_dilatation - ../opening_closing_hats/opening_closing_hats - ../pyramids/pyramids - ../threshold/threshold +.. include:: ../../definitions/tocDefinitions.rst -.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n - -* :ref:`Smoothing` + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv ===================== ============================================== - |ImageProcessing_1| *Title:* **Smoothing Images** - + |ImageProcessing_1| **Title:** :ref:`Smoothing` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| Let's take a look at some basic linear filters! - + ===================== ============================================== - - .. |ImageProcessing_1| image:: images/Smoothing_Tutorial_Cover.png - :height: 100pt - :width: 100pt - - -* :ref:`Morphology_1` + + .. |ImageProcessing_1| image:: images/Smoothing_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv ===================== ============================================== - |ImageProcessing_2| *Title:* **Erosion and Dilation** - + |ImageProcessing_2| **Title:** :ref:`Morphology_1` + *Compatibility:* > OpenCV 2.0 Author: |Author_AnaH| - + Let's *change* the shape of objects! - + ===================== ============================================== - - .. |ImageProcessing_2| image:: images/Morphology_1_Tutorial_Cover.png - :height: 100pt - :width: 100pt - -* :ref:`Morphology_2` + + .. |ImageProcessing_2| image:: images/Morphology_1_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv ================= ================================================== - |Morphology_2| *Title:* **More advanced Morphology Transformations** - + |Morphology_2| **Title:** :ref:`Morphology_2` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| @@ -64,171 +61,484 @@ In this section you will learn about the image processing (manipulation) functio ================= ================================================== - .. |Morphology_2| image:: images/Morphology_2_Tutorial_Cover.png - :height: 100pt - :width: 100pt - - -* :ref:`Pyramids` + .. |Morphology_2| image:: images/Morphology_2_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |Pyramids| *Title:* **Image Pyramids** - + |Pyramids| **Title:** :ref:`Pyramids` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + What if I need a bigger/smaller image? - - ===================== ============================================== - - .. |Pyramids| image:: images/Pyramids_Tutorial_Cover.png - :height: 100pt - :width: 100pt - - -* :ref:`Basic_Threshold` - - ===================== ============================================== - |Threshold| *Title:* **Basic Thresholding Operations** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - After so much processing, it is time to decide which pixels stay! - + ===================== ============================================== - .. |Threshold| image:: images/Threshold_Tutorial_Cover.png - :height: 100pt - :width: 100pt - -.. ************************ -.. ImgTrans -.. ************************ - -* :ref:`filter_2d` + .. |Pyramids| image:: images/Pyramids_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |Filter_2D| *Title:* **Making your own linear filters** - + |Threshold| **Title:** :ref:`Basic_Threshold` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + + After so much processing, it is time to decide which pixels stay! + + ===================== ============================================== + + .. |Threshold| image:: images/Threshold_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ++ + ===================== ============================================== + |Filter_2D| **Title:** :ref:`filter_2d` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + Where we learn to design our own filters by using OpenCV functions - + ===================== ============================================== .. |Filter_2D| image:: images/imgtrans/Filter_2D_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt - - -* :ref:`copyMakeBorder` - + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ++ ===================== ============================================== - |CopyMakeBorder| *Title:* **Adding borders to your images** - + |CopyMakeBorder| **Title:** :ref:`copyMakeBorderTutorial` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + Where we learn how to pad our images! - + ===================== ============================================== .. |CopyMakeBorder| image:: images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt - - -* :ref:`sobel_derivatives` + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |SobelDerivatives| *Title:* **Sobel Derivatives** - + |SobelDerivatives| **Title:** :ref:`sobel_derivatives` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + Where we learn how to calculate gradients and use them to detect edges! - + ===================== ============================================== .. |SobelDerivatives| image:: images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt - -* :ref:`laplace_operator` + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |LaplaceOperator| *Title:* **Laplace Operator** - + |LaplaceOperator| **Title:** :ref:`laplace_operator` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + Where we learn about the *Laplace* operator and how to detect edges with it. - + ===================== ============================================== .. |LaplaceOperator| image:: images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt - - -* :ref:`canny_detector` + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |CannyDetector| *Title:* **Canny Edge Detector** - + |CannyDetector| **Title:** :ref:`canny_detector` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + Where we learn a sophisticated alternative to detect edges. - + ===================== ============================================== .. |CannyDetector| image:: images/imgtrans/Canny_Detector_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt - - -* :ref:`hough_lines` + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |HoughLines| *Title:* **Hough Line Transform** - + |HoughLines| **Title:** :ref:`hough_lines` + *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - + Where we learn how to detect lines - + ===================== ============================================== .. |HoughLines| image:: images/imgtrans/Hough_Lines_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt - - -* :ref:`hough_circle` + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + ===================== ============================================== - |HoughCircle| *Title:* **Hough Circle Transform** + |HoughCircle| **Title:** :ref:`hough_circle` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to detect circles + + ===================== ============================================== + + .. |HoughCircle| image:: images/imgtrans/Hough_Circle_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |Remap| **Title:** :ref:`remap` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to manipulate pixels locations + + ===================== ============================================== + + .. |Remap| image:: images/imgtrans/Remap_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |WarpAffine| **Title:** :ref:`warp_affine` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to rotate, translate and scale our images + + ===================== ============================================== + + .. |WarpAffine| image:: images/imgtrans/Warp_Affine_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |HistEqualization| **Title:** :ref:`histogram_equalization` *Compatibility:* > OpenCV 2.0 *Author:* |Author_AnaH| - Where we learn how to detect circles + Where we learn how to improve the contrast in our images ===================== ============================================== - .. |HoughCircle| image:: images/imgtrans/Hough_Circle_Tutorial_Cover.jpg - :height: 100pt - :width: 100pt + .. |HistEqualization| image:: images/histograms/Histogram_Equalization_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |HistCalculation| **Title:** :ref:`histogram_calculation` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to create and generate histograms + + ===================== ============================================== + + .. |HistCalculation| image:: images/histograms/Histogram_Calculation_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |HistComparison| **Title:** :ref:`histogram_comparison` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn to calculate metrics between histograms + + ===================== ============================================== + + .. |HistComparison| image:: images/histograms/Histogram_Comparison_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |BackProjection| **Title:** :ref:`back_projection` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to use histograms to find similar objects in images + + ===================== ============================================== + + .. |BackProjection| image:: images/histograms/Back_Projection_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |TemplateMatching| **Title:** :ref:`template_matching` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to match templates in an image + + ===================== ============================================== + + .. |TemplateMatching| image:: images/histograms/Template_Matching_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |FindContours| **Title:** :ref:`find_contours` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to find contours of objects in our image + + ===================== ============================================== + + .. |FindContours| image:: images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |Hull| **Title:** :ref:`hull` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to get hull contours and draw them! + + ===================== ============================================== + + .. |Hull| image:: images/shapedescriptors/Hull_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ===================== ============================================== + |BRC| **Title:** :ref:`bounding_rects_circles` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to obtain bounding boxes and circles for our contours. + + ===================== ============================================== + + .. |BRC| image:: images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + + ===================== ============================================== + |BRE| **Title:** :ref:`bounding_rotated_ellipses` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to obtain rotated bounding boxes and ellipses for our contours. + + ===================== ============================================== + + .. |BRE| image:: images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + + ===================== ============================================== + |MU| **Title:** :ref:`moments` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn to calculate the moments of an image + + ===================== ============================================== + + .. |MU| image:: images/shapedescriptors/Moments_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + + ++ + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + + ===================== ============================================== + |PPT| **Title:** :ref:`point_polygon_test` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + Where we learn how to calculate distances from the image to contours + + ===================== ============================================== + + .. |PPT| image:: images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg + :height: 90pt + :width: 90pt + +.. raw:: latex + + \pagebreak + +.. toctree:: + :hidden: + + ../gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter + ../erosion_dilatation/erosion_dilatation + ../opening_closing_hats/opening_closing_hats + ../pyramids/pyramids + ../threshold/threshold + ../imgtrans/filter_2d/filter_2d + ../imgtrans/copyMakeBorder/copyMakeBorder + ../imgtrans/sobel_derivatives/sobel_derivatives + ../imgtrans/laplace_operator/laplace_operator + ../imgtrans/canny_detector/canny_detector + ../imgtrans/hough_lines/hough_lines + ../imgtrans/hough_circle/hough_circle + ../imgtrans/remap/remap + ../imgtrans/warp_affine/warp_affine + ../histograms/histogram_equalization/histogram_equalization + ../histograms/histogram_calculation/histogram_calculation + ../histograms/histogram_comparison/histogram_comparison + ../histograms/back_projection/back_projection + ../histograms/template_matching/template_matching + ../shapedescriptors/find_contours/find_contours + ../shapedescriptors/hull/hull + ../shapedescriptors/bounding_rects_circles/bounding_rects_circles + ../shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses + ../shapedescriptors/moments/moments + ../shapedescriptors/point_polygon_test/point_polygon_test + + diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.jpg b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.jpg new file mode 100644 index 0000000000..82a12d28e4 Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.jpg differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.png deleted file mode 100644 index e0161bd119..0000000000 Binary files a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Cover.png and /dev/null differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.jpg b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.jpg new file mode 100644 index 0000000000..7aaa61dc6d Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.jpg differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.png deleted file mode 100644 index ddf66816f5..0000000000 Binary files a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Original_Image.png and /dev/null differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.jpg b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.jpg new file mode 100644 index 0000000000..7f6ee08aaf Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.jpg differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.png deleted file mode 100644 index 72e36fa405..0000000000 Binary files a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Binary_Inverted.png and /dev/null differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.jpg b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.jpg new file mode 100644 index 0000000000..ea3039bfee Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.jpg differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.png deleted file mode 100644 index ce1bfeb7f1..0000000000 Binary files a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Result_Zero.png and /dev/null differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png index cfd7cc395d..1962a8c1c7 100644 Binary files a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Binary_Inverted.png differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.jpg b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.jpg new file mode 100644 index 0000000000..73112e110b Binary files /dev/null and b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.jpg differ diff --git a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.png b/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.png deleted file mode 100644 index e834992341..0000000000 Binary files a/doc/tutorials/imgproc/threshold/images/Threshold_Tutorial_Theory_Example.png and /dev/null differ diff --git a/doc/tutorials/imgproc/threshold/threshold.rst b/doc/tutorials/imgproc/threshold/threshold.rst index 1db97811a5..1ac4919bd0 100644 --- a/doc/tutorials/imgproc/threshold/threshold.rst +++ b/doc/tutorials/imgproc/threshold/threshold.rst @@ -28,9 +28,8 @@ What is Thresholding? * Once we have separated properly the important pixels, we can set them with a determined value to identify them (i.e. we can assign them a value of :math:`0` (black), :math:`255` (white) or any value that suits your needs). - .. image:: images/Threshold_Tutorial_Theory_Example.png + .. image:: images/Threshold_Tutorial_Theory_Example.jpg :alt: Threshold simple example - :height: 150pt :align: center Types of Thresholding @@ -44,7 +43,6 @@ Types of Thresholding .. image:: images/Threshold_Tutorial_Theory_Base_Figure.png :alt: Threshold Binary - :height: 100pt :align: center Threshold Binary @@ -60,7 +58,6 @@ Threshold Binary .. image:: images/Threshold_Tutorial_Theory_Binary.png :alt: Threshold Binary - :height: 100pt :align: center @@ -77,7 +74,6 @@ Threshold Binary, Inverted .. image:: images/Threshold_Tutorial_Theory_Binary_Inverted.png :alt: Threshold Binary Inverted - :height: 100pt :align: center Truncate @@ -93,7 +89,6 @@ Truncate .. image:: images/Threshold_Tutorial_Theory_Truncate.png :alt: Threshold Truncate - :height: 100pt :align: center @@ -111,7 +106,6 @@ Threshold to Zero .. image:: images/Threshold_Tutorial_Theory_Zero.png :alt: Threshold Zero - :height: 100pt :align: center @@ -128,7 +122,6 @@ Threshold to Zero, Inverted .. image:: images/Threshold_Tutorial_Theory_Zero_Inverted.png :alt: Threshold Zero Inverted - :height: 100pt :align: center @@ -296,25 +289,20 @@ Results #. After compiling this program, run it giving a path to an image as argument. For instance, for an input image as: - .. image:: images/Threshold_Tutorial_Original_Image.png + .. image:: images/Threshold_Tutorial_Original_Image.jpg :alt: Threshold Original Image - :height: 200pt :align: center #. First, we try to threshold our image with a *binary threhold inverted*. We expect that the pixels brighter than the :math:`thresh` will turn dark, which is what actually happens, as we can see in the snapshot below (notice from the original image, that the doggie's tongue and eyes are particularly bright in comparison with the image, this is reflected in the output image). - .. image:: images/Threshold_Tutorial_Result_Binary_Inverted.png + .. image:: images/Threshold_Tutorial_Result_Binary_Inverted.jpg :alt: Threshold Result Binary Inverted - :height: 200pt :align: center #. Now we try with the *threshold to zero*. With this, we expect that the darkest pixels (below the threshold) will become completely black, whereas the pixels with value greater than the threshold will keep its original value. This is verified by the following snapshot of the output image: - .. image:: images/Threshold_Tutorial_Result_Zero.png + .. image:: images/Threshold_Tutorial_Result_Zero.jpg :alt: Threshold Result Zero - :height: 200pt - :align: center - - + :align: center \ No newline at end of file diff --git a/doc/tutorials/introduction/android_binary_package/android_binary_package.rst b/doc/tutorials/introduction/android_binary_package/android_binary_package.rst new file mode 100644 index 0000000000..e711cb8858 --- /dev/null +++ b/doc/tutorials/introduction/android_binary_package/android_binary_package.rst @@ -0,0 +1,319 @@ + +.. _Android_Binary_Package: + + +Using Android binary package with Eclipse +***************************************** + +This tutorial was tested using Ubuntu 10.04 and Windows 7 SP1 operating systems. Nevertheless, it should also work on any other **OS**\ es supported by Android SDK (including Mac OS X). If you encounter errors after following the steps described here, feel free to contact us via *android-opencv* discussion group https://groups.google.com/group/android-opencv/ and we will try to help you. + +Quick environment setup for Android development +=============================================== + +If you are making a clean environment installation then you can try **T**\ egra **A**\ ndroid **D**\ evelopment **P**\ ack (*TADP*) released by *NVIDIA*: + + http://developer.nvidia.com/tegra-android-development-pack + +It will cover all of the environment set up automatically and you can go to the next step :ref:`Get_the_OpenCV_package_for_Android_development` right after automatic setup. + +If you are a beginner in Android development then we recommentd you to start with TADP. + +.. note:: *NVIDIA*\ 's Tegra Android Development Pack includes some special features for |Nvidia_Tegra_Platform|_ but it is not just for *Tegra* devices + + + You need at least *1.6 Gb* free disk space for installation. + + + TADP will download Android SDK platforms and Android NDK from Google's server, so you need an Internet connection for the installation. + + + TADP can ask you to flash your development kit at the end of installation process. Just skip this step if you have no |Tegra_Ventana_Development_Kit|_\ . + + + (``UNIX``) TADP will ask you for a *root* in the middle of installation, so you need to be a member of *sudo* group. + + .. + + +.. |Nvidia_Tegra_Platform| replace:: *NVIDIA*\ ’s Tegra platform +.. _Nvidia_Tegra_Platform: http://developer.nvidia.com/node/19071 +.. |Tegra_Ventana_Development_Kit| replace:: Tegra Ventana Development Kit +.. _Tegra_Ventana_Development_Kit: http://developer.nvidia.com/tegra-ventana-development-kit + +.. _Android_Environment_Setup_Lite: + +Manual environment setup for Android Development +================================================ + +You need the following tools to be installed: + +#. **Sun JDK 6** + + Visit http://www.oracle.com/technetwork/java/javase/downloads/index.html and download installer for your OS. + + Here is a detailed :abbr:`JDK (Java Development Kit)` installation guide for Ubuntu and Mac OS: http://source.android.com/source/initializing.html#installing-the-jdk (only JDK sections are applicable for OpenCV) + + .. note:: OpenJDK is not usable for Android development because Android SDK supports only Sun JDK. + If you use Ubuntu, after installation of Sun JDK you should run the following command to set Sun java environment: + + .. code-block:: bash + + sudo update-java-alternatives --set java-6-sun + +#. **Android SDK** + + Get the latest Android SDK from http://developer.android.com/sdk/index.html + + Here is Google's install guide for SDK http://developer.android.com/sdk/installing.html + + .. note:: If you choose SDK packed into Windows installer, then you should have 32-bit JRE installed. It is not needed for Android development, but installer is x86 application and requires 32-bit Java runtime. + + .. note:: If you are running x64 version of Ubuntu Linux, then you need ia32 shared libraries for use on amd64 and ia64 systems to be installed. You can install them with the following command: + + .. code-block:: bash + + sudo apt-get install ia32-libs + + For Red Hat based systems the following command might be helpful: + + .. code-block:: bash + + sudo yum install libXtst.i386 + +#. **Android SDK components** + + You need the following SDK components to be installed: + + * *Android SDK Tools, revision12* or newer + + Older revisions should also work, but they are not recommended. + + * *SDK Platform Android 2.2, API 8, revision 2* (also known as *android-8*) + + This is minimal platform supported by OpenCV Java API. And it is set as default for OpenCV distribution. It is possible to use newer platform with OpenCV package, but it requires to edit OpenCV project settings. + + .. image:: images/android_sdk_and_avd_manager.png + :height: 400px + :alt: Android SDK and AVD manager + :align: center + + See `Adding SDK Components + `_ for help with installing/updating SDK components. + +#. **Eclipse IDE** + + Check the `Android SDK System Requirements + `_ document for a list of Eclipse versions that are compatible with the Android SDK. + For OpenCV 2.3.1 we recommend Eclipse 3.7 (Indigo) or Eclipse 3.6 (Helios). They work well for OpenCV under both Windows and Linux. + + If you have no Eclipse installed, you can download it from this location: + + http://www.eclipse.org/downloads/ + +#. **ADT plugin for Eclipse** + + This instruction is copied from http://developer.android.com/sdk/eclipse-adt.html#downloading + . Please, visit that page if you have any troubles with ADT plugin installation. + + Assuming that you have Eclipse IDE installed, as described above, follow these steps to download and install the ADT plugin: + + #. Start Eclipse, then select :menuselection:`Help --> Install New Software...` + #. Click :guilabel:`Add` (in the top-right corner). + #. In the :guilabel:`Add Repository` dialog that appears, enter "ADT Plugin" for the Name and the following URL for the Location: + + https://dl-ssl.google.com/android/eclipse/ + + #. Click :guilabel:`OK` + + .. note:: If you have trouble acquiring the plugin, try using "http" in the Location URL, instead of "https" (https is preferred for security reasons). + + #. In the :guilabel:`Available Software` dialog, select the checkbox next to :guilabel:`Developer Tools` and click :guilabel:`Next`. + #. In the next window, you'll see a list of the tools to be downloaded. Click :guilabel:`Next`. + #. Read and accept the license agreements, then click :guilabel:`Finish`. + + .. note:: If you get a security warning saying that the authenticity or validity of the software can't be established, click :guilabel:`OK`. + + #. When the installation completes, restart Eclipse. + +.. _Get_the_OpenCV_package_for_Android_development: + +Get the OpenCV package for Android development +============================================== + +#. Go to the http://sourceforge.net/projects/opencvlibrary/files/opencv-android/ and download the latest available version. Currently it is |opencv_android_bin_pack_url|_ + +#. Create new folder for Android+OpenCV development. + + .. note:: Better to use a path without spaces in it. Otherwise you will probably have problems with :command:`ndk-build`. + +#. Unpack the OpenCV package into that dir. + + You can unpack it using any popular archiver (for example with |seven_zip|_): + + .. image:: images/android_package_7zip.png + :alt: Exploring OpenCV package with 7-Zip + :align: center + + On Unix you can also use the following command: + + .. code-block:: bash + + tar -jxvf ~/Downloads/OpenCV-2.3.1-android-bin.tar.bz2 + + For this tutorial I have unpacked OpenCV to the :file:`C:\\Work\\android-opencv\\` directory. + +.. |opencv_android_bin_pack| replace:: OpenCV-2.3.1-android-bin.tar.bz2 +.. _opencv_android_bin_pack_url: http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.3.1/OpenCV-2.3.1-android-bin.tar.bz2/download +.. |opencv_android_bin_pack_url| replace:: |opencv_android_bin_pack| +.. |seven_zip| replace:: 7-Zip +.. _seven_zip: http://www.7-zip.org/ + +Open OpenCV library and samples in Eclipse +========================================== + +#. Start the *Eclipse* and choose your workspace location. + + I recommend to start familiarizing yourself with OpenCV for Android from a new clean workspace. So I have chosen my OpenCV package directory for the new workspace: + + .. image:: images/eclipse_1_choose_workspace.png + :alt: Choosing C:\Work\android-opencv\ as workspace location + :align: center + +#. Configure your ADT plugin + + .. important:: ADT plugin settings are workspace-dependent. So you have to repeat this step each time when you create a new workspace. + + Once you have created a new workspace, you have to point the ADT plugin to the Android SDK directory. This setting is stored in workspace metadata, as result this step is required each time when you are creating new workspace for Android development. See `Configuring the ADT Plugin + `_ document for the original instructions from *Google*. + + * Select :menuselection:`Window --> Preferences...` to open the Preferences panel (Mac OS X: :menuselection:`Eclipse --> Preferences`): + + .. image:: images/eclipse_2_window_preferences.png + :height: 400px + :alt: Select Window > Preferences... + :align: center + + * Select :guilabel:`Android` from the left panel. + + You may see a dialog asking whether you want to send usage statistics to *Google*. If so, make your choice and click :guilabel:`Proceed`. You cannot continue with this procedure until you click :guilabel:`Proceed`. + + .. image:: images/eclipse_3_preferences_android.png + :alt: Select Android from the left panel + :align: center + + * For the SDK Location in the main panel, click :guilabel:`Browse...` and locate your Android SDK directory. + + * Click :guilabel:`Apply` button at the bottom right corner of main panel: + + .. image:: images/eclipse_4_locate_sdk.png + :alt: Locate Android SDK + :align: center + + * Click :guilabel:`OK` to close preferences dialog. + +#. Import OpenCV and samples into workspace. + + OpenCV library is packed as a ready-for-use `Android Library Project + `_. You can simply reference it in your projects. + + Each sample included into |opencv_android_bin_pack| is a regular Android project that already references OpenCV library. + Follow next steps to import OpenCV and samples into workspace: + + * Right click on the :guilabel:`Package Explorer` window and choose :guilabel:`Import...` option from the context menu: + + .. image:: images/eclipse_5_import_command.png + :alt: Select Import... from context menu + :align: center + + * In the main panel select :menuselection:`General --> Existing Projects into Workspace` and press :guilabel:`Next` button: + + .. image:: images/eclipse_6_import_existing_projects.png + :alt: General > Existing Projects into Workspace + :align: center + + * For the :guilabel:`Select root directory` in the main panel locate your OpenCV package folder. (If you have created workspace in the package directory, then just click :guilabel:`Browse...` button and instantly close directory choosing dialog with :guilabel:`OK` button!) Eclipse should automatically locate OpenCV library and samples: + + .. image:: images/eclipse_7_select_projects.png + :alt: Locate OpenCV library and samples + :align: center + + * Click :guilabel:`Finish` button to complete the import operation. + + After clicking :guilabel:`Finish` button Eclipse will load all selected projects into workspace. And... will indicate numerous errors: + + .. image:: images/eclipse_8_false_alarm.png + :alt: Confusing Eclipse screen with numerous errors + :align: center + + However **all these errors are only false-alarms**! + + To help Eclipse to understand that there are no any errors choose OpenCV library in :guilabel:`Package Explorer` (left mouse click) and press :kbd:`F5` button on your keyboard. Then choose any sample (except first samples in *Tutorial Base* and *Tutorial Advanced*) and also press :kbd:`F5`. + + After this manipulation Eclipse will rebuild your workspace and error icons will disappear one after another: + + .. image:: images/eclipse_9_errors_dissapearing.png + :alt: After small help Eclipse removes error icons! + :align: center + + Once Eclipse completes build you will have the clean workspace without any build errors: + + .. image:: images/eclipse_10_crystal_clean.png + :alt: OpenCV package imported into Eclipse + :align: center + + .. note:: If you are importing only OpenCV library without samples then instead of second refresh command (:kbd:`F5`) you might need to make :menuselection:`Android Tools --> Fix Project Properties` from project context menu. + +Running OpenCV Samples +====================== + +At this point you should be able to build and run all samples except two from Advanced tutorial (these samples require Android NDK to build working applications, see the next tutorial :ref:`Android_Binary_Package_with_NDK` to learn how to compile them). + +Also I want to note that only ``Tutorial 1 Basic - 0. Android Camera`` and ``Tutorial 1 Basic - 1. Add OpenCV`` samples are able to run on Emulator from Android SDK. Other samples are using OpenCV Native Camera which does not work with emulator. + +.. note:: Latest *Android SDK tools, revision 12* can run ARM v7 OS images but *Google* does not provide such images with SDK. + +Well, running samples from Eclipse is very simple: + +* Connect your device with :command:`adb` tool from Android SDK or create Emulator with camera support. + + * See `Managing Virtual Devices + `_ document for help with Android Emulator. + * See `Using Hardware Devices + `_ for help with real devices (not emulators). + + +* Select project you want to start in :guilabel:`Package Explorer:guilabel:` and just press :kbd:`Ctrl + F11` or select option :menuselection:`Run --> Run` from main menu, or click :guilabel:`Run` button on the toolbar. + + .. note:: Android Emulator can take several minutes to start. So, please, be patient. + +* On the first run Eclipse will ask you how to run your application: + + .. image:: images/eclipse_11_run_as.png + :alt: Run sample as Android Application + :align: center + +* Select the :guilabel:`Android Application` option and click :guilabel:`OK` button. Eclipse will install and run the sample. + + Here is ``Tutorial 1 Basic - 1. Add OpenCV`` sample detecting edges using Canny algorithm from OpenCV: + + .. image:: images/emulator_canny.png + :height: 600px + :alt: Tutorial 1 Basic - 1. Add OpenCV - running Canny + :align: center + + + +How to use OpenCV library project in your application +===================================================== + +If you already have an Android application, you can add a reference to OpenCV and import all its functionality. + +#. First of all you need to have both projects (your app and OpenCV) in a single workspace. + So, open workspace with your application and import the OpenCV project into your workspace as stated above. + +#. Add a reference to OpenCV project. + + Do the right mouse click on your app in Package Explorer, go to :menuselection:`Properties --> Android --> Library --> Add` + and choose the OpenCV library project. + +Whats next? +=========== + +Read the :ref:`Android_Binary_Package_with_NDK` tutorial to learn how add native OpenCV code to your Android project. + diff --git a/doc/tutorials/introduction/android_binary_package/android_binary_package_using_with_NDK.rst b/doc/tutorials/introduction/android_binary_package/android_binary_package_using_with_NDK.rst new file mode 100644 index 0000000000..ef5c917611 --- /dev/null +++ b/doc/tutorials/introduction/android_binary_package/android_binary_package_using_with_NDK.rst @@ -0,0 +1,377 @@ + + +.. _Android_Binary_Package_with_NDK: + + +Using C++ OpenCV code with Android binary package +************************************************* + +The Android way is writing all your code in Java. But somethimes it is not enough and you need to go to a native level and write part of your application in C/C++. +This is important when you already have some computer vision functionality which is written in C++ and uses OpenCV, and you want to use it in your Android application, +but do not want to rewrite the C++ code to Java. +In this case the only way is to use JNI mechanism. +It means, that you should add a class with native methods wrapping your C++ functionality into the Java part of your Android application. + +This tutorial describes a fast way how to create and build Android applications containing OpenCV code written in C++. It shows how to build an application which uses OpenCV inside its JNI calls. + +Please note that before starting this tutorial you should fulfill all the steps, described in the tutorial :ref:`Android_Binary_Package`. + +This tutorial was tested using Ubuntu 10.04 and Windows 7 SP1 operating systems. +Nevertheless, it should also work on Mac OS X. If you encounter errors after following the steps described here, feel free to contact us via *android-opencv* discussion group https://groups.google.com/group/android-opencv/ and we will try to help you. + + +Prerequisites: Setup NDK +======================== + +To compile C++ code for Android platform you need Android **N**\ ative **D**\ evelopment **K**\ it (*NDK*). + +You can get the latest version of NDK from the page http://developer.android.com/sdk/ndk/index.html . + +To install Android NDK just extract the archive to some folder on your computer. (Here is installation instructions on the NDK home page: http://developer.android.com/sdk/ndk/index.html#installing) + +.. note:: Before start you can read official Android NDK documentation which is in the Android NDK archive, in the folder :file:`docs/`. + + The main article about using Android NDK build system you can read in the file :file:`ANDROID-MK.html`. + + Also some additional useful information you can read in the files + :file:`APPLICATION-MK.html`, :file:`NDK-BUILD.html`, and in the files :file:`CPU-ARM-NEON.html`, :file:`CPLUSPLUS-SUPPORT.html`, :file:`PREBUILTS.html`. + +Theory: Android application structure +===================================== + +Usually code of an Android application has the following structure: + ++ :file:`root folder of the project/` + + - :file:`jni/` + + - :file:`libs/` + + - :file:`res/` + + - :file:`src/` + + - :file:`AndroidManifest.xml` + + - :file:`default.properties` + + - :file:`... other files ...` + +where + ++ the :file:`src` folder contains Java code of the application, + ++ the :file:`res` folder contains resources of the application (images, xml files describing UI layout , etc), + ++ the :file:`libs` folder will contain native libraries after successful build, + ++ and the :file:`jni` folder contains C/C++ application source code and NDK's build scripts :file:`Android.mk` and :file:`Application.mk`. + + These scripts control the C++ build process (they are written in Makefile language). + + +Also the root folder should contain the following files + +* :file:`AndroidManifest.xml` file presents essential information about application to the Android system + (name of the Application, name of main application's package, components of the application, required permissions, etc) + + It can be created using Eclipse wizard or :command:`android` tool from Android SDK + +* :file:`default.properties` is a text file containing information about target Android platform and other build details. + + This file is generated by Eclipse or can be created with :command:`android` tool from Android SDK + +.. note:: Both files (:file:`AndroidManifest.xml` and :file:`default.properties`) are required to compile the C++ part of the application (NDK build system uses information from these files). If any of these files does not exist, compile the Java part of the project before the C++ part. + + +Theory: How to build Android application having C++ native part (from command line) +=================================================================================== + +Here is the standard way to compile C++ part of an Android application: + +#. Open console and go to the root folder of Android application + + .. code-block:: bash + + cd / + + .. note:: Alternatively you can go to the folder :file:`jni` of Android project but samples from OpenCV binary package are configured for building from project root level (because of relative path to the OpenCV library). + +#. Run the following command + + .. code-block:: bash + + /ndk-build + + .. note:: If you are working in *cygwin* shell and encounter an error saying that NDK does not find some *cygwin*\ 's path then you might need to define the following environment variable: + + .. code-block:: bash + + export NDK_USE_CYGPATH=1 + +#. After executing this command the C++ part of the source code is compiled. + +After that the Java part of the application can be (re)compiled (using either *Eclipse* or :command:`ant` build tool). + +.. note:: Some parameters can be set for the :command:`ndk-build`: + + **Example 1**: Verbose compilation + + .. code-block:: bash + + /ndk-build V=1 + + **Example 2**: Rebuild all + + .. code-block:: bash + + /ndk-build -B + + +.. _Android_NDK_integration_with_Eclipse: + + +Theory: How to build Android application having C++ native part (from *Eclipse*) +================================================================================ + +There are several possible ways to integrate compilation of C++ code by Android NDK into Eclipse compilation process. We recommend the approach taken from this site: http://mobilepearls.com/labs/ndk-builder-in-eclipse/ + +.. important:: This instructions should be applied for each Android project in *Eclipse* workspace. So if you have 3 projects having C++ part then you need to configure 3 builders. + +Below is an adapted version of this guide: + +#. Navigate to :guilabel:`Package Explorer` window and expand your project having JNI resources. + + If you can not see :file:`libs` folder under this project then you need to create it manually. (It will be required on step 7, but you need to create it before you open project properties.) + +#. Right click on your project in :guilabel:`Package Explorer` window and select :guilabel:`Properties`. + +#. In the :guilabel:`Properties` dialog select :guilabel:`Builders` menu and press the :guilabel:`New...` button: + + .. image:: images/eclipse_builders.png + :alt: Configure builders + :align: center + +#. In the resulting dialog select the :guilabel:`Program` type and press :guilabel:`OK` button: + + .. image:: images/eclipse_builder_types.png + :alt: Choose builder type + :align: center + +#. In the :guilabel:`Main` tab fill the following fields: + + * :guilabel:`Name` - any name for your builder. ("Tutorial 2.1 Builder" in my case.) + + .. note:: This name has to be unique for each project in your workspace. + + * :guilabel:`Location` - full path to :command:`ndk-build` tool. + + + *UNIX* + + Just put full path to :command:`ndk-build` into this filed. Also you can add some options to the :guilabel:`Arguments:guilabel:` fied, for example ``-B`` option. + + + *Cygwin* + + - Instead of path to the :command:`ndk-build` tool you need to put full path to *cygwin*\ 's :program:`bash.exe` location. E.g: :file:`C:\\cygwin\\bin\\bash.exe`. + + - Put full path to :command:`ndk-build` into the :guilabel:`Arguments` field E.g. :file:`C:\\Android\\android-ndk-r6\\ndk-build`. + + - Go to the :guilabel:`Environment` tab and define an environment variable: + + * :envvar:`PATH` - full path to the *cygwin* tools. E.g. :file:`C:\\cygwin\\bin` + + .. image:: images/eclipse_windows_environment.png + :alt: Define environment variables + :align: center + + * :guilabel:`Working Directory` - put path to your project into this field. Instead of hardcoding full path you can click :guilabel:`Browse Workspace...` button and select your project. + + .. image:: images/eclipse_edit_configuration_main.png + :alt: Define environment variables + :align: center + +#. Go to the :guilabel:`Refresh` tab and select both :guilabel:`Refresh resources upon completion` and :guilabel:`Recursively include sub-folders`. + + Next set the :guilabel:`Specific resources` option and click :guilabel:`Specify resources...` button: + + .. image:: images/eclipse_edit_configuration_refresh.png + :alt: Define environment variables + :align: center + +#. Select :file:`libs` folder under your project and click :guilabel:`Finish`: + + .. image:: images/eclipse_edit_configuration_specify_resources.png + :alt: Select resources folder to refresh automatically + :align: center + +#. Go to the last tab :guilabel:`Build options`. Make sure that all checkboxes are set as shown on the next screen: + + .. image:: images/eclipse_edit_configuration_build_options.png + :alt: Configure build options + :align: center + +#. Next, click the :guilabel:`Specify resources...` button. + +#. Select :file:`jni` folder of your project and click the :guilabel:`Finish` button: + + .. image:: images/eclipse_edit_configuration_build_resources.png + :alt: Select resources to build + :align: center + +#. Finally press :guilabel:`OK` in the builder configuration and project properties dialogs. If you have automatic build turned on then console showing build log should appear: + + .. image:: images/eclipse_NDK_build_success.png + :alt: Select resources to build + :align: center + +Theory: The structure of :file:`Android.mk` and :file:`Application.mk` scripts +============================================================================== + +The script :file:`Android.mk` usually have the following structure: + +.. code-block:: make + + LOCAL_PATH := $(call my-dir) + + include $(CLEAR_VARS) + LOCAL_MODULE := + LOCAL_SRC_FILES := + := + ... + := + + include $(BUILD_SHARED_LIBRARY) + +This is the minimal file :file:`Android.mk`, which builds a C++ source code of an Android application. Note that the first two lines and the last line are mandatory for any :file:`Android.mk`. + +Usually the file :file:`Application.mk` is optional, but in case of project using OpenCV, when STL and exceptions are used in C++, it also should be written. Example of the file :file:`Application.mk`: + +.. code-block:: make + + APP_STL := gnustl_static + APP_CPPFLAGS := -frtti -fexceptions + APP_ABI := armeabi-v7a + +Practice: Build samples from OpenCV binary package +================================================== + +OpenCV binary package includes two samples having JNI resources: + +* *Tutorial 2 Advanced - 1. Add Native OpenCV* + + This sample illustrate how you can use OpenCV in C++ but without OpenCV Java API. + +* *Tutorial 2 Advanced - 2. Mix Java+Native OpenCV* + + This sample shows how you can mix OpenCV Java API and native C++ code. + +To build these samples you need to: + +#. Fulfill all the steps, described in the tutorial :ref:`Android_Binary_Package`. + +#. Setup one builder for *"Tutorial 2 Advanced - 1. Add Native OpenCV"* project (as described in :ref:`Android_NDK_integration_with_Eclipse`) + +#. Setup second builder for *"Tutorial 2 Advanced - 2. Mix Java+Native OpenCV"* project (repeat the steps from :ref:`Android_NDK_integration_with_Eclipse`) + +#. Clean these projects (in the main Eclipse menu: :menuselection:`Project --> Clean...`) + +#. Run Eclipse build command (if option :guilabel:`Build Automatically` is not set) + + +Practice: Create an Android application, which uses OpenCV +========================================================== + +To build your own Android application, which uses OpenCV from native part, the following steps should be done: + +#. The archive with OpenCV binary package should be downloaded and extracted to some folder (as example, into the home folder) + +#. We recommend to use an environment variable to specify the location of OpenCV package. Full or relative path hardcoded in :file:`jni/Android.mk` will also work. + + So, the environment variable :envvar:`OPENCV_PACKAGE_DIR` should be defined. + The value of the variable should points to the folder, where the OpenCV package has been extracted. + + + As an example, on *UNIX* you can add add the following line into the hidden file :file:`.bashrc` placed in your home folder: + + .. code-block:: bash + + export OPENCV_PACKAGE_DIR = + + Then relogin (or better reboot your computer). + + .. attention:: without rebooting (or logout) this change might not work. + + If you are a *Windows* user, then navigate to: + + * *Windows 7 / Windows Vista* + + :menuselection:`My Computer (Right Click on Icon) --> Properties (Link) --> Advanced System Settings (Link) --> Advanced (Tab) --> Environment Variables (Button) --> System variables (Section)` + + * *Windows XP* + + :menuselection:`My Computer (Right Click on Icon) --> Properties (Link) --> Advanced (Tab) --> Environment Variables (Button) --> System variables (Section)` + + Create new variable :envvar:`OPENCV_PACKAGE_DIR` and similarly to *UNIX* relogin or reboot. + + If you are setting NDK builder as described above in :ref:`Android_NDK_integration_with_Eclipse`, then you can define this variable in builder settings. It can be done on third :guilabel:`Environment` tab of the builder configuration window (we have already added some variables to this tab on *Windows* but skipped it for other platforms). + +#. The file :file:`jni/Android.mk` should be written for the current application using the common rules for the file. + + For detailed information see the Android NDK documentation from the Android NDK archive, in the file + :file:`/docs/ANDROID-MK.html` + +#. The line + + .. code-block:: make + + include $(OPENCV_PACKAGE_DIR)/share/OpenCV/OpenCV.mk + + should be inserted into the :file:`jni/Android.mk` file right after the line + + .. code-block:: make + + include $(CLEAR_VARS) + + .. note:: If your application utilize both native (C++) OpenCV and its Java API you need to put the following line before including :file:`OpenCV.mk` to avoid conflict between C++ and Java builders: + + .. code-block:: make + + OPENCV_CAMERA_MODULES:=off + +#. The file :file:`Application.mk` should exist and should contain lines + + .. code-block:: make + + APP_STL := gnustl_static + APP_CPPFLAGS := -frtti -fexceptions + + Also the line + + .. code-block:: make + + APP_ABI := armeabi-v7a + + is recommended for the applications targeting modern ARMs + +#. To build the C++ code the Android NDK script :command:`ndk-build` should be run in the root directory of application. + Then the C++ source code using OpenCV will be built by Android NDK build system. + After that the Java part of the application can be rebuild and the application can be installed on an Android device. + + Note that this step requires calling the :command:`ndk-build` script from the console. Instead of this step you can use integration of Android NDK into Eclipse + as stated above in the section :ref:`Android_NDK_integration_with_Eclipse` . + + +Additional C++ support in Eclipse +================================== + +Note that you can install additional C++ plugins in Eclipse: + +#. Open :guilabel:`Help / Install New Software`. This shows the :guilabel:`Install` dialog. + +#. In the :guilabel:`Work with` drop-down list choose :guilabel:`Helios - http://download.eclipse.org/releases/helios` (or :guilabel:`Indigo - http://download.eclipse.org/releases/indigo` depending on your Eclipse version) and wait while the list of available software is loaded. + +#. From the list of available software select :menuselection:`Programming Languages --> C/C++ Development Tools`. + +#. Click :guilabel:`Next`, click :guilabel:`Next` again, accept the agreement, and click the :guilabel:`Finish` button. + +#. When installation is finished, click :guilabel:`Reload` diff --git a/doc/tutorials/introduction/android_binary_package/images/android_package_7zip.png b/doc/tutorials/introduction/android_binary_package/images/android_package_7zip.png new file mode 100644 index 0000000000..7de853b88e Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/android_package_7zip.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/android_sdk_and_avd_manager.png b/doc/tutorials/introduction/android_binary_package/images/android_sdk_and_avd_manager.png new file mode 100644 index 0000000000..dd47b4714d Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/android_sdk_and_avd_manager.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_10_crystal_clean.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_10_crystal_clean.png new file mode 100644 index 0000000000..3cc22df89e Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_10_crystal_clean.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_11_run_as.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_11_run_as.png new file mode 100644 index 0000000000..af3582aa19 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_11_run_as.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_1_choose_workspace.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_1_choose_workspace.png new file mode 100644 index 0000000000..ad7384e096 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_1_choose_workspace.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_2_window_preferences.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_2_window_preferences.png new file mode 100644 index 0000000000..de75dd02e1 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_2_window_preferences.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_3_preferences_android.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_3_preferences_android.png new file mode 100644 index 0000000000..93f7038e2a Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_3_preferences_android.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_4_locate_sdk.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_4_locate_sdk.png new file mode 100644 index 0000000000..eb8a347cb1 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_4_locate_sdk.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_5_import_command.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_5_import_command.png new file mode 100644 index 0000000000..9827b92d51 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_5_import_command.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_6_import_existing_projects.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_6_import_existing_projects.png new file mode 100644 index 0000000000..7f9a358ea7 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_6_import_existing_projects.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_7_select_projects.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_7_select_projects.png new file mode 100644 index 0000000000..69cddec4dd Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_7_select_projects.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_8_false_alarm.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_8_false_alarm.png new file mode 100644 index 0000000000..3dff24a22f Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_8_false_alarm.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_9_errors_dissapearing.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_9_errors_dissapearing.png new file mode 100644 index 0000000000..7dadcbc39f Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_9_errors_dissapearing.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_NDK_build_success.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_NDK_build_success.png new file mode 100644 index 0000000000..0bf2a85287 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_NDK_build_success.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_builder_types.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_builder_types.png new file mode 100644 index 0000000000..61673a3699 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_builder_types.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_builders.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_builders.png new file mode 100644 index 0000000000..69d90d839d Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_builders.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_build_options.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_build_options.png new file mode 100644 index 0000000000..9a4683d5bf Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_build_options.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_build_resources.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_build_resources.png new file mode 100644 index 0000000000..9c3480ea76 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_build_resources.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_main.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_main.png new file mode 100644 index 0000000000..4c3bea0c86 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_main.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_refresh.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_refresh.png new file mode 100644 index 0000000000..4e36593b98 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_refresh.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_specify_resources.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_specify_resources.png new file mode 100644 index 0000000000..bce08a8831 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_edit_configuration_specify_resources.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_windows_environment.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_windows_environment.png new file mode 100644 index 0000000000..5deced55c9 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/eclipse_windows_environment.png differ diff --git a/doc/tutorials/introduction/android_binary_package/images/emulator_canny.png b/doc/tutorials/introduction/android_binary_package/images/emulator_canny.png new file mode 100644 index 0000000000..24f2b98c17 Binary files /dev/null and b/doc/tutorials/introduction/android_binary_package/images/emulator_canny.png differ diff --git a/doc/tutorials/introduction/display_image/display_image.rst b/doc/tutorials/introduction/display_image/display_image.rst index 72fe5c1767..a8be339867 100644 --- a/doc/tutorials/introduction/display_image/display_image.rst +++ b/doc/tutorials/introduction/display_image/display_image.rst @@ -1,112 +1,127 @@ .. _Display_Image: -Display an Image -***************** +Load and Display an Image +************************* Goal ===== In this tutorial you will learn how to: -* Load an image using :imread:`imread <>` -* Create a named window (using :named_window:`namedWindow <>`) -* Display an image in an OpenCV window (using :imshow:`imshow <>`) +.. container:: enumeratevisibleitemswithsquare + + * Load an image (using :imread:`imread <>`) + * Create a named OpenCV window (using :named_window:`namedWindow <>`) + * Display an image in an OpenCV window (using :imshow:`imshow <>`) -Code -===== +Source Code +=========== -Here it is: - -.. code-block:: cpp - - #include - #include - - using namespace cv; - - int main( int argc, char** argv ) - { - Mat image; - image = imread( argv[1], 1 ); - - if( argc != 2 || !image.data ) - { - printf( "No image data \n" ); - return -1; - } - - namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); - imshow( "Display Image", image ); - - waitKey(0); - - return 0; - } +Download the :download:`source code from here <../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp>` or look it up in our library at :file:`samples/cpp/tutorial_code/introduction/display_image/display_image.cpp`. +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :tab-width: 4 + :linenos: Explanation ============ -#. .. code-block:: cpp +In OpenCV 2 we have multiple modules. Each one takes care of a different area or approach towards image processing. You could already observe this in the structure of the user guide of these tutorials itself. Before you use any of them you first need to include the header files where the content of each individual module is declared. - #include - #include - - using namespace cv; +You'll almost always end up using the: - These are OpenCV headers: +.. container:: enumeratevisibleitemswithsquare - * *cv.h* : Main OpenCV functions - * *highgui.h* : Graphical User Interface (GUI) functions + + *core* section, as here are defined the basic building blocks of the library + + *highgui* module, as this contains the functions for input and output operations - Now, let's analyze the *main* function: +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/Test.cpp + :language: cpp + :tab-width: 4 + :lines: 1-3 -#. .. code-block:: cpp +We also include the *iostream* to facilitate console line output and input. To avoid data structure and function name conflicts with other libraries, OpenCV has its own namespace: *cv*. To avoid the need appending prior each of these the *cv::* keyword you can import the namespace in the whole file by using the lines: - Mat image; - - We create a Mat object to store the data of the image to load. +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :tab-width: 4 + :lines: 5-6 -#. .. code-block:: cpp - - image = imread( argv[1], 1 ); +This is true for the STL library too (used for console I/O). Now, let's analyze the *main* function. We start up assuring that we acquire a valid image name argument from the command line. - Here, we called the function :imread:`imread <>` which basically loads the image specified by the first argument (in this case *argv[1]*). The second argument is by default. +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :tab-width: 4 + :lines: 10-14 -#. After checking that the image data was loaded correctly, we want to display our image, so we create a window: +Then create a *Mat* object that will store the data of the loaded image. - .. code-block:: cpp +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :tab-width: 4 + :lines: 16 - namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); +Now we call the :imread:`imread <>` function which loads the image name specified by the first argument (*argv[1]*). The second argument specifies the format in what we want the image. This may be: +.. container:: enumeratevisibleitemswithsquare - :named_window:`namedWindow <>` receives as arguments the window name ("Display Image") and an additional argument that defines windows properties. In this case **CV_WINDOW_AUTOSIZE** indicates that the window will adopt the size of the image to be displayed. + + CV_LOAD_IMAGE_UNCHANGED (<0) loads the image as is (including the alpha channel if present) + + CV_LOAD_IMAGE_GRAYSCALE ( 0) loads the image as an intensity one + + CV_LOAD_IMAGE_COLOR (>0) loads the image in the RGB format -#. Finally, it is time to show the image, for this we use :imshow:`imshow <>` +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :tab-width: 4 + :lines: 17 - .. code-block:: cpp - - imshow( "Display Image", image ) +.. note:: -#. Finally, we want our window to be displayed until the user presses a key (otherwise the program would end far too quickly): + OpenCV offers support for the image formats Windows bitmap (bmp), portable image formats (pbm, pgm, ppm) and Sun raster (sr, ras). With help of plugins (you need to specify to use them if you build yourself the library, nevertheless in the packages we ship present by default) you may also load image formats like JPEG (jpeg, jpg, jpe), JPEG 2000 (jp2 - codenamed in the CMake as Jasper), TIFF files (tiff, tif) and portable network graphics (png). Furthermore, OpenEXR is also a possibility. - .. code-block:: cpp - - waitKey(0); +After checking that the image data was loaded correctly, we want to display our image, so we create an OpenCV window using the :named_window:`namedWindow <>` function. These are automatically managed by OpenCV once you create them. For this you need to specify its name and how it should handle the change of the image it contains from a size point of view. It may be: - We use the :wait_key:`waitKey <>` function, which allow us to wait for a keystroke during a number of milliseconds (determined by the argument). If the argument is zero, then it will wait indefinitely. +.. container:: enumeratevisibleitemswithsquare + + + *CV_WINDOW_AUTOSIZE* is the only supported one if you do not use the Qt backend. In this case the window size will take up the size of the image it shows. No resize permitted! + + *CV_WINDOW_NORMAL* on Qt you may use this to allow window resize. The image will resize itself according to the current window size. By using the | operator you also need to specify if you would like the image to keep its aspect ratio (*CV_WINDOW_KEEPRATIO*) or not (*CV_WINDOW_FREERATIO*). + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :lines: 25 + :tab-width: 4 + +Finally, to update the content of the OpenCV window with a new image use the :imshow:`imshow <>` function. Specify the OpenCV window name to update and the image to use during this operation: + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :lines: 26 + :tab-width: 4 + +Because we want our window to be displayed until the user presses a key (otherwise the program would end far too quickly), we use the :wait_key:`waitKey <>` function whose only parameter is just how long should it wait for a user input (measured in milliseconds). Zero means to wait forever. + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp + :language: cpp + :lines: 28 + :tab-width: 4 Result ======= -* Compile your code and then run the executable giving a image path as argument: +* Compile your code and then run the executable giving an image path as argument. If you're on Windows the executable will of course contain an *exe* extension too. Of course assure the image file is near your program file. .. code-block:: bash - + ./DisplayImage HappyFish.jpg * You should get a nice window as the one shown below: - .. image:: images/Display_Image_Tutorial_Result.png + .. image:: images/Display_Image_Tutorial_Result.jpg :alt: Display Image Tutorial - Final Result :align: center + +.. raw:: html + +
+ +
diff --git a/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.jpg b/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.jpg new file mode 100644 index 0000000000..16400698f0 Binary files /dev/null and b/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.jpg differ diff --git a/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.png b/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.png deleted file mode 100644 index 62e3878e03..0000000000 Binary files a/doc/tutorials/introduction/display_image/images/Display_Image_Tutorial_Result.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-0.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-0.png deleted file mode 100644 index 3ad10d4920..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-0.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-1.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-1.png deleted file mode 100644 index 31c284a1a9..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-1.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-10.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-10.png deleted file mode 100644 index 48bf684ab1..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-10.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-11.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-11.png deleted file mode 100644 index edca4abe13..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-11.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-12.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-12.png deleted file mode 100644 index 47f1fe432d..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-12.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-13.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-13.png deleted file mode 100644 index 2a2d9b3ad0..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-13.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-14.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-14.png deleted file mode 100644 index 6cd7878d43..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-14.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-15.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-15.png deleted file mode 100644 index 337fd00309..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-15.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-2.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-2.png deleted file mode 100644 index ddb86ea7c3..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-2.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-3.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-3.png deleted file mode 100644 index 0bfad99975..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-3.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-4.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-4.png deleted file mode 100644 index 8a1e2c4a3e..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-4.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-5.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-5.png deleted file mode 100644 index ba5504a925..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-5.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-6.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-6.png deleted file mode 100644 index 0b16972a10..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-6.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-7.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-7.png deleted file mode 100644 index b9aa3187e4..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-7.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-8.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-8.png deleted file mode 100644 index 800f67b653..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-8.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-9.png b/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-9.png deleted file mode 100644 index e56b28c375..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/Eclipse_Tutorial_Screenshot-9.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a0.png b/doc/tutorials/introduction/linux_eclipse/images/a0.png new file mode 100644 index 0000000000..00577b7e48 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a0.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a1.png b/doc/tutorials/introduction/linux_eclipse/images/a1.png new file mode 100644 index 0000000000..edbb69ea45 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a1.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a10.png b/doc/tutorials/introduction/linux_eclipse/images/a10.png new file mode 100644 index 0000000000..d3603ba75d Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a10.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a12.png b/doc/tutorials/introduction/linux_eclipse/images/a12.png new file mode 100644 index 0000000000..4838501d5b Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a12.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a14.png b/doc/tutorials/introduction/linux_eclipse/images/a14.png new file mode 100644 index 0000000000..7db82993b0 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a14.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a15.jpg b/doc/tutorials/introduction/linux_eclipse/images/a15.jpg new file mode 100644 index 0000000000..4f1fa43716 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a15.jpg differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a3.png b/doc/tutorials/introduction/linux_eclipse/images/a3.png new file mode 100644 index 0000000000..53f700e00c Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a3.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a4.png b/doc/tutorials/introduction/linux_eclipse/images/a4.png new file mode 100644 index 0000000000..fc1eb71008 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a4.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a7.png b/doc/tutorials/introduction/linux_eclipse/images/a7.png new file mode 100644 index 0000000000..a87d6eb41b Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a7.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/a9.png b/doc/tutorials/introduction/linux_eclipse/images/a9.png new file mode 100644 index 0000000000..0e34c7e1a7 Binary files /dev/null and b/doc/tutorials/introduction/linux_eclipse/images/a9.png differ diff --git a/doc/tutorials/introduction/linux_eclipse/images/eclipse_cpp_logo.jpeg b/doc/tutorials/introduction/linux_eclipse/images/eclipse_cpp_logo.jpeg deleted file mode 100644 index f1aecfe85b..0000000000 Binary files a/doc/tutorials/introduction/linux_eclipse/images/eclipse_cpp_logo.jpeg and /dev/null differ diff --git a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst index 38cd647b23..2d300f0100 100644 --- a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst +++ b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst @@ -1,247 +1,260 @@ -.. _Linux_Eclipse_Usage: - -Using OpenCV with Eclipse (plugin CDT) -**************************************** - -.. note:: - For me at least, this works, is simple and quick. Suggestions are welcome - -Prerequisites -=============== - -#. Having installed `Eclipse `_ in your workstation (only the CDT plugin for C/C++ is needed). You can follow the following steps: - - * Go to the Eclipse site - - * Download `Eclipse IDE for C/C++ Developers `_ . Choose the link according to your workstation. - -#. Having installed OpenCV. If not yet, go :ref:`here ` - -Making a project -================= - -#. Start Eclipse. Just run the executable that comes in the folder. - -#. Go to **File -> New -> C/C++ Project** - - .. image:: images/Eclipse_Tutorial_Screenshot-0.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 0 - :align: center - -#. Choose a name for your project (i.e. DisplayImage). An **Empty Project** should be okay for this example. - - .. image:: images/Eclipse_Tutorial_Screenshot-1.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 1 - :align: center - -#. Leave everything else by default. Press **Finish**. - - .. image:: images/Eclipse_Tutorial_Screenshot-2.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 2 - :align: center - -#. Your project (in this case DisplayImage) should appear in the **Project Navigator** (usually at the left side of your window). - - .. image:: images/Eclipse_Tutorial_Screenshot-3.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 3 - :align: center - - -#. Now, let's add a source file using OpenCV: - - * Right click on **DisplayImage** (in the Navigator). **New -> Folder** . - - .. image:: images/Eclipse_Tutorial_Screenshot-4.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 4 - :align: center - - * Name your folder **src** and then hit **Finish** - - .. image:: images/Eclipse_Tutorial_Screenshot-5.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 5 - :align: center - - * Right click on your newly created **src** folder. Choose **New source file**: - - .. image:: images/Eclipse_Tutorial_Screenshot-6.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 6 - :align: center - - * Call it **DisplayImage.cpp**. Hit **Finish** - - .. image:: images/Eclipse_Tutorial_Screenshot-7.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 7 - :align: center - -#. So, now you have a project with a empty .cpp file. Let's fill it with some sample code (in other words, copy and paste the snippet below): - - .. code-block:: cpp - - #include - #include - - using namespace cv; - - int main( int argc, char** argv ) - { - Mat image; - image = imread( argv[1], 1 ); - - if( argc != 2 || !image.data ) - { - printf( "No image data \n" ); - return -1; - } - - namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); - imshow( "Display Image", image ); - - waitKey(0); - - return 0; - } - -#. We are only missing one final step: To tell OpenCV where the OpenCV headers and libraries are. For this, do the following: - - * - Go to **Project-->Properties** - - .. image:: images/Eclipse_Tutorial_Screenshot-8.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 8 - :align: center - - * - In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab. Here we will enter the headers and libraries info: - - a. - In **GCC C++ Compiler**, go to **Includes**. In **Include paths(-l)** you should include the path of the folder where opencv was installed. In our example, this is ``/usr/local/include/opencv``. - - .. image:: images/Eclipse_Tutorial_Screenshot-9.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 9 - :align: center - - .. note:: - If you do not know where your opencv files are, open the **Terminal** and type: - - .. code-block:: bash - - pkg-config --cflags opencv - - For instance, that command gave me this output: - - .. code-block:: bash - - -I/usr/local/include/opencv -I/usr/local/include - - - b. - Now go to **GCC C++ Linker**,there you have to fill two spaces: - - * In **Library search path (-L)** you have to write the path to where the opencv libraries reside, in my case the path is: - :: - - /usr/local/lib - - .. - - * - In **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 3 first on the list below are enough (for simple applications) . In my case, I am putting all of them since I plan to use the whole bunch: - - - * opencv_core - * opencv_imgproc - * opencv_highgui - * opencv_ml - * opencv_video - * opencv_features2d - * opencv_calib3d - * opencv_objdetect - * opencv_contrib - * opencv_legacy - * opencv_flann - - .. image:: images/Eclipse_Tutorial_Screenshot-10.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 10 - :align: center - - .. note:: - - If you don't know where your libraries are (or you are just psychotic and want to make sure the path is fine), type in **Terminal**: - - .. code-block:: bash - - pkg-config --libs opencv - - My output (in case you want to check) was: - - .. code-block:: bash - - -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann - - Now you are done. Click **OK** - - * Your project should be ready to be built. For this, go to **Project->Build all** - - .. image:: images/Eclipse_Tutorial_Screenshot-11.png - :height: 400px - :alt: Eclipse Tutorial Screenshot 11 - :align: center - - In the Console you should get something like - - .. image:: images/Eclipse_Tutorial_Screenshot-12.png - :height: 200px - :alt: Eclipse Tutorial Screenshot 12 - :align: center - - If you check in your folder, there should be an executable there. - -Running the executable -======================== - -So, now we have an executable ready to run. If we were to use the Terminal, we would probably do something like: - -.. code-block:: bash - - cd - cd src - ./DisplayImage ../images/HappyLittleFish.jpg - -Assuming that the image to use as the argument would be located in /images/HappyLittleFish.jpg. We can still do this, but let's do it from Eclipse: - - -#. Go to **Run->Run Configurations** - - .. image:: images/Eclipse_Tutorial_Screenshot-13.png - :height: 300px - :alt: Eclipse Tutorial Screenshot 13 - :align: center - -#. Under C/C++ Application you will see the name of your executable + Debug (if not, click over C/C++ Application a couple of times). Select the name (in this case **DisplayImage Debug**). - -#. Now, in the right side of the window, choose the **Arguments** Tab. Write the path of the image file we want to open (path relative to the workspace/DisplayImage folder). Let's use **HappyLittleFish.jpg**: - - .. image:: images/Eclipse_Tutorial_Screenshot-14.png - :height: 300px - :alt: Eclipse Tutorial Screenshot 14 - :align: center - -#. Click on the **Apply** button and then in Run. An OpenCV window should pop up with the fish image (or whatever you used). - - .. image:: images/Eclipse_Tutorial_Screenshot-15.png - :alt: Eclipse Tutorial Screenshot 15 - :align: center - - -#. Congratulations! You are ready to have fun with OpenCV using Eclipse. +.. _Linux_Eclipse_Usage: + +Using OpenCV with Eclipse (plugin CDT) +**************************************** + +.. note:: + Two ways, one by forming a project directly, and another by CMake + +Prerequisites +=============== + +1. Having installed `Eclipse `_ in your workstation (only the CDT plugin for C/C++ is needed). You can follow the following steps: + + * Go to the Eclipse site + + * Download `Eclipse IDE for C/C++ Developers `_ . Choose the link according to your workstation. + +#. Having installed OpenCV. If not yet, go :ref:`here `. + +Making a project +================= + +1. Start Eclipse. Just run the executable that comes in the folder. + +#. Go to **File -> New -> C/C++ Project** + + .. image:: images/a0.png + :alt: Eclipse Tutorial Screenshot 0 + :align: center + +#. Choose a name for your project (i.e. DisplayImage). An **Empty Project** should be okay for this example. + + .. image:: images/a1.png + :alt: Eclipse Tutorial Screenshot 1 + :align: center + +#. Leave everything else by default. Press **Finish**. + +#. Your project (in this case DisplayImage) should appear in the **Project Navigator** (usually at the left side of your window). + + .. image:: images/a3.png + :alt: Eclipse Tutorial Screenshot 3 + :align: center + + +#. Now, let's add a source file using OpenCV: + + * Right click on **DisplayImage** (in the Navigator). **New -> Folder** . + + .. image:: images/a4.png + :alt: Eclipse Tutorial Screenshot 4 + :align: center + + * Name your folder **src** and then hit **Finish** + + * Right click on your newly created **src** folder. Choose **New source file**: + + * Call it **DisplayImage.cpp**. Hit **Finish** + + .. image:: images/a7.png + :alt: Eclipse Tutorial Screenshot 7 + :align: center + +#. So, now you have a project with a empty .cpp file. Let's fill it with some sample code (in other words, copy and paste the snippet below): + + .. code-block:: cpp + + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + Mat image; + image = imread( argv[1], 1 ); + + if( argc != 2 || !image.data ) + { + printf( "No image data \n" ); + return -1; + } + + namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); + imshow( "Display Image", image ); + + waitKey(0); + + return 0; + } + +#. We are only missing one final step: To tell OpenCV where the OpenCV headers and libraries are. For this, do the following: + + * Go to **Project-->Properties** + + * In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab. Here we will enter the headers and libraries info: + + a. In **GCC C++ Compiler**, go to **Includes**. In **Include paths(-l)** you should include the path of the folder where opencv was installed. In our example, this is ``/usr/local/include/opencv``. + + .. image:: images/a9.png + :alt: Eclipse Tutorial Screenshot 9 + :align: center + + .. note:: + If you do not know where your opencv files are, open the **Terminal** and type: + + .. code-block:: bash + + pkg-config --cflags opencv + + For instance, that command gave me this output: + + .. code-block:: bash + + -I/usr/local/include/opencv -I/usr/local/include + + + b. Now go to **GCC C++ Linker**,there you have to fill two spaces: + + First in **Library search path (-L)** you have to write the path to where the opencv libraries reside, in my case the path is: + :: + + /usr/local/lib + + Then in **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 3 first on the list below are enough (for simple applications) . In my case, I am putting all of them since I plan to use the whole bunch: + + + opencv_core + opencv_imgproc + opencv_highgui + opencv_ml + opencv_video + opencv_features2d + opencv_calib3d + opencv_objdetect + opencv_contrib + opencv_legacy + opencv_flann + + .. image:: images/a10.png + :alt: Eclipse Tutorial Screenshot 10 + :align: center + + If you don't know where your libraries are (or you are just psychotic and want to make sure the path is fine), type in **Terminal**: + + .. code-block:: bash + + pkg-config --libs opencv + + + My output (in case you want to check) was: + .. code-block:: bash + + -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann + + Now you are done. Click **OK** + + * Your project should be ready to be built. For this, go to **Project->Build all** + + In the Console you should get something like + + .. image:: images/a12.png + :alt: Eclipse Tutorial Screenshot 12 + :align: center + + If you check in your folder, there should be an executable there. + +Running the executable +======================== + +So, now we have an executable ready to run. If we were to use the Terminal, we would probably do something like: + +.. code-block:: bash + + cd + cd src + ./DisplayImage ../images/HappyLittleFish.png + +Assuming that the image to use as the argument would be located in /images/HappyLittleFish.png. We can still do this, but let's do it from Eclipse: + + +#. Go to **Run->Run Configurations** + +#. Under C/C++ Application you will see the name of your executable + Debug (if not, click over C/C++ Application a couple of times). Select the name (in this case **DisplayImage Debug**). + +#. Now, in the right side of the window, choose the **Arguments** Tab. Write the path of the image file we want to open (path relative to the workspace/DisplayImage folder). Let's use **HappyLittleFish.png**: + + .. image:: images/a14.png + :alt: Eclipse Tutorial Screenshot 14 + :align: center + +#. Click on the **Apply** button and then in Run. An OpenCV window should pop up with the fish image (or whatever you used). + + .. image:: images/a15.jpg + :alt: Eclipse Tutorial Screenshot 15 + :align: center + +#. Congratulations! You are ready to have fun with OpenCV using Eclipse. + +================================================== +V2: Using CMake+OpenCV with Eclipse (plugin CDT) +================================================== + +(See the `getting started ` section of the OpenCV Wiki) + +Say you have or create a new file, *helloworld.cpp* in a directory called *foo*: + +.. code-block:: cpp + + + #include + #include + int main ( int argc, char **argv ) + { + cvNamedWindow( "My Window", 1 ); + IplImage *img = cvCreateImage( cvSize( 640, 480 ), IPL_DEPTH_8U, 1 ); + CvFont font; + double hScale = 1.0; + double vScale = 1.0; + int lineWidth = 1; + cvInitFont( &font, CV_FONT_HERSHEY_SIMPLEX | CV_FONT_ITALIC, + hScale, vScale, 0, lineWidth ); + cvPutText( img, "Hello World!", cvPoint( 200, 400 ), &font, + cvScalar( 255, 255, 0 ) ); + cvShowImage( "My Window", img ); + cvWaitKey(); + return 0; + } + +1. Create a build directory, say, under *foo*: ``mkdir /build``. Then ``cd build``. + +#. Put a *CmakeLists.txt* file in build: + +.. code-block:: bash + + PROJECT( helloworld_proj ) + FIND_PACKAGE( OpenCV REQUIRED ) + ADD_EXECUTABLE( helloworld helloworld.cxx ) + TARGET_LINK_LIBRARIES( helloworld ${OpenCV_LIBS} ) + +#. Run: ``cmake-gui ..`` and make sure you fill in where opencv was built. + +#. Then click ``configure`` and then ``generate``. If it's OK, **quit cmake-gui** + +#. Run ``make -j4`` *(the ``-j4`` is optional, it just tells the compiler to build in 4 threads)*. Make sure it builds. + +#. Start ``eclipse`` . Put the workspace in some directory but **not** in ``foo`` or ``foo\\build`` + +#. Right click in the ``Project Explorer`` section. Select ``Import`` And then open the ``C/C++`` filter. Choose *Existing Code* as a Makefile Project`` + +#. Name your project, say *helloworld*. Browse to the Existing Code location ``foo\\build`` (where you ran your cmake-gui from). Select *Linux GCC* in the *"Toolchain for Indexer Settings"* and press *Finish*. + +#. Right click in the ``Project Explorer`` section. Select ``Properties``. Under ``C/C++ Build``, set the *build directory:* from something like ``${workspace_loc:/helloworld}`` to ``${workspace_loc:/helloworld}/build`` since that's where you are building to. + + a. You can also optionally modify the ``Build command:`` from ``make`` to something like ``make VERBOSE=1 -j4`` which tells the compiler to produce detailed symbol files for debugging and also to compile in 4 parallel threads. + +#. Done! + + + diff --git a/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.jpg b/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.jpg new file mode 100644 index 0000000000..9eeef5ddb4 Binary files /dev/null and b/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.jpg differ diff --git a/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.png b/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.png deleted file mode 100644 index 524f7e2143..0000000000 Binary files a/doc/tutorials/introduction/linux_gcc_cmake/images/GCC_CMake_Example_Tutorial.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_gcc_cmake/images/gccegg-65.png b/doc/tutorials/introduction/linux_gcc_cmake/images/gccegg-65.png deleted file mode 100644 index cd59029373..0000000000 Binary files a/doc/tutorials/introduction/linux_gcc_cmake/images/gccegg-65.png and /dev/null differ diff --git a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst index 7b9d5ed3c7..d5e039134a 100644 --- a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst +++ b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst @@ -78,7 +78,6 @@ By now you should have an executable (called DisplayImage in this case). You jus You should get a nice window as the one shown below: -.. image:: images/GCC_CMake_Example_Tutorial.png +.. image:: images/GCC_CMake_Example_Tutorial.jpg :alt: Display Image - Lena :align: center - diff --git a/doc/tutorials/introduction/linux_install/images/ubuntu_logo.jpeg b/doc/tutorials/introduction/linux_install/images/ubuntu_logo.jpeg deleted file mode 100644 index 50544c119c..0000000000 Binary files a/doc/tutorials/introduction/linux_install/images/ubuntu_logo.jpeg and /dev/null differ diff --git a/doc/tutorials/introduction/linux_install/linux_install.rst b/doc/tutorials/introduction/linux_install/linux_install.rst index 52f080addd..e78e1d849c 100644 --- a/doc/tutorials/introduction/linux_install/linux_install.rst +++ b/doc/tutorials/introduction/linux_install/linux_install.rst @@ -19,7 +19,7 @@ Required packages * pkgconfig * libpng, zlib, libjpeg, libtiff, libjasper with development files (e.g. libpjeg-dev) * Python 2.3 or later with developer packages (e.g. python-dev) - * SWIG 1.3.30 or later + * SWIG 1.3.30 or later (only for versions prior to OpenCV 2.3) * libavcodec * libdc1394 2.x diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.jpg b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.jpg new file mode 100644 index 0000000000..fcc7afa4e3 Binary files /dev/null and b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.jpg differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.png deleted file mode 100644 index 91c9eb6b76..0000000000 Binary files a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_1.png and /dev/null differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.jpg b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.jpg new file mode 100644 index 0000000000..e91b6a1a02 Binary files /dev/null and b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.jpg differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.png deleted file mode 100644 index ccf4f493fc..0000000000 Binary files a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_2.png and /dev/null differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_a.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_a.png deleted file mode 100644 index c4b76850c3..0000000000 Binary files a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_a.png and /dev/null differ diff --git a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_b.png b/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_b.png deleted file mode 100644 index cc31604c61..0000000000 Binary files a/doc/tutorials/introduction/load_save_image/images/Load_Save_Image_Result_b.png and /dev/null differ diff --git a/doc/tutorials/introduction/load_save_image/load_save_image.rst b/doc/tutorials/introduction/load_save_image/load_save_image.rst index 8afdf0c2d4..6ea6499982 100644 --- a/doc/tutorials/introduction/load_save_image/load_save_image.rst +++ b/doc/tutorials/introduction/load_save_image/load_save_image.rst @@ -1,22 +1,22 @@ .. _Load_Save_Image: -Load and Save an Image -*********************** +Load, Modify, and Save an Image +******************************* .. note:: - We assume that by now you know: - - * Load an image using :imread:`imread <>` - * Display an image in an OpenCV window (using :imshow:`imshow <>`) + We assume that by now you know how to load an image using :imread:`imread <>` and to display it in a window (using :imshow:`imshow <>`). Read the :ref:`Display_Image` tutorial otherwise. Goals ====== In this tutorial you will learn how to: -* Transform an image from RGB to Grayscale format by using :cvt_color:`cvtColor <>` -* Save your transformed image in a file on disk (using :imwrite:`imwrite <>`) +.. container:: enumeratevisibleitemswithsquare + + * Load an image using :imread:`imread <>` + * Transform an image from RGB to Grayscale format by using :cvt_color:`cvtColor <>` + * Save your transformed image in a file on disk (using :imwrite:`imwrite <>`) Code ====== @@ -47,7 +47,7 @@ Here it is: Mat gray_image; cvtColor( image, gray_image, CV_RGB2GRAY ); - imwrite( "../../images/Gray_Image.png", gray_image ); + imwrite( "../../images/Gray_Image.jpg", gray_image ); namedWindow( imageName, CV_WINDOW_AUTOSIZE ); namedWindow( "Gray image", CV_WINDOW_AUTOSIZE ); @@ -76,20 +76,21 @@ Explanation As you can see, :cvt_color:`cvtColor <>` takes as arguments: - * a source image (*image*) - * a destination image (*gray_image*), in which we will save the converted image. + .. container:: enumeratevisibleitemswithsquare - And an additional parameter that indicates what kind of transformation will be performed. In this case we use **CV_RGB2GRAY** (self-explanatory). + * a source image (*image*) + * a destination image (*gray_image*), in which we will save the converted image. + * an additional parameter that indicates what kind of transformation will be performed. In this case we use **CV_RGB2GRAY** (self-explanatory). #. So now we have our new *gray_image* and want to save it on disk (otherwise it will get lost after the program ends). To save it, we will use a function analagous to :imread:`imread <>`: :imwrite:`imwrite <>` .. code-block:: cpp - imwrite( "../../images/Gray_Image.png", gray_image ); + imwrite( "../../images/Gray_Image.jpg", gray_image ); - Which will save our *gray_image* as *Gray_Image.png* in the folder *images* located two levels up of my current location. + Which will save our *gray_image* as *Gray_Image.jpg* in the folder *images* located two levels up of my current location. -#. Finally, let's check out the images. We create 02 windows and use them to show the original image as well as the new one: +#. Finally, let's check out the images. We create two windows and use them to show the original image as well as the new one: .. code-block:: cpp @@ -99,7 +100,7 @@ Explanation imshow( imageName, image ); imshow( "Gray image", gray_image ); -#. Add the usual *waitKey(0)* for the program to wait forever until the user presses a key. +#. Add add the *waitKey(0)* function call for the program to wait forever for an user key press. Result @@ -107,16 +108,14 @@ Result When you run your program you should get something like this: - .. image:: images/Load_Save_Image_Result_1.png + .. image:: images/Load_Save_Image_Result_1.jpg :alt: Load Save Image Result 1 - :height: 400px :align: center -And if you check in your folder (in my case *images*), you should have a newly .png file named *Gray_Image.png*: +And if you check in your folder (in my case *images*), you should have a newly .jpg file named *Gray_Image.jpg*: - .. image:: images/Load_Save_Image_Result_2.png + .. image:: images/Load_Save_Image_Result_2.jpg :alt: Load Save Image Result 2 - :height: 250px :align: center -Congratulations, you are done with this tutorial! +Congratulations, you are done with this tutorial! diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.jpg new file mode 100644 index 0000000000..9c646e21ae Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.png b/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.png deleted file mode 100644 index 0c2e67c1dc..0000000000 Binary files a/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.png and /dev/null differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.jpg new file mode 100644 index 0000000000..5b8fc982ce Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.png b/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.png deleted file mode 100644 index 97fef256d9..0000000000 Binary files a/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.png and /dev/null differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/android_logo.png b/doc/tutorials/introduction/table_of_content_introduction/images/android_logo.png new file mode 100644 index 0000000000..69bccd74d2 Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/android_logo.png differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg b/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg index 95d4b7938d..e63e26b1b4 100644 Binary files a/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg and b/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.jpg new file mode 100644 index 0000000000..e3e44d1f6c Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.png b/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.png deleted file mode 100644 index cd59029373..0000000000 Binary files a/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.png and /dev/null differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu-logo.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu-logo.jpg new file mode 100644 index 0000000000..a34243496c Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu-logo.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu_logo.jpeg b/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu_logo.jpeg deleted file mode 100644 index 0efc4f73d7..0000000000 Binary files a/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu_logo.jpeg and /dev/null differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/visual-studio-2010-logo.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/visual-studio-2010-logo.jpg new file mode 100644 index 0000000000..8b053695c4 Binary files /dev/null and b/doc/tutorials/introduction/table_of_content_introduction/images/visual-studio-2010-logo.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg b/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg index 9727ee4e90..e35a8a86ae 100644 Binary files a/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg and b/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg differ diff --git a/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst b/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst index 2b8884fd1c..7b41cf876e 100644 --- a/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst +++ b/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst @@ -5,127 +5,192 @@ Introduction to OpenCV Here you can read tutorials about how to set up your computer to work with the OpenCV library. Additionaly you can find a few very basic sample source code that will let introduce you to the world of the OpenCV. +.. include:: ../../definitions/tocDefinitions.rst + +* **Linux** + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ====================================================== + |Install_1| **Title:** :ref:`Linux-Installation` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to setup OpenCV in your computer! + + =========== ====================================================== + + .. |Install_1| image:: images/ubuntu-logo.jpg + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ====================================================== + |Usage_1| **Title:** :ref:`Linux_GCC_Usage` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to compile your first project using gcc and CMake + + =========== ====================================================== + + .. |Usage_1| image:: images/gccegg-65.jpg + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ====================================================== + |Usage_2| **Title:** :ref:`Linux_Eclipse_Usage` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to compile your first project using the Eclipse environment + + =========== ====================================================== + + .. |Usage_2| image:: images/eclipse_cpp_logo.jpeg + :height: 90pt + :width: 90pt + +* **Windows** + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ====================================================== + |WinInstal| **Title:** :ref:`Windows_Installation` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will learn how to setup OpenCV in your Windows Operating System! + + =========== ====================================================== + + .. |WinInstal| image:: images/windows_logo.jpg + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ====================================================== + |WinVSHowT| **Title:** :ref:`Windows_Visual_Studio_How_To` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_BernatG| + + You will learn what steps you need to perform in order to use the OpenCV library inside a new Microsoft Visual Studio project. + + =========== ====================================================== + + .. |WinVSHowT| image:: images/visual-studio-2010-logo.jpg + :height: 90pt + :width: 90pt + +* **Android** + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ================ ====================================================== + |AndroidBinPack| **Title:** :ref:`Android_Binary_Package` + + *Compatibility:* > OpenCV 2.3.1 + + *Author:* |Author_AndreyK| + + You will learn how to setup OpenCV for Android platform! + + ================ ====================================================== + + .. |AndroidBinPack| image:: images/android_logo.png + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ================ ====================================================== + |AndroidNDKPack| **Title:** :ref:`Android_Binary_Package_with_NDK` + + *Compatibility:* > OpenCV 2.3.1 + + *Author:* |Author_LeonidBLB| + + You will learn how to work with C++ OpenCV code for Android platform + + ================ ====================================================== + + .. |AndroidNDKPack| image:: images/android_logo.png + :height: 90pt + :width: 90pt + +* **From where to start?** + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ============= ====================================================== + |Beginners_1| **Title:** :ref:`Display_Image` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to display an image using OpenCV + + ============= ====================================================== + + .. |Beginners_1| image:: images/Display_Image_Tutorial_Result.jpg + :height: 90pt + :width: 90pt + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |Beginners_2| **Title:** :ref:`Load_Save_Image` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_AnaH| + + We will learn how to save an Image in OpenCV...plus a small conversion to grayscale + + =============== ====================================================== + + .. |Beginners_2| image:: images/Load_Save_Image_Result_1.jpg + :height: 90pt + :width: 90pt + +.. raw:: latex + + \pagebreak + .. We use a custom table of content format and as the table of content only imforms Sphinx about the hierarchy of the files, no need to show it. .. toctree:: :hidden: - + ../linux_install/linux_install ../linux_gcc_cmake/linux_gcc_cmake ../linux_eclipse/linux_eclipse ../windows_install/windows_install + ../windows_visual_studio_Opencv/windows_visual_studio_Opencv + ../android_binary_package/android_binary_package + ../android_binary_package/android_binary_package_using_with_NDK ../display_image/display_image ../load_save_image/load_save_image - -.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n -.. |Author_BernatG| unicode:: Bern U+00E1 t U+0020 G U+00E1 bor - -* **Linux** - - * :ref:`Linux-Installation` - - =========== ====================================================== - |Install_1| *Title:* **Installation steps in Linux** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to setup OpenCV in your computer! - - =========== ====================================================== - - .. |Install_1| image:: images/ubuntu_logo.jpeg - :height: 100pt - :width: 100pt - - - * :ref:`Linux_GCC_Usage` - - =========== ====================================================== - |Usage_1| *Title:* **Using OpenCV with gcc (and CMake)** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to compile your first project using gcc and CMake - - =========== ====================================================== - - .. |Usage_1| image:: images/gccegg-65.png - :height: 100pt - :width: 100pt - - - * :ref:`Linux_Eclipse_Usage` - - =========== ====================================================== - |Usage_2| *Title:* **Using OpenCV with Eclipse (CDT plugin)** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to compile your first project using the Eclipse environment - - =========== ====================================================== - - .. |Usage_2| image:: images/eclipse_cpp_logo.jpeg - :height: 100pt - :width: 100pt - -* **Windows** - - * :ref:`Windows_Installation` - - =========== ====================================================== - |Install_2| *Title:* **Installation steps in Windows** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will learn how to setup OpenCV in your Windows Operating System! - - =========== ====================================================== - - .. |Install_2| image:: images/windows_logo.jpg - :height: 100pt - :width: 100pt - -* **From where to start?** - - * :ref:`Display_Image` - - =============== ====================================================== - |Beginners_1| *Title:* **Display an Image** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to display an image using OpenCV - - =============== ====================================================== - - .. |Beginners_1| image:: images/Display_Image_Tutorial_Result.png - :height: 100pt - :width: 100pt - - - * :ref:`Load_Save_Image` - - =============== ====================================================== - |Beginners_2| *Title:* **Load and save an Image** - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to save an Image in OpenCV...plus a small conversion to grayscale - - =============== ====================================================== - - .. |Beginners_2| image:: images/Load_Save_Image_Result_1.png - :height: 100pt - :width: 100pt diff --git a/doc/tutorials/introduction/windows_install/images/CMakeBuildOptionsOpenCV.jpg b/doc/tutorials/introduction/windows_install/images/CMakeBuildOptionsOpenCV.jpg new file mode 100644 index 0000000000..8a25b70629 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/CMakeBuildOptionsOpenCV.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/CMakeBuildWithWindowsGUI.jpg b/doc/tutorials/introduction/windows_install/images/CMakeBuildWithWindowsGUI.jpg new file mode 100644 index 0000000000..eb39491387 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/CMakeBuildWithWindowsGUI.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/CMakeOutputPackageNotFound.jpg b/doc/tutorials/introduction/windows_install/images/CMakeOutputPackageNotFound.jpg new file mode 100644 index 0000000000..227f4766df Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/CMakeOutputPackageNotFound.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/CMakePackageNotFoundWindows.jpg b/doc/tutorials/introduction/windows_install/images/CMakePackageNotFoundWindows.jpg new file mode 100644 index 0000000000..5cfa668176 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/CMakePackageNotFoundWindows.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/CMakeSelectBin.jpg b/doc/tutorials/introduction/windows_install/images/CMakeSelectBin.jpg new file mode 100644 index 0000000000..db37cf65f5 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/CMakeSelectBin.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/CMake_Configure_Windows.jpg b/doc/tutorials/introduction/windows_install/images/CMake_Configure_Windows.jpg new file mode 100644 index 0000000000..fb6c506d58 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/CMake_Configure_Windows.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/ChangeBuildVisualStudio.jpg b/doc/tutorials/introduction/windows_install/images/ChangeBuildVisualStudio.jpg new file mode 100644 index 0000000000..0bba04b5ea Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/ChangeBuildVisualStudio.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/IntelTBB.png b/doc/tutorials/introduction/windows_install/images/IntelTBB.png new file mode 100644 index 0000000000..64b53b7f31 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/IntelTBB.png differ diff --git a/doc/tutorials/introduction/windows_install/images/MiktexInstall.png b/doc/tutorials/introduction/windows_install/images/MiktexInstall.png new file mode 100644 index 0000000000..193a403991 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/MiktexInstall.png differ diff --git a/doc/tutorials/introduction/windows_install/images/OpenCVBuildResultWindows.jpg b/doc/tutorials/introduction/windows_install/images/OpenCVBuildResultWindows.jpg new file mode 100644 index 0000000000..4ca9f58e60 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/OpenCVBuildResultWindows.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/OpenCV_Install_Directory.png b/doc/tutorials/introduction/windows_install/images/OpenCV_Install_Directory.png new file mode 100644 index 0000000000..b038b26b56 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/OpenCV_Install_Directory.png differ diff --git a/doc/tutorials/introduction/windows_install/images/PathEditorOpenCVInsertNew.png b/doc/tutorials/introduction/windows_install/images/PathEditorOpenCVInsertNew.png new file mode 100644 index 0000000000..9e2f12399b Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/PathEditorOpenCVInsertNew.png differ diff --git a/doc/tutorials/introduction/windows_install/images/PathEditorOpenCVSetPath.png b/doc/tutorials/introduction/windows_install/images/PathEditorOpenCVSetPath.png new file mode 100644 index 0000000000..c9f8987222 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/PathEditorOpenCVSetPath.png differ diff --git a/doc/tutorials/introduction/windows_install/images/SVNCheckOutProgress.png b/doc/tutorials/introduction/windows_install/images/SVNCheckOutProgress.png new file mode 100644 index 0000000000..9370b4e807 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/SVNCheckOutProgress.png differ diff --git a/doc/tutorials/introduction/windows_install/images/Sphinx_Install.png b/doc/tutorials/introduction/windows_install/images/Sphinx_Install.png new file mode 100644 index 0000000000..da2e06c0bf Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/Sphinx_Install.png differ diff --git a/doc/tutorials/introduction/windows_install/images/TortoiseSVNCheckout.png b/doc/tutorials/introduction/windows_install/images/TortoiseSVNCheckout.png new file mode 100644 index 0000000000..8ab3fa1dca Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/TortoiseSVNCheckout.png differ diff --git a/doc/tutorials/introduction/windows_install/images/TortoiseSVNCheckoutWindow.png b/doc/tutorials/introduction/windows_install/images/TortoiseSVNCheckoutWindow.png new file mode 100644 index 0000000000..1bef3ba592 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/TortoiseSVNCheckoutWindow.png differ diff --git a/doc/tutorials/introduction/windows_install/images/WindowsBuildDoc.png b/doc/tutorials/introduction/windows_install/images/WindowsBuildDoc.png new file mode 100644 index 0000000000..18cad032c3 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/WindowsBuildDoc.png differ diff --git a/doc/tutorials/introduction/windows_install/images/WindowsBuildInstall.png b/doc/tutorials/introduction/windows_install/images/WindowsBuildInstall.png new file mode 100644 index 0000000000..efc1779fc5 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/WindowsBuildInstall.png differ diff --git a/doc/tutorials/introduction/windows_install/images/WindowsOpenCVDirPath.png b/doc/tutorials/introduction/windows_install/images/WindowsOpenCVDirPath.png new file mode 100644 index 0000000000..6f98134074 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/WindowsOpenCVDirPath.png differ diff --git a/doc/tutorials/introduction/windows_install/images/WindowsOpenCVInstaller.png b/doc/tutorials/introduction/windows_install/images/WindowsOpenCVInstaller.png new file mode 100644 index 0000000000..664a15e62e Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/WindowsOpenCVInstaller.png differ diff --git a/doc/tutorials/introduction/windows_install/images/WindowsQtContoursOutput.png b/doc/tutorials/introduction/windows_install/images/WindowsQtContoursOutput.png new file mode 100644 index 0000000000..ebb41ac4b9 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/WindowsQtContoursOutput.png differ diff --git a/doc/tutorials/introduction/windows_install/images/cmsdstartwindows.jpg b/doc/tutorials/introduction/windows_install/images/cmsdstartwindows.jpg new file mode 100644 index 0000000000..e0d9530d5c Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/cmsdstartwindows.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/qtDownloadThisPackage.png b/doc/tutorials/introduction/windows_install/images/qtDownloadThisPackage.png new file mode 100644 index 0000000000..1ed849a6e8 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/qtDownloadThisPackage.png differ diff --git a/doc/tutorials/introduction/windows_install/images/visualstudiocommandprompt.jpg b/doc/tutorials/introduction/windows_install/images/visualstudiocommandprompt.jpg new file mode 100644 index 0000000000..712d58b963 Binary files /dev/null and b/doc/tutorials/introduction/windows_install/images/visualstudiocommandprompt.jpg differ diff --git a/doc/tutorials/introduction/windows_install/images/windows_logo.jpg b/doc/tutorials/introduction/windows_install/images/windows_logo.jpg deleted file mode 100644 index 37e130dee6..0000000000 Binary files a/doc/tutorials/introduction/windows_install/images/windows_logo.jpg and /dev/null differ diff --git a/doc/tutorials/introduction/windows_install/windows_install.rst b/doc/tutorials/introduction/windows_install/windows_install.rst index 7fff23c7aa..720249d46f 100644 --- a/doc/tutorials/introduction/windows_install/windows_install.rst +++ b/doc/tutorials/introduction/windows_install/windows_install.rst @@ -1,5 +1,372 @@ -.. _Windows_Installation: - -Installation in Windows -*********************** -For now this is just a stub article. It will be updated with valuable content as soon as possible. Make sure to check back for it! +.. _Windows_Installation: + +Installation in Windows +*********************** + +.. include:: + +The description here was tested by the author using the Windows 7 SP1 **o**\ perating **s**\ ystem (*OS*). Nevertheless, it should also work on any other Windows OS too. If you encounter errors after following the steps described here feel free to contact us via our :opencv_group:`user group <>` and we will try to fix your problem. + +.. note:: To use the OpenCV library you have two options: :ref:`Windows_Install_Prebuild` or :ref:`CppTutWindowsMakeOwn`. While the first one is easier to complete, it only works if you are coding inside the latest Microsoft Visual Studio **i**\ ntegrated **d**\ evelopment **e**\ nvironments (*IDE*) and doesn't takes advantage of the most novel technologies we integrate into our library. + +.. _Windows_Install_Prebuild: + +Installation by using the pre-built libraries +============================================= + +1. Open up a web browser and go to: http://sourceforge.net/projects/opencvlibrary/files/opencv-win/ + +#. Open the folder for the latest version (currently this is 2.3). + +#. Choose a build you want to use and download it. The naming conventions used will show what kind of support they offer. For example: + + .. container:: enumeratevisibleitemswithsquare + + * *vs2010* means the Visual Studio + * *win32* means that it is for 32 bit applications in the OS + * *gpu* means that it includes the support for using your GPU in order to further increase the performance of the library). + + If you downloaded the source files present here see :ref:`CppTutWindowsMakeOwn`. + +#. Make sure you have admin rights. Start the setup and follow the wizard. Agree to the \" License Agreement \" . + +#. While adding the OpenCV library to the system path is a good decision for a better control of this we will do it manually. Therefore, make sure you do not set this option. + +#. Most of the time it is a good idea to install the source files as this will allow for you to debug into the OpenCV library, if it is necessary. Therefore, just follow the default settings of the wizard and finish the installation. + +#. You can check the installation at the chosen path as you can see below. + + .. image:: images/OpenCV_Install_Directory.png + :alt: An example of how the installation directory should look in case of success. + :align: center + +#. To finalize the installation go to the :ref:`WindowsSetPathAndEnviromentVariable` section. + +.. _CppTutWindowsMakeOwn: + +Installation by making your own libraries from the source files +=============================================================== + +You may find the content of this tutorial also inside the following videos: `Part 1 `_ and `Part 2 `_, hosted on YouTube. + +.. raw:: html + +
+ + +
+ +If you are building your own libraries you can take either the source files from our latest: + + .. container:: enumeratevisibleitemswithsquare + + + stable and tested build - https://code.ros.org/svn/opencv/branches/2.3 (this will change with every new realease) + + development build - https://code.ros.org/svn/opencv/trunk/ + +While the later one may contain a couple of new and experimental algorithms, performance increases and interface improvements, be aware, that it may also contain many-many bugs. Using the first one is recommended in most of the cases. That is unless you are extending the OpenCV library itself or really need to most up to date version of it. + +Building the OpenCV library from scratch requires a couple of tools installed beforehand: + +.. |CMake| replace:: CMake +.. _CMake: http://www.cmake.org/cmake/resources/software.html +.. |TortoiseSVN| replace:: TortoiseSVN +.. _TortoiseSVN: http://tortoisesvn.net/downloads.html +.. |Python_Libraries| replace:: Python libraries +.. _Python_Libraries: http://www.python.org/getit/ +.. |Numpy| replace:: Numpy +.. _Numpy: http://numpy.scipy.org/ +.. |IntelTBB| replace:: Intel |copy| Threading Building Blocks (*TBB*) +.. _IntelTBB: http://threadingbuildingblocks.org/file.php?fid=77 +.. |IntelIIP| replace:: Intel |copy| Integrated Performance Primitives (*IPP*) +.. _IntelIIP: http://software.intel.com/en-us/articles/intel-ipp/ +.. |qtframework| replace:: Qt framework +.. _qtframework: http://qt.nokia.com/downloads +.. |Eigen| replace:: Eigen +.. _Eigen: http://eigen.tuxfamily.org/index.php?title=Main_Page#Download +.. |CUDA_Toolkit| replace:: CUDA Toolkit +.. _CUDA_Toolkit: http://developer.nvidia.com/cuda-downloads +.. |OpenEXR| replace:: OpenEXR +.. _OpenEXR: http://www.openexr.com/downloads.html +.. |OpenNI_Framework| replace:: OpenNI Framework +.. _OpenNI_Framework: http://www.openni.org/ +.. |Miktex| replace:: Miktex +.. _Miktex: http://miktex.org/2.9/setup +.. |Sphinx| replace:: Sphinx +.. _Sphinx: http://sphinx.pocoo.org/ + +.. container:: enumeratevisibleitemswithsquare + + + An **I**\ ntegrated **D**\ eveloper **E**\ nviroment (*IDE*) preferably, or just a C\C++ compiler that will actually make the binary files. Here I will use the `Microsoft Visual Studio `_. Nevertheless, you can use any other *IDE* that has a valid C\\C++ compiler. + + + Then |CMake|_ is a neat tool that will make the project files (for your choosen *IDE*) from the OpenCV source files. It will also allow an easy configuration of the OpenCV build files, in order to make binary files that fits exactly to your needs. + + + A **S**\ ubversion **C**\ ontrol **S**\ ystem (*SVN*) to acquire the OpenCV source files. A good tool for this is |TortoiseSVN|_. Alternatively, you can just download an archived version of the source files from the `Sourceforge OpenCV page `_. + +OpenCV may come in multiple flavors. There is a "core" section that will work on its own. Nevertheless, they are a couple of tools, libraries made by other organizations (so called 3rd parties) that offer services of which the OpenCV may take advantage. These will improve in many ways its capabilities. In order to use any of them, you need to download and install them on your system. + +.. container:: enumeratevisibleitemswithsquare + + + The |Python_Libraries|_ are required to build the *Python interface* of OpenCV. For now use the version :file:`2.7.{x}`. This is also a must have if you want to build the *OpenCV documentation*. + + + |Numpy|_ is a scientific computing package for Python. Required for the *Python interface*. + + + |IntelTBB|_ is used inside OpenCV for parallel code snippets. Using this will make sure that the OpenCV library will take advantage of all the cores you have in your systems CPU. + + + |IntelIIP|_ may be used to improve the performance of color conversion, Haar training and DFT functions of the OpenCV library. Watch out as this isn't a *free* service. + + + OpenCV offers a somewhat fancier and more useful graphical user interface, than the default one by using the |qtframework|_. For a quick overview of what this has to offer look into the documentations *highgui* module, under the *Qt New Functions* section. Version 4.6 or later of the framework is required. + + + |Eigen|_ is a C++ template library for linear algebra. + + + The latest |CUDA_Toolkit|_ will allow you to use the power lying inside your GPU. This will drastically improve performance for some of the algorithms, like the HOG descriptor. Getting to work more and more of our algorithms on the GPUs is a constant effort of the OpenCV team. + + + |OpenEXR|_ source files are required for the library to work with this high dynamic range (HDR) image file format. + + + The |OpenNI_Framework|_ contains a set of open source APIs that provide support for natural interaction with devices via methods such as voice command recognition, hand gestures and body motion tracking. + + + |Miktex|_ is the best `TEX `_ implementation on the Windows OS. It is required to build the *OpenCV documentation*. + + + |Sphinx|_ is a python documentation generator and is the tool that will actually create the *OpenCV documentation*. This on its own requires a couple of tools installed, I will cover this in depth at the :ref:`How to Install Sphinx ` section. + +Now I will describe the steps to follow for a full build (using all the above frameworks, tools and libraries). If you do not need the support for some of these you can just freely skip those parts. + +.. _WindowsBuildLibrary: + +Building the library +^^^^^^^^^^^^^^^^^^^^ + +1. Make sure you have a working IDE with a valid compiler. In case of the Microsoft Visual Studio just install it and make sure it starts up. + +#. Install |CMake|_. Simply follow the wizard, no need to add it to the path. The default install options are great. No need to change them. + +#. Install |TortoiseSVN|_. Choose the 32 or 64 bit version according to the type of OS you work in. Again follow the wizard, default options are good. Restart of your system is required. + +#. Choose a directory in your file system where you will download the OpenCV libraries. I recommend creating a new one that has short path and no special charachters in it, for example :file:`D:/OpenCV`. During this tutorial I'll suppose you've done so. If you use a different directory just change this front part of the path in my future examples. Then, :menuselection:`Right Click --> SVN Checkout...` in the directory. + + .. image:: images/TortoiseSVNCheckout.png + :alt: The TortoiseSVN Checkout Menu + :align: center + + A window will appear where you can select from what repository you want to download source files (1) and to which directory (2): + + .. image:: images/TortoiseSVNCheckoutWindow.png + :alt: The TortoiseSVN Checkout Window + :align: center + + Add here either ones of the versions described above. Then push the OK button and be patient as the repository currently is over 330MB to download. It will take some time until it is finished depending on your Internet connection. + + .. image:: images/SVNCheckOutProgress.png + :alt: The TortoiseSVN Checkout Progress + :align: center + + When you are done you should have a *opencv* and an *opencv_extra* directory as seen at (3). + +#. In this section I will cover installing the 3rd party libraries. + + a) Download the |Python_Libraries|_ and install it with the default options. You will need a couple other python extensions. Luckily installing all these may be automated by a nice tool called `Setuptools `_. Download and install again. + + #) .. _HereInstallSphinx: + + Installing Sphinx is easy once you have installed *Setuptools*. This contains a little application that will automatically connect to the python databases and download the latest version of many python scripts. Start up a command window (enter *cmd* into the windows start menu and press enter) and use the *CD* command to navigate to your Python folders Script sub-folder. Here just pass to the *easy_install.exe* as argument the name of the program you want to install. Add the *sphinx* argument. + + .. image:: images/cmsdstartwindows.jpg + :alt: The Windows Command Startup + :align: center + + .. image:: images/Sphinx_Install.png + :alt: How to start the command window + :align: center + + .. note:: + + The *CD* navigation command works only inside a drive. For example if you are somewhere in the *C:* drive you cannot use it this to go to another drive (like for example *D:*). To do so you first need to change drives letters. For this simply enter the command *D:*. Then you can use the *CD* to navigate to specific folder inside the drive. Bonus tip: you can clear the screen by using the *CLS* command. + + This will also install its prerequisites `Jinja2 `_ and `Pygments `_. + + #) The easiest way to install |Numpy|_ is to just download its binaries from the `sourceforga page `_. Make sure your download and install exactly the binary for your python version (so for version :file:`2.7`). + + #) Download the |Miktex|_ and install it. Again just follow the wizard. At the fourth step make sure you select for the *"Install missing packages on-the-fly"* the *Yes* option, as you can see on the image below. Again this will take quite some time so be patient. + + .. image:: images/MiktexInstall.png + :alt: The Miktex Install Screen + :align: center + + #) For the |IntelTBB|_ download the source files and extract it inside a directory on your system. For example let there be :file:`D:/OpenCV/dep`. For installing the |IntelIIP|_ the story is the same. For exctracting the archives I recommend using the `7-Zip `_ application. + + .. image:: images/IntelTBB.png + :alt: The Miktex Install Screen + :align: center + + #) In case of the |Eigen|_ library it is again a case of download and extract to the :file:`D:/OpenCV/dep` directory. + + #) Same as above with |OpenEXR|_. + + #) For the |OpenNI_Framework|_ you need to install both the `development build `_ and the `PrimeSensor Module `_. + + #) For the CUDA you need again two modules: the latest |CUDA_Toolkit|_ and the *CUDA Tools SDK*. Download and install both of them with a *complete* option by using the 32 or 64 bit setups according to your OS. + + #) In case of the |qtframework|_ you need to build yourself the binary files (unless you use the Microsoft Visual Studio 2008 with 32 bit compiler). To do this go to the `Qt Downloads `_ page. Download the source files (not the installers!!!): + + .. image:: images/qtDownloadThisPackage.png + :alt: Download this Qt Package + :align: center + + Extract it into a nice and short named directory like :file:`D:/OpenCV/dep/qt/` . + Then you need to build it. Start up a *Visual* *Studio* *Command* *Prompt* (*2010*) by using the start menu search (or navigate through the start menu :menuselection:`All Programs --> Microsoft Visual Studio 2010 --> Visual Studio Tools --> Visual Studio Command Prompt (2010)`). + + .. image:: images/visualstudiocommandprompt.jpg + :alt: The Visual Studio command prompt + :align: center + + Now navigate to the extracted folder and enter inside it by using this console window. You should have a folder containing files like *Install*, *Make* and so on. Use the *dir* command to list files inside your current directory. Once arrived at this directory enter the following command: + + .. code-block:: bash + + configure.exe -release -no-webkit -no-phonon -no-phonon-backend -no-script -no-scripttools + -no-qt3support -no-multimedia -no-ltcg + + Completing this will take around 10-20 minutes. Then enter the next command that will take a lot longer (can easily take even more than a full hour): + + .. code-block:: bash + + nmake + + After this set the Qt enviroment variables using the following command on Windows 7: + + .. code-block:: bash + + setx -m QTDIR D:/OpenCV/dep/qt/qt-everywhere-opensource-src-4.7.3 + + .. |PathEditor| replace:: Path Editor + .. _PathEditor: http://www.redfernplace.com/software-projects/patheditor/ + + Also, add the built binary files path to the system path by using the |PathEditor|_. In our case this is :file:`D:/OpenCV/dep/qt/qt-everywhere-opensource-src-4.7.3/bin`. + + .. note:: + + If you plan on doing Qt application development you can also install at this point the *Qt Visual Studio Add-in*. After this you can make and build Qt applications without using the *Qt Creator*. Everything is nicely integrated into Visual Studio. + +#. Now start the *CMake (cmake-gui)*. You may again enter it in the start menu search or get it from the :menuselection:`All Programs --> CMake 2.8 --> CMake (cmake-gui)`. First, select the directory for the source files of the OpenCV library (1). Then, specify a directory where you will build the binary files for OpenCV (2). + + .. image:: images/CMakeSelectBin.jpg + :alt: Select the directories + :align: center + + Press the Configure button to specify the compiler (and *IDE*) you want to use. Note that in case you can choose between different compilers for making either 64 bit or 32 bit libraries. Select the one you use in your application development. + + .. image:: images/CMake_Configure_Windows.jpg + :alt: How CMake should look at build time. + :align: center + + CMake will start out and based on your system variables will try to automatically locate as many packages as possible. You can modify the packages to use for the build in the :menuselection:`WITH --> WITH_X` menu points (where *X* is the package abbreviation). Here are a list of current packages you can turn on or off: + + .. image:: images/CMakeBuildWithWindowsGUI.jpg + :alt: The packages OpenCV may use + :align: center + + Select all the packages you want to use and press again the *Configure* button. For an easier overview of the build options make sure the *Grouped* option under the binary directory selection is turned on. For some of the packages CMake may not find all of the required files or directories. In case of these CMake will throw an error in its output window (located at the bottom of the GUI) and set its field values, to not found constants. For example: + + .. image:: images/CMakePackageNotFoundWindows.jpg + :alt: Constant for not found packages + :align: center + + .. image:: images/CMakeOutputPackageNotFound.jpg + :alt: Error (warning) thrown in output window of the CMake GUI + :align: center + + For these you need to manually set the queried directories or files path. After this press again the *Configure* button to see if the value entered by you was accepted or not. Do this until all entries are good and you cannot see errors in the field/value or the output part of the GUI. + Now I want to emphasize an option that you will definitely love: :menuselection:`ENABLE --> ENABLE_SOLUTION_FOLDERS`. OpenCV will create many-many projects and turning this option will make sure that they are categorized inside directories in the *Solution Explorer*. It is a must have feature, if you ask me. + + .. image:: images/CMakeBuildOptionsOpenCV.jpg + :alt: Set the Solution Folders and the parts you want to build + :align: center + + Furthermore, you need to select what part of OpenCV you want to build. + + .. container:: enumeratevisibleitemswithsquare + + + *BUILD_DOCS* -> It creates two projects for building the documentation of OpenCV (there will be a separate project for building the HTML and the PDF files). Note that these aren't built together with the solution. You need to make an explicit build project command on these to do so. + + *BUILD_EXAMPLES* -> OpenCV comes with many example applications from which you may learn most of the libraries capabilities. This will also come handy to easily try out if OpenCV is fully functional on your computer. + + *BUILD_JAVA_SUPPORT* -> At the moment this has no real meaning on the Windows platform. Ignore it. + + *BUILD_NEW_PYTHON_SUPPORT* -> Self-explanatory. Create the binaries to use OpenCV from the Python language. + + *BUILD_PACKAGE* -> Prior to version 2.3 with this you could build a project that will build an OpenCV installer. With this you can easily install your OpenCV flavor on other systems. For the latest source files of OpenCV it generates a new project that simply creates zip archive with OpenCV sources. + + *BUILD_SHARED_LIBS* -> With this you can control to build DLL files (when turned on) or static library files (\*.lib) otherwise. + + *BUILD_TESTS* -> Each module of OpenCV has a test project assigned to it. Building these test projects is also a good way to try out, that the modules work just as expected on your system too. + + Press again the *Configure* button and ensure no errors are reported. If this is the case you can tell CMake to create the project files by pushing the *Generate* button. Go to the build directory and open the created **OpenCV** solution. + Depending on just how much of the above options you have selected the solution may contain quite a lot of projects so be tolerant on the IDE at the startup. + Now you need to build both the *Release* and the *Debug* binaries. Use the drop-down menu on your IDE to change to another of these after building for one of them. + + .. image:: images/ChangeBuildVisualStudio.jpg + :alt: Look here for changing the Build Type + :align: center + + In the end you can observe the built binary files inside the bin directory: + + .. image:: images/OpenCVBuildResultWindows.jpg + :alt: The Result of the build. + :align: center + + For the documentation you need to explicitly issue the build commands on the *doc* project for the PDF files and on the *doc_html* for the HTML ones. Each of these will call *Sphinx* to do all the hard work. You can find the generated documentation inside the :file:`Build/Doc/_html` for the HTML pages and within the :file:`Build/Doc` the PDF manuals. + + .. image:: images/WindowsBuildDoc.png + :alt: The Documentation Projects + :align: center + + To collect the header and the binary files, that you will use during your own projects, into a separate directory (simillary to how the pre-built binaries ship) you need to explicitely build the *Install* project. + + .. image:: images/WindowsBuildInstall.png + :alt: The Install Project + :align: center + + This will create an *install* directory inside the *Build* one collecting all the built binaries into a single place. Use this only after you built both the *Release* and *Debug* versions. + + .. note:: + + To create an installer you need to install `NSIS `_. Then just build the *Package* project to build the installer into the :file:`Build/_CPack_Packages/{win32}/NSIS` folder. You can then use this to distribute OpenCV with your build settings on other systems. + + .. image:: images/WindowsOpenCVInstaller.png + :alt: The Installer directory + :align: center + + To test your build just go into the :file:`Build/bin/Debug` or :file:`Build/bin/Release` directory and start a couple of applications like the *contours.exe*. If they run, you are done. Otherwise, something definitely went awfully wrong. In this case you should contact us via our :opencv_group:`user group <>`. + If everything is okay the *contours.exe* output should resemble the following image (if built with Qt support): + + .. image:: images/WindowsQtContoursOutput.png + :alt: A good output result + :align: center + + .. note:: + + If you use the GPU module (CUDA libraries) make sure you also upgrade to the latest drivers of your GPU. Error messages containing invalid entries in (or cannot find) the nvcuda.dll are caused mostly by old video card drivers. For testing the GPU (if built) run the *performance_gpu.exe* sample application. + +.. _WindowsSetPathAndEnviromentVariable: + +Set the OpenCV enviroment variable and add it to the systems path +================================================================= + +First we set an enviroment variable to make easier our work. This will hold the install directory of our OpenCV library that we use in our projects. Start up a command window and enter: + +.. code-block:: bash + + setx -m OPENCV_DIR D:\OpenCV\Build\Install + +Here the directory is where you have your OpenCV binaries (*installed* or *built*). Inside this you should have folders like *bin* and *include*. The -m should be added if you wish to make the settings computer wise, instead of user wise. + +If you built static libraries then you are done. Otherwise, you need to add the *bin* folders path to the systems path.This is cause you will use the OpenCV library in form of *\"Dynamic-link libraries\"* (also known as **DLL**). Inside these are stored all the algorithms and information the OpenCV library contains. The operating system will load them only on demand, during runtime. However, to do this he needs to know where they are. The systems **PATH** contains a list of folders where DLLs can be found. Add the OpenCV library path to this and the OS will know where to look if he ever needs the OpenCV binaries. Otherwise, you will need to copy the used DLLs right beside the applications executable file (*exe*) for the OS to find it, which is highly unpleasent if you work on many projects. To do this start up again the |PathEditor|_ and add the following new entry (right click in the application to bring up the menu): + +.. code-block:: bash + + %OPENCV_DIR%\bin + +.. image:: images/PathEditorOpenCVInsertNew.png + :alt: Right click to insert new path manually. + :align: center + +.. image:: images/PathEditorOpenCVSetPath.png + :alt: Add the entry. + :align: center + +Save it to the registry and you are done. If you ever change the location of your install directories or want to try out your applicaton with a different build all you will need to do is to update the OPENCV_DIR variable via the *setx* command inside a command window. + +Now you can continue reading the tutorials with the :ref:`Windows_Visual_Studio_How_To` section. There you will find out how to use the OpenCV library in your own projects with the help of the Microsoft Visual Studio IDE. diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/AddNewPropertySheet.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/AddNewPropertySheet.jpg new file mode 100644 index 0000000000..773d4d0b2a Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/AddNewPropertySheet.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/NewProjectVisualStudio.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/NewProjectVisualStudio.jpg new file mode 100644 index 0000000000..fb12f8f0f1 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/NewProjectVisualStudio.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/OpenCVEditEnviromentVisual.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/OpenCVEditEnviromentVisual.jpg new file mode 100644 index 0000000000..f5e55ab395 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/OpenCVEditEnviromentVisual.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/OpenCV_Install_Directory.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/OpenCV_Install_Directory.jpg new file mode 100644 index 0000000000..3f32c0f674 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/OpenCV_Install_Directory.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertyPageAddExisting.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertyPageAddExisting.jpg new file mode 100644 index 0000000000..30c3194f97 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertyPageAddExisting.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertyPageExample.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertyPageExample.jpg new file mode 100644 index 0000000000..f2f2034adc Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertyPageExample.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetInsideFolder.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetInsideFolder.jpg new file mode 100644 index 0000000000..a20d59f111 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetInsideFolder.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVInclude.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVInclude.jpg new file mode 100644 index 0000000000..5826f4dd6c Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVInclude.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLib.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLib.jpg new file mode 100644 index 0000000000..25c88b3762 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLib.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesDebug.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesDebug.jpg new file mode 100644 index 0000000000..c28841acfa Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesDebug.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesDebugSmple.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesDebugSmple.jpg new file mode 100644 index 0000000000..7fcbf9d8f0 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesDebugSmple.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesRelease.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesRelease.jpg new file mode 100644 index 0000000000..dd93d21688 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetOpenCVLibrariesRelease.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetVS2010.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetVS2010.jpg new file mode 100644 index 0000000000..64446ac422 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/PropertySheetVS2010.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/SuccessVisualStudioWindows.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/SuccessVisualStudioWindows.jpg new file mode 100644 index 0000000000..d63b5c981d Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/SuccessVisualStudioWindows.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VCDirectories2008.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VCDirectories2008.jpg new file mode 100644 index 0000000000..7cb6aa9151 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VCDirectories2008.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VCDirectories2010.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VCDirectories2010.jpg new file mode 100644 index 0000000000..4cf1fcd3d8 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VCDirectories2010.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VisualStudioCommandLineArguments.jpg b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VisualStudioCommandLineArguments.jpg new file mode 100644 index 0000000000..9d52d98945 Binary files /dev/null and b/doc/tutorials/introduction/windows_visual_studio_Opencv/images/VisualStudioCommandLineArguments.jpg differ diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.rst b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.rst new file mode 100644 index 0000000000..67b781c455 --- /dev/null +++ b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.rst @@ -0,0 +1,180 @@ +.. _Windows_Visual_Studio_How_To: + +How to build applications with OpenCV inside the *Microsoft Visual Studio* +************************************************************************** + +Everything I describe here will apply to the C\\C++ interface of OpenCV. +I start out from the assumption that you have read and completed with success the :ref:`Windows_Installation` tutorial. Therefore, before you go any further make sure you have an OpenCV directory that contains the OpenCV header files plus binaries and you have set the environment variables as :ref:`described here `. + +.. image:: images/OpenCV_Install_Directory.jpg + :alt: You should have a folder looking like this. + :align: center + +The OpenCV libraries, distributed by us, on the Microsoft Windows operating system are in a **D**\ ynamic **L**\ inked **L**\ ibraries (*DLL*). These have the advantage that all the content of the library are loaded only at runtime, on demand, and that countless programs may use the same library file. This means that if you have ten applications using the OpenCV library, no need to have around a version for each one of them. Of course you need to have the *dll* of the OpenCV on all systems where you want to run your application. + +Another approach is to use static libraries that have *lib* extensions. You may build these by using our source files as described in the :ref:`Windows_Installation` tutorial. When you use this the library will be built-in inside your *exe* file. So there is no chance that the user deletes them, for some reason. As a drawback your application will be larger one and as, it will take more time to load it during its startup. + +To build an application with OpenCV you need to do two things: + +.. container:: enumeratevisibleitemswithsquare + + + *Tell* to the compiler how the OpenCV library *looks*. You do this by *showing* it the header files. + + *Tell* to the linker from where to get the functions or data structures of OpenCV, when they are needed. + + If you use the *lib* system you must set the path where the library files are and specify in which one of them to look. During the build the linker will look into these libraries and add the definitions and implementation of all *used* functions and data structures to the executable file. + + If you use the *DLL* system you must again specify all this, however now for a different reason. This is a Microsoft OS specific stuff. It seems that the linker needs to know that where in the DLL to search for the data structure or function at the runtime. This information is stored inside *lib* files. Nevertheless, they aren't static libraries. They are so called import libraries. This is why when you make some *DLLs* in Windows you will also end up with some *lib* extension libraries. The good part is that at runtime only the *DLL* is required. + +To pass on all this information to the Visual Studio IDE you can either do it globally (so all your future projects will get these information) or locally (so only for you current project). The advantage of the global one is that you only need to do it once; however, it may be undesirable to clump all your projects all the time with all these information. In case of the global one how you do it depends on the Microsoft Visual Studio you use. There is a **2008 and previous versions** and a **2010 way** of doing it. Inside the global section of this tutorial I'll show what the main differences are. + +The base item of a project in Visual Studio is a solution. A solution may contain multiple projects. Projects are the building blocks of an application. Every project will realize something and you will have a main project in which you can put together this project puzzle. In case of the many simple applications (like many of the tutorials will be) you do not need to break down the application into modules. In these cases your main project will be the only existing one. Now go create a new solution inside Visual studio by going through the :menuselection:`File --> New --> Project` menu selection. Choose *Win32 Console Application* as type. Enter its name and select the path where to create it. Then in the upcoming dialog make sure you create an empty project. + +.. image:: images/NewProjectVisualStudio.jpg + :alt: Which options to select + :align: center + +The *local* method +================== + +Every project is built separately from the others. Due to this every project has its own rule package. Inside this rule packages are stored all the information the *IDE* needs to know to build your project. For any application there are at least two build modes: a *Release* and a *Debug* one. The *Debug* has many features that exist so you can find and resolve easier bugs inside your application. In contrast the *Release* is an optimized version, where the goal is to make the application run as fast as possible or to be as small as possible. You may figure that these modes also require different rules to use during build. Therefore, there exist different rule packages for each of your build modes. These rule packages are called inside the IDE as *project properties* and you can view and modify them by using the *Property Manger*. You can bring up this with :menuselection:`View --> Property Pages`. Expand it and you can see the existing rule packages (called *Proporty Sheets*). + +.. image:: images/PropertyPageExample.jpg + :alt: An example of Property Sheet + :align: center + +The really useful stuff of these is that you may create a rule package *once* and you can later just add it to your new projects. Create it once and reuse it later. We want to create a new *Property Sheet* that will contain all the rules that the compiler and linker needs to know. Of course we will need a separate one for the Debug and the Release Builds. Start up with the Debug one as shown in the image below: + +.. image:: images/AddNewPropertySheet.jpg + :alt: Add a new Property Sheet + :align: center + +Use for example the *OpenCV_Debug* name. Then by selecting the sheet :menuselection:`Right Click --> Properties`. In the following I will show to set the OpenCV rules locally, as I find unnecessary to pollute projects with custom rules that I do not use it. Go the C++ groups General entry and under the *"Additional Include Directories"* add the path to your OpenCV include. + +.. code-block:: bash + + $(OPENCV_DIR)\include + +.. image:: images/PropertySheetOpenCVInclude.jpg + :alt: Add the include dir like this. + :align: center + +When adding third party libraries settings it is generally a good idea to use the power behind the environment variables. The full location of the OpenCV library may change on each system. Moreover, you may even end up yourself with moving the install directory for some reason. If you would give explicit paths inside your property sheet your project will end up not working when you pass it further to someone else who has a different OpenCV install path. Moreover, fixing this would require to manually modifying every explicit path. A more elegant solution is to use the environment variables. Anything that you put inside a parenthesis started with a dollar sign will be replaced at runtime with the current environment variables value. Here comes in play the environment variable setting we already made in our :ref:`previous tutorial `. + +Next go to the :menuselection:`Linker --> General` and under the *"Additional Library Directories"* add the libs directory: + +.. code-block:: bash + + $(OPENCV_DIR)\libs + +.. image:: images/PropertySheetOpenCVLib.jpg + :alt: Add the library folder like this. + :align: center + +Then you need to specify the libraries in which the linker should look into. To do this go to the :menuselection:`Linker --> Input` and under the *"Additional Dependencies"* entry add the name of all modules which you want to use: + +.. image:: images/PropertySheetOpenCVLibrariesDebugSmple.jpg + :alt: Add the debug library names here. + :align: center + +.. image:: images/PropertySheetOpenCVLibrariesDebug.jpg + :alt: Like this. + :align: center + +The names of the libraries are as follow: + +.. code-block:: bash + + opencv_(The Name of the module)(The version Number of the library you use)d.lib + +A full list, for the currently latest trunk version would contain: + +.. code-block:: bash + + opencv_core231d.lib + opencv_imgproc231d.lib + opencv_highgui231d.lib + opencv_ml231d.lib + opencv_video231d.lib + opencv_features2d231d.lib + opencv_calib3d231d.lib + opencv_objdetect231d.lib + opencv_contrib231d.lib + opencv_legacy231d.lib + opencv_flann231d.lib + +The letter *d* at the end just indicates that these are the libraries required for the debug. Now click ok to save and do the same with a new property inside the Release rule section. Make sure to omit the *d* letters from the library names and to save the property sheets with the save icon above them. + +.. image:: images/PropertySheetOpenCVLibrariesRelease.jpg + :alt: And the release ones. + :align: center + +You can find your property sheets inside your projects directory. At this point it is a wise decision to back them up into some special directory, to always have them at hand in the future, whenever you create an OpenCV project. Note that for Visual Studio 2010 the file extension is *props*, while for 2008 this is *vsprops*. + +.. image:: images/PropertySheetInsideFolder.jpg + :alt: And the release ones. + :align: center + +Next time when you make a new OpenCV project just use the "Add Existing Property Sheet..." menu entry inside the Property Manager to easily add the OpenCV build rules. + +.. image:: images/PropertyPageAddExisting.jpg + :alt: Use this option. + :align: center + +The *global* method +=================== + +In case you find to troublesome to add the property pages to each and every one of your projects you can also add this rules to a *"global property page"*. However, this applies only to the additional include and library directories. The name of the libraries to use you still need to specify manually by using for instance: a Property page. + +In Visual Studio 2008 you can find this under the: :menuselection:`Tools --> Options --> Projects and Solutions --> VC++ Directories`. + +.. image:: images/VCDirectories2008.jpg + :alt: VC++ Directories in VS 2008. + :align: center + +In Visual Studio 2010 this has been moved to a global property sheet which is automatically added to every project you create: + +.. image:: images/VCDirectories2010.jpg + :alt: VC++ Directories in VS 2010. + :align: center + +The process is the same as described in case of the local approach. Just add the include directories by using the environment variable *OPENCV_DIR*. + +Test it! +======== + +Now to try this out download our little test :download:`source code <../../../../samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/Test.cpp>` or get it from the sample code folder of the OpenCV sources. Add this to your project and build it. Here's its content: + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/Test.cpp + :language: cpp + :tab-width: 4 + :linenos: + +You can start a Visual Studio build from two places. Either inside from the *IDE* (keyboard combination: :kbd:`Control-F5`) or by navigating to your build directory and start the application with a double click. The catch is that these two **aren't** the same. When you start it from the *IDE* its current working directory is the projects directory, while otherwise it is the folder where the application file currently is (so usually your build directory). Moreover, in case of starting from the *IDE* the console window will not close once finished. It will wait for a keystroke of yours. + +.. |voila| unicode:: voil U+00E1 + +This is important to remember when you code inside the code open and save commands. You're resources will be saved ( and queried for at opening!!!) relatively to your working directory. This is unless you give a full, explicit path as parameter for the I/O functions. In the code above we open :download:`this OpenCV logo<../../../../samples/cpp/tutorial_code/images/opencv-logo.png>`. Before starting up the application make sure you place the image file in your current working directory. Modify the image file name inside the code to try it out on other images too. Run it and |voila|: + +.. image:: images/SuccessVisualStudioWindows.jpg + :alt: You should have this. + :align: center + +Command line arguments with Visual Studio +========================================= + +Throughout some of our future tutorials you'll see that the programs main input method will be by giving a runtime argument. To do this you can just start up a commmand windows (:kbd:`cmd + Enter` in the start menu), navigate to your executable file and start it with an argument. So for example in case of my upper project this would look like: + +.. code-block:: bash + :linenos: + + D: + CD OpenCV\MySolutionName\Release + MySolutionName.exe exampleImage.jpg + +Here I first changed my drive (if your project isn't on the OS local drive), navigated to my project and start it with an example image argument. While under Linux system it is common to fiddle around with the console window on the Microsoft Windows many people come to use it almost never. Besides, adding the same argument again and again while you are testing your application is, somewhat, a cumbersome task. Luckily, in the Visual Studio there is a menu to automate all this: + +.. image:: images/VisualStudioCommandLineArguments.jpg + :alt: Visual Studio Command Line Arguments + :align: center + +Specify here the name of the inputs and while you start your application from the Visual Studio enviroment you have automatic argument passing. In the next introductionary tutorial you'll see an in-depth explanation of the upper source code: :ref:`Display_Image`. \ No newline at end of file diff --git a/doc/tutorials/ml/introduction_to_svm/images/optimal-hyperplane.png b/doc/tutorials/ml/introduction_to_svm/images/optimal-hyperplane.png new file mode 100644 index 0000000000..d4522f0479 Binary files /dev/null and b/doc/tutorials/ml/introduction_to_svm/images/optimal-hyperplane.png differ diff --git a/doc/tutorials/ml/introduction_to_svm/images/result.png b/doc/tutorials/ml/introduction_to_svm/images/result.png new file mode 100644 index 0000000000..5f477a4f69 Binary files /dev/null and b/doc/tutorials/ml/introduction_to_svm/images/result.png differ diff --git a/doc/tutorials/ml/introduction_to_svm/images/separating-lines.png b/doc/tutorials/ml/introduction_to_svm/images/separating-lines.png new file mode 100644 index 0000000000..93ae457c0c Binary files /dev/null and b/doc/tutorials/ml/introduction_to_svm/images/separating-lines.png differ diff --git a/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.rst b/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.rst new file mode 100644 index 0000000000..c2ef546f05 --- /dev/null +++ b/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.rst @@ -0,0 +1,188 @@ +.. _introductiontosvms: + +Introduction to Support Vector Machines +*************************************** + +Goal +==== + +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + + Use the OpenCV functions :svms:`CvSVM::train ` to build a classifier based on SVMs and :svms:`CvSVM::predict ` to test its performance. + +What is a SVM? +============== + +A Support Vector Machine (SVM) is a discriminative classifier formally defined by a separating hyperplane. In other words, given labeled training data (*supervised learning*), the algorithm outputs an optimal hyperplane which categorizes new examples. + +In which sense is the hyperplane obtained optimal? Let's consider the following +simple problem: + + For a linearly separable set of 2D-points which belong to one of two classes, find a separating straight line. + +.. image:: images/separating-lines.png + :alt: A seperation example + :align: center + +.. note:: In this example we deal with lines and points in the Cartesian plane instead of hyperplanes and vectors in a high dimensional space. This is a simplification of the problem.It is important to understand that this is done only because our intuition is better built from examples that are easy to imagine. However, the same concepts apply to tasks where the examples to classify lie in a space whose dimension is higher than two. + +In the above picture you can see that there exists multiple lines that offer a solution to the problem. Is any of them better than the others? We can intuitively define a criterion to estimate the worth of the lines: + + A line is bad if it passes too close to the points because it will be noise sensitive and it will not generalize correctly. Therefore, our goal should be to find the line passing as far as possible from all points. + +Then, the operation of the SVM algorithm is based on finding the hyperplane that gives the largest minimum distance to the training examples. Twice, this distance receives the important name of **margin** within SVM's theory. Therefore, the optimal separating hyperplane *maximizes* the margin of the training data. + +.. image:: images/optimal-hyperplane.png + :alt: The Optimal hyperplane + :align: center + +How is the optimal hyperplane computed? +======================================= + +Let's introduce the notation used to define formally a hyperplane: + +.. math:: + f(x) = \beta_{0} + \beta^{T} x, + +where :math:`\beta` is known as the *weight vector* and :math:`\beta_{0}` as the *bias*. + +.. seealso:: A more in depth description of this and hyperplanes you can find in the section 4.5 (*Seperating Hyperplanes*) of the book: *Elements of Statistical Learning* by T. Hastie, R. Tibshirani and J. H. Friedman. + +The optimal hyperplane can be represented in an infinite number of different ways by scaling of :math:`\beta` and :math:`\beta_{0}`. As a matter of convention, among all the possible representations of the hyperplane, the one chosen is + +.. math:: + |\beta_{0} + \beta^{T} x| = 1 + +where :math:`x` symbolizes the training examples closest to the hyperplane. In general, the training examples that are closest to the hyperplane are called **support vectors**. This representation is known as the **canonical hyperplane**. + +Now, we use the result of geometry that gives the distance between a point :math:`x` and a hyperplane :math:`(\beta, \beta_{0})`: + +.. math:: + \mathrm{distance} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||}. + +In particular, for the canonical hyperplane, the numerator is equal to one and the distance to the support vectors is + +.. math:: + \mathrm{distance}_{\text{ support vectors}} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||} = \frac{1}{||\beta||}. + +Recall that the margin introduced in the previous section, here denoted as :math:`M`, is twice the distance to the closest examples: + +.. math:: + M = \frac{2}{||\beta||} + +Finally, the problem of maximizing :math:`M` is equivalent to the problem of minimizing a function :math:`L(\beta)` subject to some constraints. The constraints model the requirement for the hyperplane to classify correctly all the training examples :math:`x_{i}`. Formally, + +.. math:: + \min_{\beta, \beta_{0}} L(\beta) = \frac{1}{2}||\beta||^{2} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 \text{ } \forall i, + +where :math:`y_{i}` represents each of the labels of the training examples. + +This is a problem of Lagrangian optimization that can be solved using Lagrange multipliers to obtain the weight vector :math:`\beta` and the bias :math:`\beta_{0}` of the optimal hyperplane. + +Source Code +=========== + +.. literalinclude:: ../../../../samples/cpp/tutorial_code/ml/introduction_to_svm/introduction_to_svm.cpp + :language: cpp + :linenos: + :tab-width: 4 + +Explanation +=========== + +1. **Set up the training data** + + The training data of this exercise is formed by a set of labeled 2D-points that belong to one of two different classes; one of the classes consists of one point and the other of three points. + + .. code-block:: cpp + + float labels[4] = {1.0, -1.0, -1.0, -1.0}; + float trainingData[4][2] = {{501, 10}, {255, 10}, {501, 255}, {10, 501}}; + + The function :svms:`CvSVM::train ` that will be used afterwards requires the training data to be stored as :basicstructures:`Mat ` objects of floats. Therefore, we create these objects from the arrays defined above: + + .. code-block:: cpp + + Mat trainingDataMat(3, 2, CV_32FC1, trainingData); + Mat labelsMat (3, 1, CV_32FC1, labels); + +2. **Set up SVM's parameters** + + In this tutorial we have introduced the theory of SVMs in the most simple case, when the training examples are spread into two classes that are linearly separable. However, SVMs can be used in a wide variety of problems (e.g. problems with non-linearly separable data, a SVM using a kernel function to raise the dimensionality of the examples, etc). As a consequence of this, we have to define some parameters before training the SVM. These parameters are stored in an object of the class :svms:`CvSVMParams ` . + + .. code-block:: cpp + + CvSVMParams params; + params.svm_type = CvSVM::C_SVC; + params.kernel_type = CvSVM::LINEAR; + params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); + + * *Type of SVM*. We choose here the type **CvSVM::C_SVC** that can be used for n-class classification (n :math:`\geq` 2). This parameter is defined in the attribute *CvSVMParams.svm_type*. + + .. note:: The important feature of the type of SVM **CvSVM::C_SVC** deals with imperfect separation of classes (i.e. when the training data is non-linearly separable). This feature is not important here since the data is linearly separable and we chose this SVM type only for being the most commonly used. + + * *Type of SVM kernel*. We have not talked about kernel functions since they are not interesting for the training data we are dealing with. Nevertheless, let's explain briefly now the main idea behind a kernel function. It is a mapping done to the training data to improve its resemblance to a linearly separable set of data. This mapping consists of increasing the dimensionality of the data and is done efficiently using a kernel function. We choose here the type **CvSVM::LINEAR** which means that no mapping is done. This parameter is defined in the attribute *CvSVMParams.kernel_type*. + + * *Termination criteria of the algorithm*. The SVM training procedure is implemented solving a constrained quadratic optimization problem in an **iterative** fashion. Here we specify a maximum number of iterations and a tolerance error so we allow the algorithm to finish in less number of steps even if the optimal hyperplane has not been computed yet. This parameter is defined in a structure :oldbasicstructures:`cvTermCriteria `. + +3. **Train the SVM** + + We call the method `CvSVM::train `_ to build the SVM model. + + .. code-block:: cpp + + CvSVM SVM; + SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params); + +4. **Regions classified by the SVM** + + The method :svms:`CvSVM::predict ` is used to classify an input sample using a trained SVM. In this example we have used this method in order to color the space depending on the prediction done by the SVM. In other words, an image is traversed interpreting its pixels as points of the Cartesian plane. Each of the points is colored depending on the class predicted by the SVM; in green if it is the class with label 1 and in blue if it is the class with label -1. + + .. code-block:: cpp + + Vec3b green(0,255,0), blue (255,0,0); + + for (int i = 0; i < image.rows; ++i) + for (int j = 0; j < image.cols; ++j) + { + Mat sampleMat = (Mat_(1,2) << i,j); + float response = SVM.predict(sampleMat); + + if (response == 1) + image.at(j, i) = green; + else + if (response == -1) + image.at(j, i) = blue; + } + +5. **Support vectors** + + We use here a couple of methods to obtain information about the support vectors. The method :svms:`CvSVM::get_support_vector_count ` outputs the total number of support vectors used in the problem and with the method :svms:`CvSVM::get_support_vector ` we obtain each of the support vectors using an index. We have used this methods here to find the training examples that are support vectors and highlight them. + + .. code-block:: cpp + + int c = SVM.get_support_vector_count(); + + for (int i = 0; i < c; ++i) + { + const float* v = SVM.get_support_vector(i); // get and then highlight with grayscale + circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType); + } + +Results +======= + +.. container:: enumeratevisibleitemswithsquare + + * The code opens an image and shows the training examples of both classes. The points of one class are represented with white circles and black ones are used for the other class. + + * The SVM is trained and used to classify all the pixels of the image. This results in a division of the image in a blue region and a green region. The boundary between both regions is the optimal separating hyperplane. + + * Finally the support vectors are shown using gray rings around the training examples. + +.. image:: images/result.png + :alt: The seperated planes + :align: center + diff --git a/doc/tutorials/ml/table_of_content_ml/images/introduction_to_svm.png b/doc/tutorials/ml/table_of_content_ml/images/introduction_to_svm.png new file mode 100644 index 0000000000..f2d63751fc Binary files /dev/null and b/doc/tutorials/ml/table_of_content_ml/images/introduction_to_svm.png differ diff --git a/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst b/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst index 33134ff3ae..b2b581afa9 100644 --- a/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst +++ b/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst @@ -5,4 +5,32 @@ Use the powerfull machine learning classes for statistical classification, regression and clustering of data. -.. include:: ../../definitions/noContent.rst +.. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ============ ============================================== + |IntroSVM| **Title:** :ref:`introductiontosvms` + + *Compatibility:* > OpenCV 2.0 + + *Author:* |Author_FernandoI| + + Learn what a Suport Vector Machine is. + + ============ ============================================== + + .. |IntroSVM| image:: images/introduction_to_svm.png + :height: 90pt + :width: 90pt + +.. raw:: latex + + \pagebreak + +.. toctree:: + :hidden: + + ../introduction_to_svm/introduction_to_svm diff --git a/doc/tutorials/tutorials.rst b/doc/tutorials/tutorials.rst index 9696080348..068c72814c 100644 --- a/doc/tutorials/tutorials.rst +++ b/doc/tutorials/tutorials.rst @@ -1,15 +1,184 @@ -################# +################ OpenCV Tutorials -################# +################ The following links describe a set of basic OpenCV tutorials. All the source code mentioned here is provide as part of the OpenCV regular releases, so check before you start copy & pasting the code. The list of tutorials below is automatically generated from reST files located in our SVN repository. As always, we would be happy to hear your comments and receive your contributions on any tutorial. +* :ref:`Table-Of-Content-Introduction` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |Introduct| You will learn how to setup OpenCV on your computer! + + =========== ======================================================= + + .. |Introduct| image:: images/introduction.jpg + :height: 80pt + :width: 80pt + :alt: Introduction Icon + +* :ref:`Table-Of-Content-Core` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |Core| Here you will learn the about the basic building blocks of the library. A must read and know for understanding how to manipulate the images on a pixel level. + + =========== ======================================================= + + .. |Core| image:: images/core.jpg + :height: 80pt + :width: 80pt + :alt: core Icon + +* :ref:`Table-Of-Content-ImgProc` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |ImgProc| In this section you will learn about the image processing (manipulation) functions inside OpenCV. + + =========== ======================================================= + + .. |ImgProc| image:: images/imgproc.jpg + :height: 80pt + :width: 80pt + :alt: imgproc Icon + +* :ref:`Table-Of-Content-HighGui` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |HighGui| This section contains valuable tutorials about how to read/save your image/video files and how to use the built-in graphical user interface of the library. + + =========== ======================================================= + + .. |HighGui| image:: images/highgui.jpg + :height: 80pt + :width: 80pt + :alt: highgui Icon + +* :ref:`Table-Of-Content-Calib3D` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |Calib3D| Although we got most of our images in a 2D format they do come from a 3D world. Here you will learn how to find out from the 2D images information about the 3D world. + + =========== ======================================================= + + .. |Calib3D| image:: images/calib3d.jpg + :height: 80pt + :width: 80pt + :alt: calib3d Icon + +* :ref:`Table-Of-Content-Feature2D` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |Featur2D| Learn about how to use the feature points detectors, descriptors and matching framework found inside OpenCV. + + =========== ======================================================= + + .. |Featur2D| image:: images/feature2D.jpg + :height: 80pt + :width: 80pt + :alt: feature2D Icon + +* :ref:`Table-Of-Content-Video` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |Video| Look here in order to find use on your video stream algoritms like: motion extraction, feature tracking and foreground extractions. + + =========== ======================================================= + + .. |Video| image:: images/video.jpg + :height: 80pt + :width: 80pt + :alt: video Icon + +* :ref:`Table-Of-Content-ObjDetect` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |ObjDetect| Ever wondered how your digital camera detects peoples and faces? Look here to find out! + + =========== ======================================================= + + .. |ObjDetect| image:: images/objdetect.jpg + :height: 80pt + :width: 80pt + :alt: objdetect Icon + +* :ref:`Table-Of-Content-Ml` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |ml| Use the powerfull machine learning classes for statistical classification, regression and clustering of data. + + =========== ======================================================= + + .. |ml| image:: images/ml.jpg + :height: 80pt + :width: 80pt + :alt: ml Icon + +* :ref:`Table-Of-Content-GPU` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |GPU| Squeeze out every little computation power from your system by using the power of your video card to run the OpenCV algorithms. + + =========== ======================================================= + + .. |GPU| image:: images/gpu.jpg + :height: 80pt + :width: 80pt + :alt: gpu icon + +* :ref:`Table-Of-Content-General` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |General| These tutorials are the bottom of the iceberg as they link together multiple of the modules presented above in order to solve complex problems. + + =========== ======================================================= + + .. |General| image:: images/general.jpg + :height: 80pt + :width: 80pt + :alt: General Icon + +.. raw:: latex + + \pagebreak + .. toctree:: :maxdepth: 2 :hidden: - + introduction/table_of_content_introduction/table_of_content_introduction core/table_of_content_core/table_of_content_core imgproc/table_of_content_imgproc/table_of_content_imgproc @@ -21,135 +190,3 @@ As always, we would be happy to hear your comments and receive your contribution ml/table_of_content_ml/table_of_content_ml gpu/table_of_content_gpu/table_of_content_gpu general/table_of_content_general/table_of_content_general - -* :ref:`Table-Of-Content-Introduction` - - =========== ======================================================= - |Introduct| You will learn how to setup OpenCV on your computer! - - =========== ======================================================= - - .. |Introduct| image:: images/introduction.png - :height: 80pt - :width: 80pt - :alt: Introduction Icon - -* :ref:`Table-Of-Content-Core` - - =========== ======================================================= - |Core| Here you will learn the about the basic building blocks of the library. A must read and know for understanding how to manipulate the images on a pixel level. - - =========== ======================================================= - - .. |Core| image:: images/core.png - :height: 80pt - :width: 80pt - :alt: core Icon - -* :ref:`Table-Of-Content-ImgProc` - - =========== ======================================================= - |ImgProc| In this section you will learn about the image processing (manipulation) functions inside OpenCV. - - =========== ======================================================= - - .. |ImgProc| image:: images/imgproc.png - :height: 80pt - :width: 80pt - :alt: imgproc Icon - -* :ref:`Table-Of-Content-HighGui` - - =========== ======================================================= - |HighGui| This section contains valuable tutorials about how to read/save your image/video files and how to use the built-in graphical user interface of the library. - - =========== ======================================================= - - .. |HighGui| image:: images/highgui.png - :height: 80pt - :width: 80pt - :alt: highgui Icon - -* :ref:`Table-Of-Content-Calib3D` - - =========== ======================================================= - |Calib3D| Although we got most of our images in a 2D format they do come from a 3D world. Here you will learn how to find out from the 2D images information about the 3D world. - - =========== ======================================================= - - .. |Calib3D| image:: images/calib3d.png - :height: 80pt - :width: 80pt - :alt: calib3d Icon - -* :ref:`Table-Of-Content-Feature2D` - - =========== ======================================================= - |Featur2D| Learn about how to use the feature points detectors, descriptors and matching framework found inside OpenCV. - - =========== ======================================================= - - .. |Featur2D| image:: images/feature2D.png - :height: 80pt - :width: 80pt - :alt: feature2D Icon - -* :ref:`Table-Of-Content-Video` - - =========== ======================================================= - |Video| Look here in order to find use on your video stream algoritms like: motion extraction, feature tracking and foreground extractions. - - =========== ======================================================= - - .. |Video| image:: images/video.png - :height: 80pt - :width: 80pt - :alt: video Icon - -* :ref:`Table-Of-Content-ObjDetect` - - =========== ======================================================= - |ObjDetect| Ever wondered how your digital camera detects peoples and faces? Look here to find out! - - =========== ======================================================= - - .. |ObjDetect| image:: images/objdetect.png - :height: 80pt - :width: 80pt - :alt: objdetect Icon - -* :ref:`Table-Of-Content-Ml` - - =========== ======================================================= - |ml| Use the powerfull machine learning classes for statistical classification, regression and clustering of data. - - =========== ======================================================= - - .. |ml| image:: images/ml.png - :height: 80pt - :width: 80pt - :alt: ml Icon - -* :ref:`Table-Of-Content-GPU` - - =========== ======================================================= - |GPU| Squeeze out every little computation power from your system by using the power of your video card to run the OpenCV algorithms. - - =========== ======================================================= - - .. |GPU| image:: images/gpu.png - :height: 80pt - :width: 80pt - :alt: gpu icon - -* :ref:`Table-Of-Content-General` - - =========== ======================================================= - |General| These tutorials are the bottom of the iceberg as they link together multiple of the modules presented above in order to solve complex problems. - - =========== ======================================================= - - .. |General| image:: images/general.png - :height: 80pt - :width: 80pt - :alt: General Icon diff --git a/doc/tutorials/video/table_of_content_video/table_of_content_video.rst b/doc/tutorials/video/table_of_content_video/table_of_content_video.rst index aabe62d361..423c7ac9c1 100644 --- a/doc/tutorials/video/table_of_content_video/table_of_content_video.rst +++ b/doc/tutorials/video/table_of_content_video/table_of_content_video.rst @@ -6,3 +6,7 @@ Look here in order to find use on your video stream algoritms like: motion extraction, feature tracking and foreground extractions. .. include:: ../../definitions/noContent.rst + +.. raw:: latex + + \pagebreak diff --git a/doc/user_guide/ug_features2d.rst b/doc/user_guide/ug_features2d.rst index 2086e85db7..ac56336716 100644 --- a/doc/user_guide/ug_features2d.rst +++ b/doc/user_guide/ug_features2d.rst @@ -14,7 +14,7 @@ Matching keypoints ================== The code -------- +-------- We will start with a short sample ``opencv/samples/cpp/matcher_simple.cpp``: :: Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); diff --git a/doc/user_guide/ug_highgui.rst b/doc/user_guide/ug_highgui.rst index 58776624f9..a49dd3d047 100644 --- a/doc/user_guide/ug_highgui.rst +++ b/doc/user_guide/ug_highgui.rst @@ -12,7 +12,7 @@ Kinect sensor is supported through ``VideoCapture`` class. Depth map, RGB image In order to use Kinect with OpenCV you should do the following preliminary steps: #. - Install OpenNI library (from here \url{http://www.openni.org/downloadfiles}) and PrimeSensor Module for OpenNI (from here https://github.com/avin2/SensorKinect}). The installation should be done to default folders listed in the instructions of these products: + Install OpenNI library (from here \url{http://www.openni.org/downloadfiles}) and PrimeSensor Module for OpenNI (from here https://github.com/avin2/SensorKinect}). The installation should be done to default folders listed in the instructions of these products, e.g.: .. code-block:: text @@ -32,7 +32,7 @@ In order to use Kinect with OpenCV you should do the following preliminary steps If one or both products were installed to the other folders, the user should change corresponding CMake variables ``OPENNI_LIB_DIR``, ``OPENNI_INCLUDE_DIR`` or/and ``OPENNI_PRIME_SENSOR_MODULE_BIN_DIR``. #. - Configure OpenCV with OpenNI support by setting \texttt{WITH\_OPENNI} flag in CMake. If OpenNI is found in default install folders OpenCV will be built with OpenNI library regardless of whether PrimeSensor Module is found or not. If PrimeSensor Module was not found you will get a warning in CMake log. Without PrimeSensor module OpenCV will be successfully compiled with OpenNI library, but ``VideoCapture`` object will not grab data from Kinect sensor. + Configure OpenCV with OpenNI support by setting \texttt{WITH\_OPENNI} flag in CMake. If OpenNI is found in install folders OpenCV will be built with OpenNI library (see a status ``OpenNI`` in CMake log) whereas PrimeSensor Modules can not be found (see a status ``OpenNI PrimeSensor Modules`` in CMake log). Without PrimeSensor module OpenCV will be successfully compiled with OpenNI library, but ``VideoCapture`` object will not grab data from Kinect sensor. #. Build OpenCV. @@ -53,7 +53,7 @@ VideoCapture can retrieve the following Kinect data: In order to get depth map from Kinect use ``VideoCapture::operator >>``, e. g. :: - VideoCapture capture(0); // or CV_CAP_OPENNI + VideoCapture capture( CV_CAP_OPENNI ); for(;;) { Mat depthMap; @@ -80,4 +80,46 @@ For getting several Kinect maps use ``VideoCapture::grab`` and ``VideoCapture::r break; } +For setting and getting some property of Kinect data generators use ``VideoCapture::set`` and ``VideoCapture::get`` methods respectively, e.g. :: + + VideoCapture capture( CV_CAP_OPENNI ); + capture.set( CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, CV_CAP_OPENNI_VGA_30HZ ); + cout << "FPS " << capture.get( CV_CAP_OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FPS ) << endl; + +Since two types of Kinect's data generators are supported (image generator and depth generator), there are two flags that should be used to set/get property of the needed generator: + +* CV_CAP_OPENNI_IMAGE_GENERATOR -- A flag for access to the image generator properties. + +* CV_CAP_OPENNI_DEPTH_GENERATOR -- A flag for access to the depth generator properties. This flag value is assumed by default if neither of the two possible values of the property is not set. + +Flags specifing the needed generator type must be used in combination with particular generator property. The following properties of cameras available through OpenNI interfaces are supported: + +* + For image generator: + + - ``CV_CAP_PROP_OPENNI_OUTPUT_MODE`` -- Two output modes are supported: ``CV_CAP_OPENNI_VGA_30HZ`` used by default (image generator returns images in VGA resolution with 30 FPS) or ``CV_CAP_OPENNI_SXGA_15HZ`` (image generator returns images in SXGA resolution with 15 FPS); depth generator's maps are always in VGA resolution. + + +* + For depth generator: + + - ``CV_CAP_PROP_OPENNI_REGISTRATION`` -- Flag that synchronizes the remapping depth map to image map by changing depth generator's view point (if the flag is ``"on"``) or sets this view point to its normal one (if the flag is ``"off"``). + + Next properties are available for getting only: + + - ``CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH`` -- A maximum supported depth of Kinect in mm. + - ``CV_CAP_PROP_OPENNI_BASELINE`` -- Baseline value in mm. + - ``CV_CAP_PROP_OPENNI_FOCAL_LENGTH`` -- A focal length in pixels. + - ``CV_CAP_PROP_FRAME_WIDTH`` -- Frame width in pixels. + - ``CV_CAP_PROP_FRAME_HEIGHT`` -- Frame height in pixels. + - ``CV_CAP_PROP_FPS`` -- Frame rate in FPS. + +* + Some typical flags combinations "generator type + property" are defined as single flags: + + - ``CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE`` + - ``CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE`` + - ``CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH`` + - ``CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION_ON`` + For more information please refer to a Kinect example of usage ``kinect_maps.cpp`` in ``opencv/samples/cpp`` folder. diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index f08afa4ae4..f95853f2b6 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,8 +1,9 @@ file(GLOB old_hdrs "opencv/*.h*") install(FILES ${old_hdrs} - DESTINATION include/opencv + DESTINATION ${OPENCV_INCLUDE_PREFIX}/opencv + COMPONENT main) +install(FILES "opencv2/opencv.hpp" + DESTINATION ${OPENCV_INCLUDE_PREFIX}/opencv2 COMPONENT main) -install(FILES "opencv2/opencv.hpp" - DESTINATION include/opencv2 - COMPONENT main) + diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index 4d1c2afdab..5935d63c45 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -45,11 +45,10 @@ #include "opencv2/core/core_c.h" #include "opencv2/core/core.hpp" -#include "opencv2/flann/flann.hpp" +#include "opencv2/flann/miniflann.hpp" #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/video/tracking.hpp" -#include "opencv2/video/background_segm.hpp" +#include "opencv2/video/video.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/calib3d/calib3d.hpp" diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 040b81e21c..17d71f1fcb 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -3,8 +3,10 @@ if(ANDROID) if(ANDROID_API_LEVEL LESS 8) ADD_DEFINITIONS(-DGTEST_HAS_CLONE=0) endif() - - add_subdirectory(androidcamera) + + IF(WITH_ANDROID_CAMERA) + add_subdirectory(androidcamera) + endif() endif() add_subdirectory(calib3d) @@ -22,10 +24,14 @@ add_subdirectory(contrib) add_subdirectory(ml) add_subdirectory(objdetect) -if(PYTHONLIBS_FOUND AND BUILD_NEW_PYTHON_SUPPORT) +if(PYTHONLIBS_FOUND AND BUILD_NEW_PYTHON_SUPPORT AND PYTHON_USE_NUMPY) add_subdirectory(python) endif() +if(BUILD_JAVA_SUPPORT) + add_subdirectory(java) +endif() + add_subdirectory(video) add_subdirectory(traincascade) add_subdirectory(haartraining) diff --git a/modules/androidcamera/CMakeLists.txt b/modules/androidcamera/CMakeLists.txt index 908ebd2592..3f712cbc22 100644 --- a/modules/androidcamera/CMakeLists.txt +++ b/modules/androidcamera/CMakeLists.txt @@ -32,13 +32,13 @@ SET_TARGET_PROPERTIES(${the_target} PROPERTIES IF (NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} RUNTIME DESTINATION bin COMPONENT main - ARCHIVE DESTINATION lib COMPONENT main - LIBRARY DESTINATION lib COMPONENT main + ARCHIVE DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main + LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main ) ENDIF() -if (ARMEABI_V7A AND NOT BUILD_ANDROID_CAMERA_WRAPPER) - file(GLOB camera_wrappers "${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/lib/libnative_camera_r*.so") +if (NOT BUILD_ANDROID_CAMERA_WRAPPER) + file(GLOB camera_wrappers "${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/lib/${ARMEABI_NDK_NAME}/libnative_camera_r*.so") foreach(wrapper ${camera_wrappers}) ADD_CUSTOM_COMMAND( @@ -48,7 +48,7 @@ if (ARMEABI_V7A AND NOT BUILD_ANDROID_CAMERA_WRAPPER) ) get_filename_component(wrapper_name "${wrapper}" NAME) install(FILES "${LIBRARY_OUTPUT_PATH}/${wrapper_name}" - DESTINATION lib + DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main) endforeach() endif() diff --git a/modules/androidcamera/camera_wrapper/CMakeLists.txt b/modules/androidcamera/camera_wrapper/CMakeLists.txt index 1453f682cd..e0a1458521 100644 --- a/modules/androidcamera/camera_wrapper/CMakeLists.txt +++ b/modules/androidcamera/camera_wrapper/CMakeLists.txt @@ -33,8 +33,4 @@ SET_TARGET_PROPERTIES(${the_target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} ) -install(TARGETS ${the_target} - RUNTIME DESTINATION bin COMPONENT main - ARCHIVE DESTINATION lib COMPONENT main - LIBRARY DESTINATION lib COMPONENT main - ) \ No newline at end of file +install(TARGETS ${the_target} LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main) diff --git a/modules/androidcamera/camera_wrapper/camera_wrapper.cpp b/modules/androidcamera/camera_wrapper/camera_wrapper.cpp index 0bf10ac192..53af525974 100644 --- a/modules/androidcamera/camera_wrapper/camera_wrapper.cpp +++ b/modules/androidcamera/camera_wrapper/camera_wrapper.cpp @@ -1,5 +1,3 @@ -#define USE_RECORDING_INSTEAD_PREVIEW 0 - #if !defined(ANDROID_r2_2_2) && !defined(ANDROID_r2_3_3) && !defined(ANDROID_r3_0_1) #error unsupported version of Android #endif @@ -9,125 +7,115 @@ #include "../include/camera_properties.h" #include +//undef logging macro from /system/core/libcutils/loghack.h +#ifdef LOGD +#undef LOGD +#endif + +#ifdef LOGI +#undef LOGI +#endif + +#ifdef LOGW +#undef LOGW +#endif + +#ifdef LOGE +#undef LOGE +#endif + + +// LOGGING +#include +#define CAMERA_LOG_TAG "OpenCV_NativeCamera" +#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, CAMERA_LOG_TAG, __VA_ARGS__)) +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, CAMERA_LOG_TAG, __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, CAMERA_LOG_TAG, __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, CAMERA_LOG_TAG, __VA_ARGS__)) + using namespace android; void debugShowFPS() { static int mFrameCount = 0; static int mLastFrameCount = 0; - static nsecs_t mLastFpsTime = systemTime();; + static nsecs_t mLastFpsTime = systemTime(); static float mFps = 0; mFrameCount++; - if ( ( mFrameCount % 30 ) == 0 ) { - nsecs_t now = systemTime(); - nsecs_t diff = now - mLastFpsTime; - if (diff==0) - return; + if (( mFrameCount % 30 ) != 0) + return; - mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; - mLastFpsTime = now; - mLastFrameCount = mFrameCount; - LOGI("####### [%d] Frames, %f FPS", mFrameCount, mFps); - } + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFpsTime; + + if (diff==0) + return; + + mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFpsTime = now; + mLastFrameCount = mFrameCount; + LOGI("### Camera FPS ### [%d] Frames, %.2f FPS", mFrameCount, mFps); } class CameraHandler: public CameraListener { protected: - sp camera; - CameraCallback cameraCallback; - CameraParameters params; - void* userData; int cameraId; + sp camera; + CameraParameters params; + CameraCallback cameraCallback; + void* userData; - bool isEmptyCameraCallbackReported; - virtual void doCall(void* buffer, size_t bufferSize) + int emptyCameraCallbackReported; + + void doCall(void* buffer, size_t bufferSize) { if (cameraCallback == 0) { - if (!isEmptyCameraCallbackReported) - LOGE("Camera callback is empty!"); + if (!emptyCameraCallbackReported) + LOGE("CameraHandler::doCall(void*, size_t): Camera callback is empty!"); - isEmptyCameraCallbackReported = true; - return; + emptyCameraCallbackReported++; } + else + { + bool res = (*cameraCallback)(buffer, bufferSize, userData); - bool res = (*cameraCallback)(buffer, bufferSize, userData); - - if(!res) closeCameraConnect(); + if(!res) + { + LOGE("CameraHandler::doCall(void*, size_t): cameraCallback returns false (camera connection will be closed)"); + closeCameraConnect(); + } + } } - virtual void doCall(const sp& dataPtr) + void doCall(const sp& dataPtr) { - LOGI("doCall started"); - if (dataPtr == NULL) { - LOGE("CameraBuffer: dataPtr==NULL"); + LOGE("CameraHandler::doCall(const sp&): dataPtr==NULL (no frame to handle)"); return; } size_t size = dataPtr->size(); if (size <= 0) { - LOGE("CameraBuffer: IMemory object is of zero size"); + LOGE("CameraHandler::doCall(const sp&): IMemory object is of zero size"); return; } - unsigned char* buffer = (unsigned char *)dataPtr->pointer(); + void* buffer = (void *)dataPtr->pointer(); if (!buffer) { - LOGE("CameraBuffer: Buffer pointer is invalid"); + LOGE("CameraHandler::doCall(const sp&): Buffer pointer is NULL"); return; } doCall(buffer, size); } -public: - CameraHandler(CameraCallback callback = 0, void* _userData = 0):cameraCallback(callback), userData(_userData), cameraId(0), isEmptyCameraCallbackReported(false) {} - virtual ~CameraHandler() - { - LOGW("CameraHandler destructor is called!"); - } - - virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) - { - LOGE("Notify cb: %d %d %d\n", msgType, ext1, ext2); -#if 0 - if ( msgType & CAMERA_MSG_FOCUS ) - LOGE("AutoFocus %s in %llu us\n", (ext1) ? "OK" : "FAIL", timevalDelay(&autofocus_start)); - - if ( msgType & CAMERA_MSG_SHUTTER ) - LOGE("Shutter done in %llu us\n", timeval_delay(&picture_start)); -#endif - } - - virtual void postData(int32_t msgType, const sp& dataPtr) - { - debugShowFPS(); - - if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) - { - doCall(dataPtr); - return; - } - - if (msgType != CAMERA_MSG_PREVIEW_FRAME) - LOGE("Recieved not CAMERA_MSG_PREVIEW_FRAME message %d", (int) msgType); - - if ( msgType & CAMERA_MSG_RAW_IMAGE ) - LOGE("Unexpected data format: RAW\n"); - - if (msgType & CAMERA_MSG_POSTVIEW_FRAME) - LOGE("Unexpected data format: Postview frame\n"); - - if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) - LOGE("Unexpected data format: JPEG"); - } - virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp& dataPtr) { static uint32_t count = 0; @@ -152,6 +140,56 @@ public: camera->releaseRecordingFrame(dataPtr); } +public: + CameraHandler(CameraCallback callback = 0, void* _userData = 0): + cameraId(0), + cameraCallback(callback), + userData(_userData), + emptyCameraCallbackReported(0) + { + LOGD("Instantiated new CameraHandler (%p, %p)", callback, _userData); + } + + virtual ~CameraHandler() + { + LOGD("CameraHandler destructor is called"); + } + + virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) + { + LOGE("CameraHandler::Notify: msgType=%d ext1=%d ext2=%d\n", msgType, ext1, ext2); +#if 0 + if ( msgType & CAMERA_MSG_FOCUS ) + LOGE("CameraHandler::Notify AutoFocus %s in %llu us\n", (ext1) ? "OK" : "FAIL", timevalDelay(&autofocus_start)); + + if ( msgType & CAMERA_MSG_SHUTTER ) + LOGE("CameraHandler::Notify Shutter done in %llu us\n", timeval_delay(&picture_start)); +#endif + } + + virtual void postData(int32_t msgType, const sp& dataPtr) + { + debugShowFPS(); + + if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) + { + doCall(dataPtr); + return; + } + + if (msgType != CAMERA_MSG_PREVIEW_FRAME) + LOGE("CameraHandler::postData Recieved message %d is not equal to CAMERA_MSG_PREVIEW_FRAME (%d)", (int) msgType, CAMERA_MSG_PREVIEW_FRAME); + + if ( msgType & CAMERA_MSG_RAW_IMAGE ) + LOGE("CameraHandler::postData Unexpected data format: RAW\n"); + + if (msgType & CAMERA_MSG_POSTVIEW_FRAME) + LOGE("CameraHandler::postData Unexpected data format: Postview frame\n"); + + if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) + LOGE("CameraHandler::postData Unexpected data format: JPEG"); + } + static CameraHandler* initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters); void closeCameraConnect(); double getProperty(int propIdx); @@ -159,16 +197,13 @@ public: static void applyProperties(CameraHandler** ppcameraHandler); std::string cameraPropertySupportedPreviewSizesString; + std::string cameraPropertyPreviewFormatString; }; CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters) { -// if (camera != NULL) -// { -// LOGE("initCameraConnect: camera have been connected already"); -// return false; -// } + LOGD("CameraHandler::initCameraConnect(%p, %d, %p, %p)", callback, cameraId, userData, prevCameraParameters); sp camera = 0; @@ -179,7 +214,7 @@ CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, camera = Camera::connect(cameraId); #endif - if ( NULL == camera.get() ) + if ( 0 == camera.get() ) { LOGE("initCameraConnect: Unable to connect to CameraService\n"); return 0; @@ -189,35 +224,79 @@ CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, camera->setListener(handler); handler->camera = camera; - handler->cameraId=cameraId; -#if 1 - //setting paramers from previous camera handler - if (prevCameraParameters != NULL) { - camera->setParameters(prevCameraParameters->flatten()); + handler->cameraId = cameraId; + + if (prevCameraParameters != 0) + { + LOGI("initCameraConnect: Setting paramers from previous camera handler"); + camera->setParameters(prevCameraParameters->flatten()); + handler->params.unflatten(prevCameraParameters->flatten()); } -#endif - handler->params.unflatten(camera->getParameters()); + else + { + android::String8 params_str = camera->getParameters(); + LOGI("initCameraConnect: [%s]", params_str.string()); + + handler->params.unflatten(params_str); + + LOGD("Supported Cameras: %s", handler->params.get("camera-indexes")); + LOGD("Supported Picture Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES)); + LOGD("Supported Picture Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); + LOGD("Supported Preview Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)); + LOGD("Supported Preview Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS)); + LOGD("Supported Preview Frame Rates: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); + LOGD("Supported Thumbnail Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES)); + LOGD("Supported Whitebalance Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE)); + LOGD("Supported Effects: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_EFFECTS)); + LOGD("Supported Scene Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES)); + LOGD("Supported Focus Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); + LOGD("Supported Antibanding Options: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING)); + LOGD("Supported Flash Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES)); - LOGD("Supported Cameras: %s", handler->params.get("camera-indexes")); - LOGD("Supported Picture Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES)); - LOGD("Supported Picture Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); - LOGD("Supported Preview Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)); - LOGD("Supported Preview Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS)); - LOGD("Supported Preview Frame Rates: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); - LOGD("Supported Thumbnail Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES)); - LOGD("Supported Whitebalance Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE)); - LOGD("Supported Effects: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_EFFECTS)); - LOGD("Supported Scene Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES)); - LOGD("Supported Focus Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); - LOGD("Supported Antibanding Options: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING)); - LOGD("Supported Flash Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES)); + //check if yuv420sp format available. Set this format as preview format. + const char* available_formats = handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); + if (available_formats != 0) + { + const char* format_to_set = 0; + const char* pos = available_formats; + const char* ptr = pos; + while(true) + { + while(*ptr != 0 && *ptr != ',') ++ptr; + if (ptr != pos) + { + if (0 == strncmp(pos, "yuv420sp", ptr - pos)) + { + format_to_set = "yuv420sp"; + break; + } + if (0 == strncmp(pos, "yuv420i", ptr - pos)) + format_to_set = "yuv420i"; + } + if (*ptr == 0) + break; + pos = ++ptr; + } + if (0 != format_to_set) + { + handler->params.setPreviewFormat(format_to_set); - //TODO: check if yuv420i format available. Set this format as preview format. + status_t resParams = handler->camera->setParameters(handler->params.flatten()); -#if USE_RECORDING_INSTEAD_PREVIEW - status_t err = camera->setPreviewDisplay(sp(NULL /*new DummySurface1*/)); + if (resParams != 0) + LOGE("initCameraConnect: failed to set preview format to %s", format_to_set); + else + LOGD("initCameraConnect: preview format is set to %s", format_to_set); + } + } + } + +#ifdef ANDROID_r2_2_2 + status_t pdstatus = camera->setPreviewDisplay(sp(0 /*new DummySurface*/)); + if (pdstatus != 0) + LOGE("initCameraConnect: failed setPreviewDisplay(0) call; camera migth not work correcttly on some devices"); #endif ////ATTENTION: switching between two versions: with and without copying memory inside Android OS @@ -228,17 +307,15 @@ CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, camera->setPreviewCallbackFlags( FRAME_CALLBACK_FLAG_ENABLE_MASK );//without copy #endif -#if USE_RECORDING_INSTEAD_PREVIEW - status_t resStart = camera->startRecording(); -#else status_t resStart = camera->startPreview(); -#endif if (resStart != 0) { + LOGE("initCameraConnect: startPreview() fails. Closing camera connection..."); handler->closeCameraConnect(); handler = 0; } + return handler; } @@ -246,17 +323,11 @@ void CameraHandler::closeCameraConnect() { if (camera == NULL) { - LOGI("... camera is NULL"); + LOGI("... camera is already NULL"); return; } - //TODO: ATTENTION! should we do it ALWAYS??? -#if USE_RECORDING_INSTEAD_PREVIEW - camera->stopRecording(); -#else camera->stopPreview(); -#endif - camera->disconnect(); camera.clear(); @@ -285,28 +356,50 @@ void CameraHandler::closeCameraConnect() double CameraHandler::getProperty(int propIdx) { + LOGD("CameraHandler::getProperty(%d)", propIdx); + switch (propIdx) { case ANDROID_CAMERA_PROPERTY_FRAMEWIDTH: { int w,h; - params.getPreviewSize(&w,&h); + params.getPreviewSize(&w, &h); return w; } case ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT: { int w,h; - params.getPreviewSize(&w,&h); + params.getPreviewSize(&w, &h); return h; } case ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING: { - cameraPropertySupportedPreviewSizesString=params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES); - double res; - memset(&res, 0, sizeof(res)); - (*( (void**)&res ))= (void*)( cameraPropertySupportedPreviewSizesString.c_str() ); - - return res; + cameraPropertySupportedPreviewSizesString = params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES); + union {const char* str;double res;} u; + memset(&u.res, 0, sizeof(u.res)); + u.str = cameraPropertySupportedPreviewSizesString.c_str(); + return u.res; + } + + case ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING: + { + const char* fmt = params.get(CameraParameters::KEY_PREVIEW_FORMAT); + if (fmt == CameraParameters::PIXEL_FORMAT_YUV422SP) + fmt = "yuv422sp"; + else if (fmt == CameraParameters::PIXEL_FORMAT_YUV420SP) + fmt = "yuv420sp"; + else if (fmt == CameraParameters::PIXEL_FORMAT_YUV422I) + fmt = "yuv422i"; + else if (fmt == CameraParameters::PIXEL_FORMAT_RGB565) + fmt = "rgb565"; + else if (fmt == CameraParameters::PIXEL_FORMAT_JPEG) + fmt = "jpeg"; + cameraPropertyPreviewFormatString = fmt; + + union {const char* str;double res;} u; + memset(&u.res, 0, sizeof(u.res)); + u.str = cameraPropertyPreviewFormatString.c_str(); + return u.res; } }; @@ -315,22 +408,24 @@ double CameraHandler::getProperty(int propIdx) void CameraHandler::setProperty(int propIdx, double value) { + LOGD("CameraHandler::setProperty(%d, %f)", propIdx, value); + switch (propIdx) { case ANDROID_CAMERA_PROPERTY_FRAMEWIDTH: { int w,h; - params.getPreviewSize(&w,&h); + params.getPreviewSize(&w, &h); w = (int)value; - params.setPreviewSize(w,h); + params.setPreviewSize(w, h); } break; case ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT: { int w,h; - params.getPreviewSize(&w,&h); + params.getPreviewSize(&w, &h); h = (int)value; - params.setPreviewSize(w,h); + params.setPreviewSize(w, h); } break; }; @@ -338,6 +433,20 @@ void CameraHandler::setProperty(int propIdx, double value) void CameraHandler::applyProperties(CameraHandler** ppcameraHandler) { + LOGD("CameraHandler::applyProperties()"); + + if (ppcameraHandler == 0) + { + LOGE("applyProperties: Passed NULL ppcameraHandler"); + return; + } + + if (*ppcameraHandler == 0) + { + LOGE("applyProperties: Passed null *ppcameraHandler"); + return; + } + LOGD("CameraHandler::applyProperties()"); CameraHandler* previousCameraHandler=*ppcameraHandler; CameraParameters curCameraParameters(previousCameraHandler->params.flatten()); @@ -355,12 +464,12 @@ void CameraHandler::applyProperties(CameraHandler** ppcameraHandler) CameraHandler* handler=initCameraConnect(cameraCallback, cameraId, userData, &curCameraParameters); LOGD("CameraHandler::applyProperties(): after initCameraConnect, handler=0x%x", (int)handler); if (handler == NULL) { - LOGE("ERROR in applyProperties --- cannot reinit camera"); - handler=initCameraConnect(cameraCallback, cameraId, userData, NULL); - LOGD("CameraHandler::applyProperties(): repeate initCameraConnect after ERROR, handler=0x%x", (int)handler); - if (handler == NULL) { - LOGE("ERROR in applyProperties --- cannot reinit camera AGAIN --- cannot do anything else"); - } + LOGE("ERROR in applyProperties --- cannot reinit camera"); + handler=initCameraConnect(cameraCallback, cameraId, userData, NULL); + LOGD("CameraHandler::applyProperties(): repeate initCameraConnect after ERROR, handler=0x%x", (int)handler); + if (handler == NULL) { + LOGE("ERROR in applyProperties --- cannot reinit camera AGAIN --- cannot do anything else"); + } } (*ppcameraHandler)=handler; } @@ -392,7 +501,7 @@ void setCameraPropertyC(void* camera, int propIdx, double value) void applyCameraPropertiesC(void** camera) { - CameraHandler::applyProperties((CameraHandler**)camera); + CameraHandler::applyProperties((CameraHandler**)camera); } } diff --git a/modules/androidcamera/camera_wrapper/camera_wrapper.h b/modules/androidcamera/camera_wrapper/camera_wrapper.h index f1ae6bda62..c1ba67e430 100644 --- a/modules/androidcamera/camera_wrapper/camera_wrapper.h +++ b/modules/androidcamera/camera_wrapper/camera_wrapper.h @@ -1,10 +1,3 @@ -enum CameraWrapperErrorCode { - ERROR_NATIVE_CAMERA_WRAPPER_NOERROR = 0, - ERROR_NATIVE_CAMERA_WRAPPER_CANNOT_FIND_CLASS = 1, - ERROR_NATIVE_CAMERA_WRAPPER_CANNOT_FIND_FIELD = 2, - ERROR_NATIVE_CAMERA_WRAPPER_CANNOT_SET_PREVIEW_DISPLAY = 3 -}; - typedef bool (*CameraCallback)(void* buffer, size_t bufferSize, void* userData); typedef void* (*InitCameraConnectC)(void* cameraCallback, int cameraId, void* userData); diff --git a/modules/androidcamera/include/camera_properties.h b/modules/androidcamera/include/camera_properties.h index 42202e3696..56cbb74336 100644 --- a/modules/androidcamera/include/camera_properties.h +++ b/modules/androidcamera/include/camera_properties.h @@ -4,7 +4,8 @@ enum { ANDROID_CAMERA_PROPERTY_FRAMEWIDTH = 0, ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT = 1, - ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING = 2 + ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING = 2, + ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING = 3 }; #endif // CAMERA_PROPERTIES_H diff --git a/modules/androidcamera/src/camera_activity.cpp b/modules/androidcamera/src/camera_activity.cpp index ca612b354b..c8a72deee7 100644 --- a/modules/androidcamera/src/camera_activity.cpp +++ b/modules/androidcamera/src/camera_activity.cpp @@ -133,7 +133,7 @@ CameraActivity::ErrorCode CameraWrapperConnector::getProperty(void* camera, int LOGE("CameraWrapperConnector::getProperty error: wrong pointer to camera object"); return CameraActivity::ERROR_WRONG_POINTER_CAMERA_WRAPPER; } - + LOGE("calling (*pGetPropertyC)(%p, %d)", camera, propIdx); *value = (*pGetPropertyC)(camera, propIdx); return CameraActivity::NO_ERROR; } @@ -238,7 +238,7 @@ void CameraWrapperConnector::fillListWrapperLibs(const string& folderPath, vecto dp = opendir (folderPath.c_str()); if (dp != NULL) { - while (ep = readdir (dp)) { + while ((ep = readdir (dp))) { const char* cur_name=ep->d_name; if (strstr(cur_name, PREFIX_CAMERA_WRAPPER_LIB)) { listLibs.push_back(cur_name); @@ -260,9 +260,9 @@ std::string CameraWrapperConnector::getPathLibFolder() LOGD("Library name: %s", dl_info.dli_fname); LOGD("Library base address: %p", dl_info.dli_fbase); - char addrBuf[18]; - sprintf(addrBuf, "%x-", dl_info.dli_fbase); - int addrLength = strlen(addrBuf); + const char* libName=dl_info.dli_fname; + while( ((*libName)=='/') || ((*libName)=='.') ) + libName++; char lineBuf[2048]; FILE* file = fopen("/proc/self/smaps", "rt"); @@ -271,11 +271,9 @@ std::string CameraWrapperConnector::getPathLibFolder() { while (fgets(lineBuf, sizeof lineBuf, file) != NULL) { - if(0 == strncmp(lineBuf, addrBuf, addrLength)) - { //verify that line ends with library name int lineLength = strlen(lineBuf); - int libNameLength = strlen(dl_info.dli_fname); + int libNameLength = strlen(libName); //trim end for(int i = lineLength - 1; i >= 0 && isspace(lineBuf[i]); --i) @@ -284,9 +282,9 @@ std::string CameraWrapperConnector::getPathLibFolder() --lineLength; } - if (0 != strncmp(lineBuf + lineLength - libNameLength, dl_info.dli_fname, libNameLength)) + if (0 != strncmp(lineBuf + lineLength - libNameLength, libName, libNameLength)) { - LOGE("Strange error: line \"%s\" does not ends with library name %s", lineBuf, dl_info.dli_fname); + //the line does not contain the library name continue; } @@ -305,7 +303,6 @@ std::string CameraWrapperConnector::getPathLibFolder() fclose(file); return pathBegin; - } } fclose(file); LOGE("Could not find library path."); diff --git a/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst b/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst index 595df206d9..a83c7017b2 100644 --- a/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst +++ b/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst @@ -35,6 +35,7 @@ where: * :math:`(cx, cy)` is a principal point that is usually at the image center * :math:`fx, fy` are the focal lengths expressed in pixel-related units + Thus, if an image from the camera is scaled by a factor, all of these parameters should be scaled (multiplied/divided, respectively) by the same factor. The @@ -110,9 +111,9 @@ calibrateCamera --------------- Finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern. -.. ocv:function:: double calibrateCamera( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs, OutputArray rvecs, OutputArray tvecs, int flags=0 ) +.. ocv:function:: double calibrateCamera( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags=0 ) -.. ocv:pyfunction:: cv2.calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs[, rvecs[, tvecs[, flags]]]) -> retval, cameraMatrix, distCoeffs, rvecs, tvecs +.. ocv:pyfunction:: cv2.calibrateCamera(objectPoints, imagePoints, imageSize[, cameraMatrix[, distCoeffs[, rvecs[, tvecs[, flags]]]]]) -> retval, cameraMatrix, distCoeffs, rvecs, tvecs .. ocv:cfunction:: double cvCalibrateCamera2( const CvMat* objectPoints, const CvMat* imagePoints, const CvMat* pointCounts, CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs, CvMat* rvecs=NULL, CvMat* tvecs=NULL, int flags=0 ) @@ -136,7 +137,7 @@ Finds the camera intrinsic and extrinsic parameters from several views of a cali :param rvecs: Output vector of rotation vectors (see :ocv:func:`Rodrigues` ) estimated for each pattern view. That is, each k-th rotation vector together with the corresponding k-th translation vector (see the next output parameter description) brings the calibration pattern from the model coordinate space (in which object points are specified) to the world coordinate space, that is, a real position of the calibration pattern in the k-th pattern view (k=0.. *M* -1). - :param tvecs: Output vector of translation vectors estimated for each pattern view. + :param tvecs: Output vector of translation vectors estimated for each pattern view. :param flags: Different flags that may be zero or a combination of the following values: @@ -179,7 +180,7 @@ The function returns the final re-projection error. .. note:: - If you use a non-square (=non-NxN) grid and :ocv:func:`findChessboardCorners` for calibration, and ``calibrateCamera`` returns bad values (zero distortion coefficients, an image center very far from ``(w/2-0.5,h/2-0.5)``, and/or large differences between :math:`f_x` and :math:`f_y` (ratios of 10:1 or more)), then you have probably used ``patternSize=cvSize(rows,cols)`` instead of using ``patternSize=cvSize(cols,rows)`` in :ocv:func:`findChessboardCorners` . + If you use a non-square (=non-NxN) grid and :ocv:func:`findChessboardCorners` for calibration, and ``calibrateCamera`` returns bad values (zero distortion coefficients, an image center very far from ``(w/2-0.5,h/2-0.5)``, and/or large differences between :math:`f_x` and :math:`f_y` (ratios of 10:1 or more)), then you have probably used ``patternSize=cvSize(rows,cols)`` instead of using ``patternSize=cvSize(cols,rows)`` in :ocv:func:`findChessboardCorners` . .. seealso:: @@ -534,7 +535,7 @@ Finds an object pose from 3D-2D point correspondences. :param imagePoints: Array of corresponding image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel, where N is the number of points. ``vector`` can be also passed here. :param cameraMatrix: Input camera matrix :math:`A = \vecthreethree{fx}{0}{cx}{0}{fy}{cy}{0}{0}{1}` . - + :param distCoeffs: Input vector of distortion coefficients :math:`(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])` of 4, 5, or 8 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. :param rvec: Output rotation vector (see :ocv:func:`Rodrigues` ) that, together with ``tvec`` , brings points from the model coordinate system to the camera coordinate system. @@ -597,7 +598,7 @@ Calculates a fundamental matrix from the corresponding points in two images. :param points1: Array of ``N`` points from the first image. The point coordinates should be floating-point (single or double precision). :param points2: Array of the second image points of the same size and format as ``points1`` . - + :param method: Method for computing a fundamental matrix. * **CV_FM_7POINT** for a 7-point algorithm. :math:`N = 7` @@ -605,7 +606,7 @@ Calculates a fundamental matrix from the corresponding points in two images. * **CV_FM_RANSAC** for the RANSAC algorithm. :math:`N \ge 8` * **CV_FM_LMEDS** for the LMedS algorithm. :math:`N \ge 8` - :param param1: Parameter used for RANSAC. It is the maximum distance from a point to an epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the point localization, image resolution, and the image noise. + :param param1: Parameter used for RANSAC. It is the maximum distance from a point to an epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the point localization, image resolution, and the image noise. :param param2: Parameter used for the RANSAC or LMedS methods only. It specifies a desirable level of confidence (probability) that the estimated matrix is correct. @@ -779,11 +780,12 @@ getOptimalNewCameraMatrix ----------------------------- Returns the new camera matrix based on the free scaling parameter. -.. ocv:function:: Mat getOptimalNewCameraMatrix( InputArray cameraMatrix, InputArray distCoeffs, Size imageSize, double alpha, Size newImageSize=Size(), Rect* validPixROI=0) +.. ocv:function:: Mat getOptimalNewCameraMatrix( InputArray cameraMatrix, InputArray distCoeffs, Size imageSize, double alpha, Size newImageSize=Size(), Rect* validPixROI=0, bool centerPrincipalPoint=false) -.. ocv:pyfunction:: cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, alpha[, newImgSize]) -> retval, validPixROI +.. ocv:pyfunction:: cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, alpha[, newImgSize[, centerPrincipalPoint]]) -> retval, validPixROI + +.. ocv:cfunction:: void cvGetOptimalNewCameraMatrix( const CvMat* cameraMatrix, const CvMat* distCoeffs, CvSize imageSize, double alpha, CvMat* newCameraMatrix, CvSize newImageSize=cvSize(0, 0), CvRect* validPixROI=0, int centerPrincipalPoint=0) -.. ocv:cfunction:: void cvGetOptimalNewCameraMatrix( const CvMat* cameraMatrix, const CvMat* distCoeffs, CvSize imageSize, double alpha, CvMat* newCameraMatrix, CvSize newImageSize=cvSize(0, 0), CvRect* validPixROI=0 ) .. ocv:pyoldfunction:: cv.GetOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, alpha, newCameraMatrix, newImageSize=(0, 0), validPixROI=0) -> None :param cameraMatrix: Input camera matrix. @@ -799,6 +801,8 @@ Returns the new camera matrix based on the free scaling parameter. :param newImageSize: Image size after rectification. By default,it is set to ``imageSize`` . :param validPixROI: Optional output rectangle that outlines all-good-pixels region in the undistorted image. See ``roi1, roi2`` description in :ocv:func:`StereoRectify` . + + :param centerPrincipalPoint: Optional flag that indicates whether in the new camera matrix the principal point should be at the image center or not. By default, the principal point is chosen to best fit a subset of the source image (determined by ``alpha``) to the corrected image. The function computes and returns the optimal new camera matrix based on the free scaling parameter. By varying this parameter, you may retrieve only sensible pixels ``alpha=0`` , keep all the original image pixels if there is valuable information in the corners ``alpha=1`` , or get something in between. When ``alpha>0`` , the undistortion result is likely to have some black pixels corresponding to "virtual" pixels outside of the captured distorted image. The original camera matrix, distortion coefficients, the computed new camera matrix, and ``newImageSize`` should be passed to @@ -848,7 +852,7 @@ Computes partial derivatives of the matrix product for each multiplied matrix. :param dABdA: First output derivative matrix ``d(A*B)/dA`` of size :math:`\texttt{A.rows*B.cols} \times {A.rows*A.cols}` . - :param dABdA: Second output derivative matrix ``d(A*B)/dB`` of size :math:`\texttt{A.rows*B.cols} \times {B.rows*B.cols}` . + :param dABdB: Second output derivative matrix ``d(A*B)/dB`` of size :math:`\texttt{A.rows*B.cols} \times {B.rows*B.cols}` . The function computes partial derivatives of the elements of the matrix product :math:`A*B` with regard to the elements of each of the two input matrices. The function is used to compute the Jacobian matrices in @@ -911,7 +915,7 @@ Reprojects a disparity image to 3D space. .. ocv:cfunction:: void cvReprojectImageTo3D( const CvArr* disparity, CvArr* _3dImage, const CvMat* Q, int handleMissingValues=0) .. ocv:pyoldfunction:: cv.ReprojectImageTo3D(disparity, _3dImage, Q, handleMissingValues=0) -> None - :param disparity: Input single-channel 16-bit signed or 32-bit floating-point disparity image. + :param disparity: Input single-channel 8-bit unsigned, 16-bit signed, 32-bit signed or 32-bit floating-point disparity image. :param _3dImage: Output 3-channel floating-point image of the same size as ``disparity`` . Each element of ``_3dImage(x,y)`` contains 3D coordinates of the point ``(x,y)`` computed from the disparity map. @@ -1196,11 +1200,11 @@ The method executes the SGBM algorithm on a rectified stereo pair. See ``stereo_ stereoCalibrate ------------------- +Calibrates the stereo camera. + .. ocv:function:: double stereoCalibrate( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputOutputArray cameraMatrix1, InputOutputArray distCoeffs1, InputOutputArray cameraMatrix2, InputOutputArray distCoeffs2, Size imageSize, OutputArray R, OutputArray T, OutputArray E, OutputArray F, TermCriteria term_crit = TermCriteria(TermCriteria::COUNT+ TermCriteria::EPS, 30, 1e-6), int flags=CALIB_FIX_INTRINSIC ) - Calibrates the stereo camera. - -.. ocv:pyfunction:: cv2.stereoCalibrate(objectPoints, imagePoints1, imagePoints2, cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize[, R[, T[, E[, F[, criteria[, flags]]]]]]) -> retval, cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, R, T, E, F +.. ocv:pyfunction:: cv2.stereoCalibrate(objectPoints, imagePoints1, imagePoints2, imageSize[, cameraMatrix1[, distCoeffs1[, cameraMatrix2[, distCoeffs2[, R[, T[, E[, F[, criteria[, flags]]]]]]) -> retval, cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, R, T, E, F .. ocv:cfunction:: double cvStereoCalibrate( const CvMat* objectPoints, const CvMat* imagePoints1, const CvMat* imagePoints2, const CvMat* pointCounts, CvMat* cameraMatrix1, CvMat* distCoeffs1, CvMat* cameraMatrix2, CvMat* distCoeffs2, CvSize imageSize, CvMat* R, CvMat* T, CvMat* E=0, CvMat* F=0, CvTermCriteria termCrit=cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 30, 1e-6), int flags=CV_CALIB_FIX_INTRINSIC ) .. ocv:pyoldfunction:: cv.StereoCalibrate( objectPoints, imagePoints1, imagePoints2, pointCounts, cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize, R, T, E=None, F=None, termCrit=(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 30, 1e-6), flags=CV_CALIB_FIX_INTRINSIC)-> None @@ -1211,8 +1215,7 @@ stereoCalibrate :param imagePoints2: Vector of vectors of the projections of the calibration pattern points, observed by the second camera. - :param cameraMatrix1: Input/output first camera matrix: :math:`\vecthreethree{f_x^{(j)}}{0}{c_x^{(j)}}{0}{f_y^{(j)}}{c_y^{(j)}}{0}{0}{1}` , - :math:`j = 0,\, 1` . If any of ``CV_CALIB_USE_INTRINSIC_GUESS`` , ``CV_CALIB_FIX_ASPECT_RATIO`` , ``CV_CALIB_FIX_INTRINSIC`` , or ``CV_CALIB_FIX_FOCAL_LENGTH`` are specified, some or all of the matrix components must be initialized. See the flags description for details. + :param cameraMatrix1: Input/output first camera matrix: :math:`\vecthreethree{f_x^{(j)}}{0}{c_x^{(j)}}{0}{f_y^{(j)}}{c_y^{(j)}}{0}{0}{1}` , :math:`j = 0,\, 1` . If any of ``CV_CALIB_USE_INTRINSIC_GUESS`` , ``CV_CALIB_FIX_ASPECT_RATIO`` , ``CV_CALIB_FIX_INTRINSIC`` , or ``CV_CALIB_FIX_FOCAL_LENGTH`` are specified, some or all of the matrix components must be initialized. See the flags description for details. :param distCoeffs1: Input/output vector of distortion coefficients :math:`(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])` of 4, 5, or 8 elements. The output vector length depends on the flags. @@ -1245,7 +1248,7 @@ stereoCalibrate * **CV_CALIB_FIX_ASPECT_RATIO** Optimize :math:`f^{(j)}_y` . Fix the ratio :math:`f^{(j)}_x/f^{(j)}_y` . * **CV_CALIB_SAME_FOCAL_LENGTH** Enforce :math:`f^{(0)}_x=f^{(1)}_x` and :math:`f^{(0)}_y=f^{(1)}_y` . - + * **CV_CALIB_ZERO_TANGENT_DIST** Set tangential distortion coefficients for each camera to zeros and fix there. * **CV_CALIB_FIX_K1,...,CV_CALIB_FIX_K6** Do not change the corresponding radial distortion coefficient during the optimization. If ``CV_CALIB_USE_INTRINSIC_GUESS`` is set, the coefficient from the supplied ``distCoeffs`` matrix is used. Otherwise, it is set to 0. @@ -1287,11 +1290,10 @@ Similarly to :ocv:func:`calibrateCamera` , the function minimizes the total re-p stereoRectify ----------------- +Computes rectification transforms for each head of a calibrated stereo camera. .. ocv:function:: void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2, InputArray distCoeffs2, Size imageSize, InputArray R, InputArray T, OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY, double alpha, Size newImageSize=Size(), Rect* roi1=0, Rect* roi2=0 ) - Computes rectification transforms for each head of a calibrated stereo camera. - .. ocv:cfunction:: void cvStereoRectify( const CvMat* cameraMatrix1, const CvMat* cameraMatrix2, const CvMat* distCoeffs1, const CvMat* distCoeffs2, CvSize imageSize, const CvMat* R, const CvMat* T, CvMat* R1, CvMat* R2, CvMat* P1, CvMat* P2, CvMat* Q=0, int flags=CV_CALIB_ZERO_DISPARITY, double alpha=-1, CvSize newImageSize=cvSize(0, 0), CvRect* roi1=0, CvRect* roi2=0) .. ocv:pyoldfunction:: cv.StereoRectify( cameraMatrix1, cameraMatrix2, distCoeffs1, distCoeffs2, imageSize, R, T, R1, R2, P1, P2, Q=None, flags=CV_CALIB_ZERO_DISPARITY, alpha=-1, newImageSize=(0, 0))-> (roi1, roi2) @@ -1374,13 +1376,14 @@ See below the screenshot from the ``stereo_calib.cpp`` sample. Some red horizont stereoRectifyUncalibrated ----------------------------- -.. ocv:function:: bool stereoRectifyUncalibrated( InputArray points1, InputArray points2, InputArray F, Size imgSize, OutputArray H1, OutputArray H2, double threshold=5 ) +Computes a rectification transform for an uncalibrated stereo camera. - Computes a rectification transform for an uncalibrated stereo camera. +.. ocv:function:: bool stereoRectifyUncalibrated( InputArray points1, InputArray points2, InputArray F, Size imgSize, OutputArray H1, OutputArray H2, double threshold=5 ) .. ocv:pyfunction:: cv2.stereoRectifyUncalibrated(points1, points2, F, imgSize[, H1[, H2[, threshold]]]) -> retval, H1, H2 .. ocv:cfunction:: void cvStereoRectifyUncalibrated( const CvMat* points1, const CvMat* points2, const CvMat* F, CvSize imageSize, CvMat* H1, CvMat* H2, double threshold=5 ) + .. ocv:pyoldfunction:: cv.StereoRectifyUncalibrated(points1, points2, F, imageSize, H1, H2, threshold=5)-> None :param points1: Array of feature points in the first image. @@ -1407,6 +1410,6 @@ The function computes the rectification transformations without knowing intrinsi .. [BouguetMCT] J.Y.Bouguet. MATLAB calibration tool. http://www.vision.caltech.edu/bouguetj/calib_doc/ -.. [Hartley99] Hartley, R.I., “Theory and Practice of Projective Rectification”. IJCV 35 2, pp 115-127 (1999) +.. [Hartley99] Hartley, R.I., Theory and Practice of Projective Rectification. IJCV 35 2, pp 115-127 (1999) -.. [Zhang2000] Z. Zhang. A Flexible New Technique for Camera Calibration. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(11):1330-1334, 2000. \ No newline at end of file +.. [Zhang2000] Z. Zhang. A Flexible New Technique for Camera Calibration. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(11):1330-1334, 2000. diff --git a/modules/calib3d/include/opencv2/calib3d/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d/calib3d.hpp index 83361bd235..81924805f1 100644 --- a/modules/calib3d/include/opencv2/calib3d/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d/calib3d.hpp @@ -120,7 +120,8 @@ CVAPI(void) cvGetOptimalNewCameraMatrix( const CvMat* camera_matrix, CvSize image_size, double alpha, CvMat* new_camera_matrix, CvSize new_imag_size CV_DEFAULT(cvSize(0,0)), - CvRect* valid_pixel_ROI CV_DEFAULT(0) ); + CvRect* valid_pixel_ROI CV_DEFAULT(0), + int center_principal_point CV_DEFAULT(0)); /* Converts rotation vector to rotation matrix or vice versa */ CVAPI(int) cvRodrigues2( const CvMat* src, CvMat* dst, @@ -535,6 +536,9 @@ CV_EXPORTS bool findCirclesGrid( InputArray image, Size patternSize, OutputArray centers, int flags=CALIB_CB_SYMMETRIC_GRID, const Ptr &blobDetector = new SimpleBlobDetector()); +CV_EXPORTS_W bool findCirclesGridDefault( InputArray image, Size patternSize, + OutputArray centers, int flags=CALIB_CB_SYMMETRIC_GRID ); + enum { CALIB_USE_INTRINSIC_GUESS = CV_CALIB_USE_INTRINSIC_GUESS, @@ -560,8 +564,8 @@ enum CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size imageSize, - CV_IN_OUT InputOutputArray cameraMatrix, - CV_IN_OUT InputOutputArray distCoeffs, + CV_OUT InputOutputArray cameraMatrix, + CV_OUT InputOutputArray distCoeffs, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags=0 ); @@ -580,10 +584,10 @@ CV_EXPORTS_W void calibrationMatrixValues( InputArray cameraMatrix, CV_EXPORTS_W double stereoCalibrate( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, - CV_IN_OUT InputOutputArray cameraMatrix1, - CV_IN_OUT InputOutputArray distCoeffs1, - CV_IN_OUT InputOutputArray cameraMatrix2, - CV_IN_OUT InputOutputArray distCoeffs2, + CV_OUT InputOutputArray cameraMatrix1, + CV_OUT InputOutputArray distCoeffs1, + CV_OUT InputOutputArray cameraMatrix2, + CV_OUT InputOutputArray distCoeffs2, Size imageSize, OutputArray R, OutputArray T, OutputArray E, OutputArray F, TermCriteria criteria = TermCriteria(TermCriteria::COUNT+ @@ -622,7 +626,7 @@ CV_EXPORTS_W float rectify3Collinear( InputArray cameraMatrix1, InputArray distC //! returns the optimal new camera matrix CV_EXPORTS_W Mat getOptimalNewCameraMatrix( InputArray cameraMatrix, InputArray distCoeffs, Size imageSize, double alpha, Size newImgSize=Size(), - CV_OUT Rect* validPixROI=0); + CV_OUT Rect* validPixROI=0, bool centerPrincipalPoint=false); //! converts point coordinates from normal pixel coordinates to homogeneous coordinates ((x,y)->(x,y,1)) CV_EXPORTS_W void convertPointsToHomogeneous( InputArray src, OutputArray dst ); diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp index 04392a2ba4..362b62f98c 100644 --- a/modules/calib3d/src/calibinit.cpp +++ b/modules/calib3d/src/calibinit.cpp @@ -1939,8 +1939,8 @@ void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize, bool cv::findCirclesGrid( InputArray _image, Size patternSize, OutputArray _centers, int flags, const Ptr &blobDetector ) { - bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID) ? true : false; - bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false; + bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID) ? true : false; + bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false; CV_Assert(isAsymmetricGrid ^ isSymmetricGrid); Mat image = _image.getMat(); diff --git a/modules/calib3d/src/calibration.cpp b/modules/calib3d/src/calibration.cpp index a35aa7d5bc..43a011f9fe 100644 --- a/modules/calib3d/src/calibration.cpp +++ b/modules/calib3d/src/calibration.cpp @@ -2529,46 +2529,81 @@ void cvStereoRectify( const CvMat* _cameraMatrix1, const CvMat* _cameraMatrix2, void cvGetOptimalNewCameraMatrix( const CvMat* cameraMatrix, const CvMat* distCoeffs, CvSize imgSize, double alpha, CvMat* newCameraMatrix, CvSize newImgSize, - CvRect* validPixROI ) + CvRect* validPixROI, int centerPrincipalPoint ) { cv::Rect_ inner, outer; - icvGetRectangles( cameraMatrix, distCoeffs, 0, cameraMatrix, imgSize, inner, outer ); - newImgSize = newImgSize.width*newImgSize.height != 0 ? newImgSize : imgSize; double M[3][3]; CvMat matM = cvMat(3, 3, CV_64F, M); cvConvert(cameraMatrix, &matM); - double cx0 = M[0][2]; - double cy0 = M[1][2]; - double cx = (newImgSize.width-1)*0.5; - double cy = (newImgSize.height-1)*0.5; - - double s0 = std::max(std::max(std::max((double)cx/(cx0 - inner.x), (double)cy/(cy0 - inner.y)), - (double)cx/(inner.x + inner.width - cx0)), - (double)cy/(inner.y + inner.height - cy0)); - double s1 = std::min(std::min(std::min((double)cx/(cx0 - outer.x), (double)cy/(cy0 - outer.y)), - (double)cx/(outer.x + outer.width - cx0)), - (double)cy/(outer.y + outer.height - cy0)); - double s = s0*(1 - alpha) + s1*alpha; - - M[0][0] *= s; - M[1][1] *= s; - M[0][2] = cx; - M[1][2] = cy; - cvConvert(&matM, newCameraMatrix); - - if( validPixROI ) + if( centerPrincipalPoint ) { - inner = cv::Rect_((float)((inner.x - cx0)*s + cx), - (float)((inner.y - cy0)*s + cy), - (float)(inner.width*s), - (float)(inner.height*s)); - cv::Rect r(cvCeil(inner.x), cvCeil(inner.y), cvFloor(inner.width), cvFloor(inner.height)); - r &= cv::Rect(0, 0, newImgSize.width, newImgSize.height); - *validPixROI = r; + double cx0 = M[0][2]; + double cy0 = M[1][2]; + double cx = (newImgSize.width-1)*0.5; + double cy = (newImgSize.height-1)*0.5; + + icvGetRectangles( cameraMatrix, distCoeffs, 0, cameraMatrix, imgSize, inner, outer ); + double s0 = std::max(std::max(std::max((double)cx/(cx0 - inner.x), (double)cy/(cy0 - inner.y)), + (double)cx/(inner.x + inner.width - cx0)), + (double)cy/(inner.y + inner.height - cy0)); + double s1 = std::min(std::min(std::min((double)cx/(cx0 - outer.x), (double)cy/(cy0 - outer.y)), + (double)cx/(outer.x + outer.width - cx0)), + (double)cy/(outer.y + outer.height - cy0)); + double s = s0*(1 - alpha) + s1*alpha; + + M[0][0] *= s; + M[1][1] *= s; + M[0][2] = cx; + M[1][2] = cy; + + if( validPixROI ) + { + inner = cv::Rect_((float)((inner.x - cx0)*s + cx), + (float)((inner.y - cy0)*s + cy), + (float)(inner.width*s), + (float)(inner.height*s)); + cv::Rect r(cvCeil(inner.x), cvCeil(inner.y), cvFloor(inner.width), cvFloor(inner.height)); + r &= cv::Rect(0, 0, newImgSize.width, newImgSize.height); + *validPixROI = r; + } } + else + { + // Get inscribed and circumscribed rectangles in normalized + // (independent of camera matrix) coordinates + icvGetRectangles( cameraMatrix, distCoeffs, 0, 0, imgSize, inner, outer ); + + // Projection mapping inner rectangle to viewport + double fx0 = (newImgSize.width - 1) / inner.width; + double fy0 = (newImgSize.height - 1) / inner.height; + double cx0 = -fx0 * inner.x; + double cy0 = -fy0 * inner.y; + + // Projection mapping outer rectangle to viewport + double fx1 = (newImgSize.width - 1) / outer.width; + double fy1 = (newImgSize.height - 1) / outer.height; + double cx1 = -fx1 * outer.x; + double cy1 = -fy1 * outer.y; + + // Interpolate between the two optimal projections + M[0][0] = fx0*(1 - alpha) + fx1*alpha; + M[1][1] = fy0*(1 - alpha) + fy1*alpha; + M[0][2] = cx0*(1 - alpha) + cx1*alpha; + M[1][2] = cy0*(1 - alpha) + cy1*alpha; + + if( validPixROI ) + { + icvGetRectangles( cameraMatrix, distCoeffs, 0, newCameraMatrix, imgSize, inner, outer ); + cv::Rect r = inner; + r &= cv::Rect(0, 0, newImgSize.width, newImgSize.height); + *validPixROI = r; + } + } + + cvConvert(&matM, newCameraMatrix); } @@ -3374,16 +3409,28 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints, double reprojErr = cvCalibrateCamera2(&c_objPt, &c_imgPt, &c_npoints, imageSize, &c_cameraMatrix, &c_distCoeffs, &c_rvecM, &c_tvecM, flags ); - _rvecs.create((int)nimages, 1, CV_64FC3); - _tvecs.create((int)nimages, 1, CV_64FC3); + + bool rvecs_needed = _rvecs.needed(), tvecs_needed = _tvecs.needed(); + + if( rvecs_needed ) + _rvecs.create((int)nimages, 1, CV_64FC3); + if( tvecs_needed ) + _tvecs.create((int)nimages, 1, CV_64FC3); for( i = 0; i < (int)nimages; i++ ) { - _rvecs.create(3, 1, CV_64F, i, true); - _tvecs.create(3, 1, CV_64F, i, true); - Mat rv = _rvecs.getMat(i), tv = _tvecs.getMat(i); - memcpy(rv.data, rvecM.ptr(i), 3*sizeof(double)); - memcpy(tv.data, tvecM.ptr(i), 3*sizeof(double)); + if( rvecs_needed ) + { + _rvecs.create(3, 1, CV_64F, i, true); + Mat rv = _rvecs.getMat(i); + memcpy(rv.data, rvecM.ptr(i), 3*sizeof(double)); + } + if( tvecs_needed ) + { + _tvecs.create(3, 1, CV_64F, i, true); + Mat tv = _tvecs.getMat(i); + memcpy(tv.data, tvecM.ptr(i), 3*sizeof(double)); + } } cameraMatrix.copyTo(_cameraMatrix); distCoeffs.copyTo(_distCoeffs); @@ -3520,7 +3567,7 @@ bool cv::stereoRectifyUncalibrated( InputArray _points1, InputArray _points2, cv::Mat cv::getOptimalNewCameraMatrix( InputArray _cameraMatrix, InputArray _distCoeffs, Size imgSize, double alpha, Size newImgSize, - Rect* validPixROI ) + Rect* validPixROI, bool centerPrincipalPoint ) { Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat(); CvMat c_cameraMatrix = cameraMatrix, c_distCoeffs = distCoeffs; @@ -3530,7 +3577,7 @@ cv::Mat cv::getOptimalNewCameraMatrix( InputArray _cameraMatrix, cvGetOptimalNewCameraMatrix(&c_cameraMatrix, &c_distCoeffs, imgSize, alpha, &c_newCameraMatrix, - newImgSize, (CvRect*)validPixROI); + newImgSize, (CvRect*)validPixROI, (int)centerPrincipalPoint); return newCameraMatrix; } diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp index 3982bf1a5d..be283ca091 100644 --- a/modules/calib3d/src/circlesgrid.cpp +++ b/modules/calib3d/src/circlesgrid.cpp @@ -52,11 +52,12 @@ using namespace std; void CirclesGridClusterFinder::hierarchicalClustering(const vector points, const Size &patternSize, vector &patternPoints) { - Mat dists(points.size(), points.size(), CV_32FC1, Scalar(0)); + int i, j, n = (int)points.size(); + Mat dists(n, n, CV_32FC1, Scalar(0)); Mat distsMask(dists.size(), CV_8UC1, Scalar(0)); - for(size_t i=0; i(i, j) = (float)norm(points[i] - points[j]); distsMask.at(i, j) = 255; @@ -184,10 +185,11 @@ void CirclesGridClusterFinder::findOutsideCorners(const std::vector double min1 = std::numeric_limits::max(); double min2 = std::numeric_limits::max(); Point minLoc1, minLoc2; + int i, j, n = (int)corners.size(); - for(size_t i=0; i } } std::set outsideCornersIndices; - for(size_t i=0; i (it1->first, it1->first) = 0; + distanceMatrix.at ((int)it1->first, (int)it1->first) = 0; for (Neighbors::const_iterator it2 = it1->second.neighbors.begin(); it2 != it1->second.neighbors.end(); it2++) { assert( it1->first != *it2 ); - distanceMatrix.at (it1->first, *it2) = edgeWeight; + distanceMatrix.at ((int)it1->first, (int)*it2) = edgeWeight; } } @@ -436,17 +438,17 @@ void Graph::floydWarshall(cv::Mat &distanceMatrix, int infinity) const { for (Vertices::const_iterator it3 = vertices.begin(); it3 != vertices.end(); it3++) { - int val1 = distanceMatrix.at (it2->first, it3->first); + int i1 = (int)it1->first, i2 = (int)it2->first, i3 = (int)it3->first; + int val1 = distanceMatrix.at (i2, i3); int val2; - if (distanceMatrix.at (it2->first, it1->first) == infinity || distanceMatrix.at (it1->first, - it3->first) - == infinity) + if (distanceMatrix.at (i2, i1) == infinity || + distanceMatrix.at (i1, i3) == infinity) val2 = val1; else { - val2 = distanceMatrix.at (it2->first, it1->first) + distanceMatrix.at (it1->first, it3->first); + val2 = distanceMatrix.at (i2, i1) + distanceMatrix.at (i1, i3); } - distanceMatrix.at (it2->first, it3->first) = (val1 == infinity) ? val2 : std::min(val1, val2); + distanceMatrix.at (i2, i3) = (val1 == infinity) ? val2 : std::min(val1, val2); } } } @@ -748,7 +750,13 @@ Mat CirclesGridFinder::rectifyGrid(Size detectedGridSize, const vector& const Point2f offset(150, 150); vector dstPoints; - for (int i = 0; i < detectedGridSize.height; i++) + bool isClockwiseBefore = + getDirection(centers[0], centers[detectedGridSize.width - 1], centers[centers.size() - 1]) < 0; + + int iStart = isClockwiseBefore ? 0 : detectedGridSize.height - 1; + int iEnd = isClockwiseBefore ? detectedGridSize.height : -1; + int iStep = isClockwiseBefore ? 1 : -1; + for (int i = iStart; i != iEnd; i += iStep) { for (int j = 0; j < detectedGridSize.width; j++) { @@ -1039,7 +1047,7 @@ void CirclesGridFinder::findBasis(const vector &samples, vector > clusters(2), hulls(2); - for (size_t k = 0; k < samples.size(); k++) + for (int k = 0; k < (int)samples.size(); k++) { int label = bestLabels.at (k, 0); int idx = -1; @@ -1150,13 +1158,13 @@ void computePredecessorMatrix(const Mat &dm, int verticesCount, Mat &predecessor void computeShortestPath(Mat &predecessorMatrix, size_t v1, size_t v2, vector &path) { - if (predecessorMatrix.at (v1, v2) < 0) + if (predecessorMatrix.at ((int)v1, (int)v2) < 0) { path.push_back(v1); return; } - computeShortestPath(predecessorMatrix, v1, predecessorMatrix.at (v1, v2), path); + computeShortestPath(predecessorMatrix, v1, predecessorMatrix.at ((int)v1, (int)v2), path); path.push_back(v2); } @@ -1173,7 +1181,7 @@ size_t CirclesGridFinder::findLongestPath(vector &basisGraphs, Path &best Mat distanceMatrix; g.floydWarshall(distanceMatrix, infinity); Mat predecessorMatrix; - computePredecessorMatrix(distanceMatrix, g.getVerticesCount(), predecessorMatrix); + computePredecessorMatrix(distanceMatrix, (int)g.getVerticesCount(), predecessorMatrix); double maxVal; Point maxLoc; @@ -1197,9 +1205,9 @@ size_t CirclesGridFinder::findLongestPath(vector &basisGraphs, Path &best longestPaths.push_back(path); int conf = 0; - for (size_t v2 = 0; v2 < path.vertices.size(); v2++) + for (int v2 = 0; v2 < (int)path.vertices.size(); v2++) { - conf += basisGraphs[1 - (int)graphIdx].getDegree(v2); + conf += (int)basisGraphs[1 - (int)graphIdx].getDegree(v2); } confidences.push_back(conf); } @@ -1209,7 +1217,7 @@ size_t CirclesGridFinder::findLongestPath(vector &basisGraphs, Path &best int maxConf = -1; int bestPathIdx = -1; - for (size_t i = 0; i < confidences.size(); i++) + for (int i = 0; i < (int)confidences.size(); i++) { if (confidences[i] > maxConf) { @@ -1235,7 +1243,7 @@ void CirclesGridFinder::drawBasis(const vector &basis, Point2f origin, for (size_t i = 0; i < basis.size(); i++) { Point2f pt(basis[i]); - line(drawImg, origin, origin + pt, Scalar(0, i * 255, 0), 2); + line(drawImg, origin, origin + pt, Scalar(0, (double)(i * 255), 0), 2); } } @@ -1312,7 +1320,7 @@ Size CirclesGridFinder::getDetectedGridSize() const if (holes.size() == 0) return Size(0, 0); - return Size(holes[0].size(), holes.size()); + return Size((int)holes[0].size(), (int)holes.size()); } void CirclesGridFinder::getHoles(vector &outHoles) const @@ -1405,8 +1413,8 @@ void CirclesGridFinder::getCornerSegments(const vector > &points, cornerIndices.clear(); firstSteps.clear(); secondSteps.clear(); - size_t h = points.size(); - size_t w = points[0].size(); + int h = (int)points.size(); + int w = (int)points[0].size(); CV_Assert(h >= 2 && w >= 2) ; @@ -1453,6 +1461,10 @@ void CirclesGridFinder::getCornerSegments(const vector > &points, cout << "Corners are counterclockwise" << endl; #endif std::reverse(segments.begin(), segments.end()); + std::reverse(cornerIndices.begin(), cornerIndices.end()); + std::reverse(firstSteps.begin(), firstSteps.end()); + std::reverse(secondSteps.begin(), secondSteps.end()); + std::swap(firstSteps, secondSteps); } } @@ -1514,3 +1526,10 @@ size_t CirclesGridFinder::getFirstCorner(vector &largeCornerIndices, vect return cornerIdx; } + +bool cv::findCirclesGridDefault( InputArray image, Size patternSize, + OutputArray centers, int flags ) +{ + return findCirclesGrid(image, patternSize, centers, flags); +} + diff --git a/modules/calib3d/src/fundam.cpp b/modules/calib3d/src/fundam.cpp index b289db6046..63f0219498 100644 --- a/modules/calib3d/src/fundam.cpp +++ b/modules/calib3d/src/fundam.cpp @@ -84,9 +84,9 @@ int CvHomographyEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* H const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr; const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr; - double LtL[9][9], W[9][9], V[9][9]; + double LtL[9][9], W[9][1], V[9][9]; CvMat _LtL = cvMat( 9, 9, CV_64F, LtL ); - CvMat matW = cvMat( 9, 9, CV_64F, W ); + CvMat matW = cvMat( 9, 1, CV_64F, W ); CvMat matV = cvMat( 9, 9, CV_64F, V ); CvMat _H0 = cvMat( 3, 3, CV_64F, V[8] ); CvMat _Htemp = cvMat( 3, 3, CV_64F, V[7] ); @@ -499,15 +499,15 @@ int CvFMEstimator::run8Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatri a[j*9+k] += r[j]*r[k]; } - cvSVD( &A, &W, 0, &V, CV_SVD_MODIFY_A + CV_SVD_V_T ); + cvEigenVV(&A, &V, &W); - for( i = 0; i < 8; i++ ) + for( i = 0; i < 9; i++ ) { if( fabs(w[i]) < DBL_EPSILON ) break; } - if( i < 7 ) + if( i < 8 ) return 0; F0 = cvMat( 3, 3, CV_64F, v + 9*8 ); // take the last column of v as a solution of Af = 0 @@ -616,7 +616,7 @@ CV_IMPL int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, (mask->rows == 1 || mask->cols == 1) && mask->rows*mask->cols == count ); } - if( mask || count > 8 ) + if( mask || count >= 8 ) tempMask = cvCreateMat( 1, count, CV_8U ); if( !tempMask.empty() ) cvSet( tempMask, cvScalarAll(1.) ); @@ -624,9 +624,9 @@ CV_IMPL int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, CvFMEstimator estimator(7); if( count == 7 ) result = estimator.run7Point(m1, m2, &_F9x3); - else if( count == 8 || method == CV_FM_8POINT ) + else if( method == CV_FM_8POINT ) result = estimator.run8Point(m1, m2, &_F3x3); - else if( count >= 8 ) + else { if( param1 <= 0 ) param1 = 3; diff --git a/modules/calib3d/src/solvepnp.cpp b/modules/calib3d/src/solvepnp.cpp index 0f43bc6fc4..5ceee9208f 100644 --- a/modules/calib3d/src/solvepnp.cpp +++ b/modules/calib3d/src/solvepnp.cpp @@ -132,7 +132,7 @@ namespace cv const Mat& rvecInit, const Mat& tvecInit, Mutex& resultsMutex) { Mat modelObjectPoints(1, MIN_POINTS_COUNT, CV_32FC3), modelImagePoints(1, MIN_POINTS_COUNT, CV_32FC2); - for (size_t i = 0, colIndex = 0; i < pointsMask.size(); i++) + for (int i = 0, colIndex = 0; i < (int)pointsMask.size(); i++) { if (pointsMask[i]) { @@ -239,8 +239,8 @@ namespace cv void generateVar(vector& mask) const { - size_t size = mask.size(); - for (size_t i = 0; i < size; i++) + int size = (int)mask.size(); + for (int i = 0; i < size; i++) { int i1 = generator.uniform(0, size); int i2 = generator.uniform(0, size); @@ -302,12 +302,11 @@ void cv::solvePnPRansac(InputArray _opoints, InputArray _ipoints, if (localInliers.size() >= (size_t)pnpransac::MIN_POINTS_COUNT) { - size_t pointsCount = localInliers.size(); + int i, pointsCount = (int)localInliers.size(); Mat inlierObjectPoints(1, pointsCount, CV_32FC3), inlierImagePoints(1, pointsCount, CV_32FC2); - int index; - for (size_t i = 0; i < localInliers.size(); i++) + for (i = 0; i < pointsCount; i++) { - index = localInliers[i]; + int index = localInliers[i]; Mat colInlierImagePoints = inlierImagePoints(Rect(i, 0, 1, 1)); imagePoints.col(index).copyTo(colInlierImagePoints); Mat colInlierObjectPoints = inlierObjectPoints(Rect(i, 0, 1, 1)); diff --git a/modules/calib3d/src/stereobm.cpp b/modules/calib3d/src/stereobm.cpp index 8215ef6cb6..354e4fc07c 100644 --- a/modules/calib3d/src/stereobm.cpp +++ b/modules/calib3d/src/stereobm.cpp @@ -718,7 +718,7 @@ struct FindStereoCorrespInvoker uchar *ptr = state->slidingSumBuf->data.ptr + range.begin() * stripeBufSize; int FILTERED = (state->minDisparity - 1)*16; - Rect roi = validDisparityRect & Rect(0, _row0, cols, _row1); + Rect roi = validDisparityRect & Rect(0, _row0, cols, _row1 - _row0); if( roi.height == 0 ) return; int row0 = roi.y; @@ -871,7 +871,6 @@ static void findStereoCorrespondenceBM( const Mat& left0, const Mat& right0, Mat double N0 = 8000000 / (useShorts ? 1 : 4); // approx tbb's min number instructions reasonable for one thread double maxStripeSize = min(max(N0 / (width * ndisp), (wsz-1) * SAD_overhead_coeff), (double)height); int nstripes = cvCeil(height / maxStripeSize); - printf("nstripes=%d\n", nstripes); #else const int nstripes = 1; #endif diff --git a/modules/calib3d/test/test_fundam.cpp b/modules/calib3d/test/test_fundam.cpp index 4315ee040b..0ee21f72b1 100644 --- a/modules/calib3d/test/test_fundam.cpp +++ b/modules/calib3d/test/test_fundam.cpp @@ -372,7 +372,7 @@ static void test_convertHomogeneous( const Mat& _src, Mat& _dst ) { count = src.rows; sdims = src.channels()*src.cols; - sstep1 = src.step/sizeof(double); + sstep1 = (int)(src.step/sizeof(double)); sstep2 = 1; } else @@ -387,7 +387,7 @@ static void test_convertHomogeneous( const Mat& _src, Mat& _dst ) else { sstep1 = 1; - sstep2 = src.step/sizeof(double); + sstep2 = (int)(src.step/sizeof(double)); } } @@ -395,7 +395,7 @@ static void test_convertHomogeneous( const Mat& _src, Mat& _dst ) { CV_Assert( count == dst.rows ); ddims = dst.channels()*dst.cols; - dstep1 = dst.step/sizeof(double); + dstep1 = (int)(dst.step/sizeof(double)); dstep2 = 1; } else @@ -410,7 +410,7 @@ static void test_convertHomogeneous( const Mat& _src, Mat& _dst ) else { dstep1 = 1; - dstep2 = dst.step/sizeof(double); + dstep2 = (int)(dst.step/sizeof(double)); } } diff --git a/modules/contrib/include/opencv2/contrib/contrib.hpp b/modules/contrib/include/opencv2/contrib/contrib.hpp index 45acfa78e0..ca5c3bc76c 100644 --- a/modules/contrib/include/opencv2/contrib/contrib.hpp +++ b/modules/contrib/include/opencv2/contrib/contrib.hpp @@ -568,7 +568,7 @@ namespace cv { public: // Flags - enum {USE_INITIAL_DISPARITY = 1, USE_EQUALIZE_HIST = 2, USE_SMART_ID = 4, USE_MEDIAN_FILTERING = 8}; + enum {USE_INITIAL_DISPARITY = 1, USE_EQUALIZE_HIST = 2, USE_SMART_ID = 4, USE_AUTO_PARAMS = 8, USE_MEDIAN_FILTERING = 16}; enum {CYCLE_O, CYCLE_V}; enum {PENALIZATION_TICHONOV, PENALIZATION_CHARBONNIER, PENALIZATION_PERONA_MALIK}; @@ -598,7 +598,8 @@ namespace cv CV_PROP_RW int flags; private: - void FMG(Mat &I1, Mat &I2, Mat &I2x, Mat &u, int level); + void autoParams(); + void FMG(Mat &I1, Mat &I2, Mat &I2x, Mat &u, int level); void VCycle_MyFAS(Mat &I1_h, Mat &I2_h, Mat &I2x_h, Mat &u_h, int level); void VariationalSolver(Mat &I1_h, Mat &I2_h, Mat &I2x_h, Mat &u_h, int level); }; @@ -606,6 +607,7 @@ namespace cv CV_EXPORTS void polyfit(const Mat& srcx, const Mat& srcy, Mat& dst, int order); } +#include "opencv2/contrib/retina.hpp" #endif diff --git a/modules/contrib/include/opencv2/contrib/retina.hpp b/modules/contrib/include/opencv2/contrib/retina.hpp new file mode 100644 index 0000000000..06a3ff8045 --- /dev/null +++ b/modules/contrib/include/opencv2/contrib/retina.hpp @@ -0,0 +1,222 @@ +/*#****************************************************************************** + ** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + ** + ** By downloading, copying, installing or using the software you agree to this license. + ** If you do not agree to this license, do not download, install, + ** copy or use the software. + ** + ** + ** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. + ** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. + ** + ** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) + ** + ** Creation - enhancement process 2007-2011 + ** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France + ** + ** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). + ** Refer to the following research paper for more information: + ** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + ** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: + ** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + ** + ** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : + ** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: + ** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 + ** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. + ** ====> more informations in the above cited Jeanny Heraults's book. + ** + ** License Agreement + ** For Open Source Computer Vision Library + ** + ** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + ** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. + ** + ** For Human Visual System tools (hvstools) + ** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. + ** + ** Third party copyrights are property of their respective owners. + ** + ** Redistribution and use in source and binary forms, with or without modification, + ** are permitted provided that the following conditions are met: + ** + ** * Redistributions of source code must retain the above copyright notice, + ** this list of conditions and the following disclaimer. + ** + ** * Redistributions in binary form must reproduce the above copyright notice, + ** this list of conditions and the following disclaimer in the documentation + ** and/or other materials provided with the distribution. + ** + ** * The name of the copyright holders may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** This software is provided by the copyright holders and contributors "as is" and + ** any express or implied warranties, including, but not limited to, the implied + ** warranties of merchantability and fitness for a particular purpose are disclaimed. + ** In no event shall the Intel Corporation or contributors be liable for any direct, + ** indirect, incidental, special, exemplary, or consequential damages + ** (including, but not limited to, procurement of substitute goods or services; + ** loss of use, data, or profits; or business interruption) however caused + ** and on any theory of liability, whether in contract, strict liability, + ** or tort (including negligence or otherwise) arising in any way out of + ** the use of this software, even if advised of the possibility of such damage. + *******************************************************************************/ + +#ifndef __OPENCV_CONTRIB_RETINA_HPP__ +#define __OPENCV_CONTRIB_RETINA_HPP__ + +/* + * Retina.hpp + * + * Created on: Jul 19, 2011 + * Author: Alexandre Benoit + */ + +#include "opencv2/core/core.hpp" // for all OpenCV core functionalities access, including cv::Exception support +#include + +namespace cv +{ + + enum RETINA_COLORSAMPLINGMETHOD + { + RETINA_COLOR_RANDOM, /// each pixel position is either R, G or B in a random choice + RETINA_COLOR_DIAGONAL,/// color sampling is RGBRGBRGB..., line 2 BRGBRGBRG..., line 3, GBRGBRGBR... + RETINA_COLOR_BAYER/// standard bayer sampling + }; + + class RetinaFilter; + + /** + * @brief a wrapper class which allows the use of the Gipsa/Listic Labs retina model + * @class Retina object is a wrapper class which allows the Gipsa/Listic Labs model to be used. + * This retina model allows spatio-temporal image processing (applied on still images, video sequences). + * As a summary, these are the retina model properties: + * => It applies a spectral whithening (mid-frequency details enhancement) + * => high frequency spatio-temporal noise reduction + * => low frequency luminance to be reduced (luminance range compression) + * => local logarithmic luminance compression allows details to be enhanced in low light conditions + * + * for more information, reer to the following papers : + * Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + * Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + */ + class CV_EXPORTS Retina { + + public: + + /** + * Main constructor with most commun use setup : create an instance of color ready retina model + * @param inputSize : the input frame size + */ + Retina(const std::string parametersSaveFile, Size inputSize); + + /** + * Complete Retina filter constructor which allows all basic structural parameters definition + * @param inputSize : the input frame size + * @param colorMode : the chosen processing mode : with or without color processing + * @param samplingMethod: specifies which kind of color sampling will be used + * @param useRetinaLogSampling: activate retina log sampling, if true, the 2 following parameters can be used + * @param reductionFactor: only usefull if param useRetinaLogSampling=true, specifies the reduction factor of the output frame (as the center (fovea) is high resolution and corners can be underscaled, then a reduction of the output is allowed without precision leak + * @param samplingStrenght: only usefull if param useRetinaLogSampling=true, specifies the strenght of the log scale that is applied + */ + Retina(const std::string parametersSaveFile, Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); + + virtual ~Retina(); + + /** + * try to open an XML retina parameters file to adjust current retina instance setup + * => if the xml file does not exist, then default setup is applied + * => warning, Exceptions are thrown if read XML file is not valid + * @param retinaParameterFile : the parameters filename + */ + void setup(std::string retinaParameterFile="", const bool applyDefaultSetupOnFailure=true); + + /** + * parameters setup display method + * @return a string which contains formatted parameters information + */ + const std::string printSetup(); + + /** + * setup the OPL and IPL parvo channels (see biologocal model) + * OPL is referred as Outer Plexiform Layer of the retina, it allows the spatio-temporal filtering which withens the spectrum and reduces spatio-temporal noise while attenuating global luminance (low frequency energy) + * IPL parvo is the OPL next processing stage, it refers to Inner Plexiform layer of the retina, it allows high contours sensitivity in foveal vision. + * for more informations, please have a look at the paper Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + * @param colorMode : specifies if (true) color is processed of not (false) to then processing gray level image + * @param normaliseOutput : specifies if (true) output is rescaled between 0 and 255 of not (false) + * @param photoreceptorsLocalAdaptationSensitivity: the photoreceptors sensitivity renage is 0-1 (more log compression effect when value increases) + * @param photoreceptorsTemporalConstant: the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame + * @param photoreceptorsSpatialConstant: the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel + * @param horizontalCellsGain: gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 + * @param HcellsTemporalConstant: the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors + * @param HcellsSpatialConstant: the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) + * @param ganglionCellsSensitivity: the compression strengh of the ganglion cells local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 230 + */ + void setupOPLandIPLParvoChannel(const bool colorMode=true, const bool normaliseOutput = true, const double photoreceptorsLocalAdaptationSensitivity=0.7, const double photoreceptorsTemporalConstant=0.5, const double photoreceptorsSpatialConstant=0.53, const double horizontalCellsGain=0, const double HcellsTemporalConstant=1, const double HcellsSpatialConstant=7, const double ganglionCellsSensitivity=0.7); + + /** + * set parameters values for the Inner Plexiform Layer (IPL) magnocellular channel + * this channel processes signals outpint from OPL processing stage in peripheral vision, it allows motion information enhancement. It is decorrelated from the details channel. See reference paper for more details. + * @param normaliseOutput : specifies if (true) output is rescaled between 0 and 255 of not (false) + * @param parasolCells_beta: the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 + * @param parasolCells_tau: the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) + * @param parasolCells_k: the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 + * @param amacrinCellsTemporalCutFrequency: the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, tipicall value is 5 + * @param V0CompressionParameter: the compression strengh of the ganglion cells local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 200 + * @param localAdaptintegration_tau: specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + * @param localAdaptintegration_k: specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + */ + void setupIPLMagnoChannel(const bool normaliseOutput = true, const double parasolCells_beta=0, const double parasolCells_tau=0, const double parasolCells_k=7, const double amacrinCellsTemporalCutFrequency=1.2, const double V0CompressionParameter=0.95, const double localAdaptintegration_tau=0, const double localAdaptintegration_k=7); + /** + * method which allows retina to be applied on an input image + * @param + * /// encapsulated retina module is ready to deliver its outputs using dedicated acccessors, see getParvo and getMagno methods + * + */ + void run(const Mat &inputImage); + /** + * accessor of the details channel of the retina (models foveal vision) + * @param retinaOutput_parvo : the output buffer (reallocated if necessary) + */ + void getParvo(Mat &retinaOutput_parvo); + + /** + * accessor of the motion channel of the retina (models peripheral vision) + * @param retinaOutput_magno : the output buffer (reallocated if necessary) + */ + void getMagno(Mat &retinaOutput_magno); + + void clearBuffers(); + + protected: + //// Parameteres setup members + // parameters file ... saved on instance delete + FileStorage _parametersSaveFile; + std::string _parametersSaveFileName; + //// Retina model related modules + // buffer that ensure library cross-compatibility + std::valarray _inputBuffer; + + // pointer to retina model + RetinaFilter* _retinaFilter; + + /** + * exports a valarray buffer outing from HVStools objects to a cv::Mat in CV_8UC1 (gray level picture) or CV_8UC3 (color) format + * @param grayMatrixToConvert the valarray to export to OpenCV + * @param nbRows : the number of rows of the valarray flatten matrix + * @param nbColumns : the number of rows of the valarray flatten matrix + * @param colorMode : a flag which mentions if matrix is color (true) or graylevel (false) + * @param outBuffer : the output matrix which is reallocated to satisfy Retina output buffer dimensions + */ + void _convertValarrayGrayBuffer2cvMat(const std::valarray &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, Mat &outBuffer); + + // private method called by constructirs + void _init(const std::string parametersSaveFile, Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); + + + }; + +} +#endif /* __OPENCV_CONTRIB_RETINA_HPP__ */ + diff --git a/modules/contrib/src/ba.cpp b/modules/contrib/src/ba.cpp index 0f4cf568de..636ba59c26 100644 --- a/modules/contrib/src/ba.cpp +++ b/modules/contrib/src/ba.cpp @@ -995,8 +995,8 @@ void LevMarqSparse::bundleAdjust( vector& points, //positions of points const TermCriteria& criteria, BundleAdjustCallback cb, void* user_data) { //,enum{MOTION_AND_STRUCTURE,MOTION,STRUCTURE}) - int num_points = points.size(); - int num_cameras = cameraMatrix.size(); + int num_points = (int)points.size(); + int num_cameras = (int)cameraMatrix.size(); CV_Assert( imagePoints.size() == (size_t)num_cameras && visibility.size() == (size_t)num_cameras && diff --git a/modules/contrib/src/basicretinafilter.cpp b/modules/contrib/src/basicretinafilter.cpp new file mode 100644 index 0000000000..f836bcae30 --- /dev/null +++ b/modules/contrib/src/basicretinafilter.cpp @@ -0,0 +1,867 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#include "precomp.hpp" + +#include +#include +#include "basicretinafilter.hpp" +#include + + +namespace cv +{ + +// @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ + +////////////////////////////////////////////////////////// +// BASIC RETINA FILTER +////////////////////////////////////////////////////////// + +// Constructor and Desctructor of the basic retina filter +BasicRetinaFilter::BasicRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns, const unsigned int parametersListSize, const bool useProgressiveFilter) +:_filterOutput(NBrows, NBcolumns), + _localBuffer(NBrows*NBcolumns), + _filteringCoeficientsTable(3*parametersListSize), + _progressiveSpatialConstant(0),// pointer to a local table containing local spatial constant (allocated with the object) + _progressiveGain(0) +{ +#ifdef T_BASIC_RETINA_ELEMENT_DEBUG + std::cout<<"BasicRetinaFilter::BasicRetinaFilter: new filter, size="<0) + { + _progressiveSpatialConstant.resize(_filterOutput.size()); + _progressiveGain.resize(_filterOutput.size()); + } + // reset buffers + clearAllBuffers(); +} + +// Change coefficients table +void BasicRetinaFilter::setLPfilterParameters(const double beta, const double tau, const double desired_k, const unsigned int filterIndex) +{ + double _beta = beta+tau; + double k=desired_k; + // check if the spatial constant is correct (avoid 0 value to avoid division by 0) + if (desired_k<=0) + { + k=0.001; + std::cerr<<"BasicRetinaFilter::spatial constant of the low pass filter must be superior to zero !!! correcting parameter setting to 0,001"< old:"<<(1-_a)*(1-_a)*(1-_a)*(1-_a)/(1+_beta)<1) + localSpatialConstantValue=1; + + _progressiveSpatialConstant[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localSpatialConstantValue; + _progressiveSpatialConstant[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localSpatialConstantValue; + _progressiveSpatialConstant[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localSpatialConstantValue; + _progressiveSpatialConstant[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localSpatialConstantValue; + + // computing local gain + double localGain=(1-localSpatialConstantValue)*(1-localSpatialConstantValue)*(1-localSpatialConstantValue)*(1-localSpatialConstantValue)/(1+_beta); + _progressiveGain[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localGain; + _progressiveGain[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localGain; + _progressiveGain[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localGain; + _progressiveGain[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localGain; + + //std::cout< &accuracyMap, const unsigned int filterIndex) +{ + + if (accuracyMap.size()!=_filterOutput.size()) + { + std::cerr<<"BasicRetinaFilter::setProgressiveFilterConstants_CustomAccuracy: error: input accuracy map does not match filter size, init skept"<1) + localSpatialConstantValue=1; + + _progressiveSpatialConstant[index]=localSpatialConstantValue; + + // computing local gain + double localGain=(1-localSpatialConstantValue)*(1-localSpatialConstantValue)*(1-localSpatialConstantValue)*(1-localSpatialConstantValue)/(1+_beta); + _progressiveGain[index]=localGain; + + //std::cout< &BasicRetinaFilter::runFilter_LocalAdapdation(const std::valarray &inputFrame, const std::valarray &localLuminance) +{ + _localLuminanceAdaptation(get_data(inputFrame), get_data(localLuminance), &_filterOutput[0]); + return _filterOutput; +} +// run local adaptation filter at a specific output adress +void BasicRetinaFilter::runFilter_LocalAdapdation(const std::valarray &inputFrame, const std::valarray &localLuminance, std::valarray &outputFrame) +{ + _localLuminanceAdaptation(get_data(inputFrame), get_data(localLuminance), &outputFrame[0]); +} +// run local adaptation filter and save result in _filterOutput with autonomous low pass filtering before adaptation +const std::valarray &BasicRetinaFilter::runFilter_LocalAdapdation_autonomous(const std::valarray &inputFrame) +{ + _spatiotemporalLPfilter(get_data(inputFrame), &_filterOutput[0]); + _localLuminanceAdaptation(get_data(inputFrame), &_filterOutput[0], &_filterOutput[0]); + return _filterOutput; +} +// run local adaptation filter at a specific output adress with autonomous low pass filtering before adaptation +void BasicRetinaFilter::runFilter_LocalAdapdation_autonomous(const std::valarray &inputFrame, std::valarray &outputFrame) +{ + _spatiotemporalLPfilter(get_data(inputFrame), &_filterOutput[0]); + _localLuminanceAdaptation(get_data(inputFrame), &_filterOutput[0], &outputFrame[0]); +} +// local luminance adaptation of the input in regard of localLuminance buffer +void BasicRetinaFilter::_localLuminanceAdaptation(const double *inputFrame, const double *localLuminance, double *outputFrame) +{ + double meanLuminance=0; + const double *luminancePTR=inputFrame; + for (unsigned int i=0;i<_filterOutput.getNBpixels();++i) + meanLuminance+=*(luminancePTR++); + meanLuminance/=_filterOutput.getNBpixels(); + //double tempMeanValue=meanLuminance+_meanInputValue*_tau; + + updateCompressionParameter(meanLuminance); + //std::cout< &BasicRetinaFilter::runFilter_LPfilter(const std::valarray &inputFrame, const unsigned int filterIndex) +{ + _spatiotemporalLPfilter(get_data(inputFrame), &_filterOutput[0], filterIndex); + return _filterOutput; +} + +// run LP filter for a new frame input and save result at a specific output adress +void BasicRetinaFilter::runFilter_LPfilter(const std::valarray &inputFrame, std::valarray &outputFrame, const unsigned int filterIndex) +{ + _spatiotemporalLPfilter(get_data(inputFrame), &outputFrame[0], filterIndex); +} + +// run LP filter on the input data and rewrite it +void BasicRetinaFilter::runFilter_LPfilter_Autonomous(std::valarray &inputOutputFrame, const unsigned int filterIndex) +{ + unsigned int coefTableOffset=filterIndex*3; + + /**********/ + _a=_filteringCoeficientsTable[coefTableOffset]; + _gain=_filteringCoeficientsTable[1+coefTableOffset]; + _tau=_filteringCoeficientsTable[2+coefTableOffset]; + + // launch the serie of 1D directional filters in order to compute the 2D low pass filter + _horizontalCausalFilter(&inputOutputFrame[0], 0, _filterOutput.getNBrows()); + _horizontalAnticausalFilter(&inputOutputFrame[0], 0, _filterOutput.getNBrows()); + _verticalCausalFilter(&inputOutputFrame[0], 0, _filterOutput.getNBcolumns()); + _verticalAnticausalFilter_multGain(&inputOutputFrame[0], 0, _filterOutput.getNBcolumns()); + +} +// run LP filter for a new frame input and save result at a specific output adress +void BasicRetinaFilter::_spatiotemporalLPfilter(const double *inputFrame, double *outputFrame, const unsigned int filterIndex) +{ + unsigned int coefTableOffset=filterIndex*3; + /**********/ + _a=_filteringCoeficientsTable[coefTableOffset]; + _gain=_filteringCoeficientsTable[1+coefTableOffset]; + _tau=_filteringCoeficientsTable[2+coefTableOffset]; + + // launch the serie of 1D directional filters in order to compute the 2D low pass filter + _horizontalCausalFilter_addInput(inputFrame, outputFrame, 0,_filterOutput.getNBrows()); + _horizontalAnticausalFilter(outputFrame, 0, _filterOutput.getNBrows()); + _verticalCausalFilter(outputFrame, 0, _filterOutput.getNBcolumns()); + _verticalAnticausalFilter_multGain(outputFrame, 0, _filterOutput.getNBcolumns()); + +} + +// run SQUARING LP filter for a new frame input and save result at a specific output adress +const double BasicRetinaFilter::_squaringSpatiotemporalLPfilter(const double *inputFrame, double *outputFrame, const unsigned int filterIndex) +{ + unsigned int coefTableOffset=filterIndex*3; + /**********/ + _a=_filteringCoeficientsTable[coefTableOffset]; + _gain=_filteringCoeficientsTable[1+coefTableOffset]; + _tau=_filteringCoeficientsTable[2+coefTableOffset]; + + // launch the serie of 1D directional filters in order to compute the 2D low pass filter + + _squaringHorizontalCausalFilter(inputFrame, outputFrame, 0, _filterOutput.getNBrows()); + _horizontalAnticausalFilter(outputFrame, 0, _filterOutput.getNBrows()); + _verticalCausalFilter(outputFrame, 0, _filterOutput.getNBcolumns()); + return _verticalAnticausalFilter_returnMeanValue(outputFrame, 0, _filterOutput.getNBcolumns()); +} + +///////////////////////////////////////////////// +// standard version of the 1D low pass filters + +// horizontal causal filter which adds the input inside +void BasicRetinaFilter::_horizontalCausalFilter(double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd) +{ + + + //#pragma omp parallel for + for (unsigned int IDrow=IDrowStart; IDrow squaring horizontal causal filter +void BasicRetinaFilter::_squaringHorizontalCausalFilter(const double *inputFrame, double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd) +{ + register double* outputPTR=outputFrame+IDrowStart*_filterOutput.getNBcolumns(); + register const double* inputPTR=inputFrame+IDrowStart*_filterOutput.getNBcolumns(); + for (unsigned int IDrow=IDrowStart; IDrow USE IRREGULAR SPATIAL CONSTANT + +// irregular filter computed from a buffer and rewrites it +void BasicRetinaFilter::_spatiotemporalLPfilter_Irregular(double *inputOutputFrame, const unsigned int filterIndex) +{ + if (_progressiveGain.size()==0) + { + std::cerr<<"BasicRetinaFilter::runProgressiveFilter: cannot perform filtering, no progressive filter settled up"< B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#ifndef BASICRETINAELEMENT_HPP_ +#define BASICRETINAELEMENT_HPP_ + +#include + + +/** +* @class BasicRetinaFilter +* @brief Brief overview, this class provides tools for low level image processing: +* --> this class is able to perform: +* -> first order Low pass optimized filtering +* -> local luminance adaptation (able to correct back light problems and contrast enhancement) +* -> progressive low pass filter filtering (higher filtering on the borders than on the center) +* -> image data between 0 and 255 resampling with different options, linear rescaling, sigmoide) +* +* TYPICAL USE: +* +* // create object at a specified picture size +* BasicRetinaFilter *_photoreceptorsPrefilter; +* _photoreceptorsPrefilter =new BasicRetinaFilter(sizeRows, sizeWindows); +* +* // init gain, spatial and temporal parameters: +* _photoreceptorsPrefilter->setCoefficientsTable(gain,temporalConstant, spatialConstant); +* +* // during program execution, call the filter for local luminance correction or low pass filtering for an input picture called "FrameBuffer": +* _photoreceptorsPrefilter->runFilter_LocalAdapdation(FrameBuffer); +* // or (Low pass first order filter) +* _photoreceptorsPrefilter->runFilter_LPfilter(FrameBuffer); +* // get output frame and its size: +* const unsigned int output_nbRows=_photoreceptorsPrefilter->getNBrows(); +* const unsigned int output_nbColumns=_photoreceptorsPrefilter->getNBcolumns(); +* const double *outputFrame=_photoreceptorsPrefilter->getOutput(); +* +* // at the end of the program, destroy object: +* delete _photoreceptorsPrefilter; + +* @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ +* Creation date 2007 +* synthesis of the work described in Alexandre BENOIT thesis: "Le systeme visuel humain au secours de la vision par ordinateur" +*/ + +#include +#include "templatebuffer.hpp" + +//#define __BASIC_RETINA_ELEMENT_DEBUG + +//using namespace std; +namespace cv +{ +class BasicRetinaFilter +{ + +public: + + /** + * constructor of the base bio-inspired toolbox, parameters are only linked to imae input size and number of filtering capabilities of the object + * @param NBrows: number of rows of the input image + * @param NBcolumns: number of columns of the input image + * @param parametersListSize: specifies the number of parameters set (each parameters set represents a specific low pass spatio-temporal filter) + * @param useProgressiveFilter: specifies if the filter has irreguar (progressive) filtering capabilities (this can be activated later using setProgressiveFilterConstants_xxx methods) + */ + BasicRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns, const unsigned int parametersListSize=1, const bool useProgressiveFilter=false); + + /** + * standrad destructore + */ + ~BasicRetinaFilter(); + + /** + * function which clears the output buffer of the object + */ + inline void clearOutputBuffer(){_filterOutput=0;}; + + /** + * function which clears the secondary buffer of the object + */ + inline void clearSecondaryBuffer(){_localBuffer=0;}; + + /** + * function which clears the output and the secondary buffer of the object + */ + inline void clearAllBuffers(){clearOutputBuffer();clearSecondaryBuffer();}; + + /** + * resize basic retina filter object (resize all allocated buffers + * @param NBrows: the new height size + * @param NBcolumns: the new width size + */ + void resize(const unsigned int NBrows, const unsigned int NBcolumns); + + /** + * forbiden method inherited from parent std::valarray + * prefer not to use this method since the filter matrix become vectors + */ + void resize(const unsigned int){std::cerr<<"error, not accessible method"< &runFilter_LPfilter(const std::valarray &inputFrame, const unsigned int filterIndex=0); // run the LP filter for a new frame input and save result in _filterOutput + + /** + * low pass filter call and run (models the homogeneous cells network at the retina level, for example horizontal cells or photoreceptors) + * @param inputFrame: the input image to be processed + * @param outputFrame: the output buffer in which the result is writed + * @param filterIndex: the offset which specifies the parameter set that should be used for the filtering + */ + void runFilter_LPfilter(const std::valarray &inputFrame, std::valarray &outputFrame, const unsigned int filterIndex=0); // run LP filter on a specific output adress + + /** + * low pass filter call and run (models the homogeneous cells network at the retina level, for example horizontal cells or photoreceptors) + * @param inputOutputFrame: the input image to be processed on which the result is rewrited + * @param filterIndex: the offset which specifies the parameter set that should be used for the filtering + */ + void runFilter_LPfilter_Autonomous(std::valarray &inputOutputFrame, const unsigned int filterIndex=0);// run LP filter on the input data and rewrite it + + /** + * local luminance adaptation call and run (contrast enhancement property of the photoreceptors) + * @param inputOutputFrame: the input image to be processed + * @param localLuminance: an image which represents the local luminance of the inputFrame parameter, in general, it is its low pass spatial filtering + * @return the processed image, the output is reachable later by using function getOutput() + */ + const std::valarray &runFilter_LocalAdapdation(const std::valarray &inputOutputFrame, const std::valarray &localLuminance);// run local adaptation filter and save result in _filterOutput + + /** + * local luminance adaptation call and run (contrast enhancement property of the photoreceptors) + * @param inputFrame: the input image to be processed + * @param localLuminance: an image which represents the local luminance of the inputFrame parameter, in general, it is its low pass spatial filtering + * @param outputFrame: the output buffer in which the result is writed + */ + void runFilter_LocalAdapdation(const std::valarray &inputFrame, const std::valarray &localLuminance, std::valarray &outputFrame); // run local adaptation filter on a specific output adress + + /** + * local luminance adaptation call and run (contrast enhancement property of the photoreceptors) + * @param inputFrame: the input image to be processed + * @return the processed image, the output is reachable later by using function getOutput() + */ + const std::valarray &runFilter_LocalAdapdation_autonomous(const std::valarray &inputFrame);// run local adaptation filter and save result in _filterOutput + + /** + * local luminance adaptation call and run (contrast enhancement property of the photoreceptors) + * @param inputFrame: the input image to be processed + * @param outputFrame: the output buffer in which the result is writen + */ + void runFilter_LocalAdapdation_autonomous(const std::valarray &inputFrame, std::valarray &outputFrame); // run local adaptation filter on a specific output adress + + /** + * run low pass filtering with progressive parameters (models the retina log sampling of the photoreceptors and its low pass filtering effect consequence: more powerfull low pass filtering effect on the corners) + * @param inputFrame: the input image to be processed + * @param filterIndex: the index which specifies the parameter set that should be used for the filtering + * @return the processed image, the output is reachable later by using function getOutput() if outputFrame is NULL + */ + inline void runProgressiveFilter(std::valarray &inputFrame, const unsigned int filterIndex=0){_spatiotemporalLPfilter_Irregular(&inputFrame[0], filterIndex);}; + + /** + * run low pass filtering with progressive parameters (models the retina log sampling of the photoreceptors and its low pass filtering effect consequence: more powerfull low pass filtering effect on the corners) + * @param inputFrame: the input image to be processed + * @param outputFrame: the output buffer in which the result is writen + * @param filterIndex: the index which specifies the parameter set that should be used for the filtering + */ + inline void runProgressiveFilter(const std::valarray &inputFrame, + std::valarray &outputFrame, + const unsigned int filterIndex=0) + {_spatiotemporalLPfilter_Irregular(get_data(inputFrame), &outputFrame[0], filterIndex);}; + + /** + * first order spatio-temporal low pass filter setup function + * @param beta: gain of the filter (generally set to zero) + * @param tau: time constant of the filter (unit is frame for video processing) + * @param k: spatial constant of the filter (unit is pixels) + * @param filterIndex: the index which specifies the parameter set that should be used for the filtering + */ + void setLPfilterParameters(const double beta, const double tau, const double k, const unsigned int filterIndex=0); // change the parameters of the filter + + /** + * first order spatio-temporal low pass filter setup function + * @param beta: gain of the filter (generally set to zero) + * @param tau: time constant of the filter (unit is frame for video processing) + * @param alpha0: spatial constant of the filter (unit is pixels) on the border of the image + * @param filterIndex: the index which specifies the parameter set that should be used for the filtering + */ + void setProgressiveFilterConstants_CentredAccuracy(const double beta, const double tau, const double alpha0, const unsigned int filterIndex=0); + + /** + * first order spatio-temporal low pass filter setup function + * @param beta: gain of the filter (generally set to zero) + * @param tau: time constant of the filter (unit is frame for video processing) + * @param alpha0: spatial constant of the filter (unit is pixels) on the border of the image + * @param accuracyMap an image (double format) which values range is between 0 and 1, where 0 means, apply no filtering and 1 means apply the filtering as specified in the parameters set, intermediate values allow to smooth variations of the filtering strenght + * @param filterIndex: the index which specifies the parameter set that should be used for the filtering + */ + void setProgressiveFilterConstants_CustomAccuracy(const double beta, const double tau, const double alpha0, const std::valarray &accuracyMap, const unsigned int filterIndex=0); + + /** + * local luminance adaptation setup, this function should be applied for normal local adaptation (not for tone mapping operation) + * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect + * @param maxInputValue: the maximum amplitude value measured after local adaptation processing (c.f. function runFilter_LocalAdapdation & runFilter_LocalAdapdation_autonomous) + * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI) + */ + void setV0CompressionParameter(const double v0, const double maxInputValue, const double){ _v0=v0*maxInputValue; _localLuminanceFactor=v0; _localLuminanceAddon=maxInputValue*(1.0-v0); _maxInputValue=maxInputValue;}; + + /** + * update local luminance adaptation setup, initial maxInputValue is kept. This function should be applied for normal local adaptation (not for tone mapping operation) + * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect + * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI) + */ + void setV0CompressionParameter(const double v0, const double meanLuminance){ this->setV0CompressionParameter(v0, _maxInputValue, meanLuminance);}; + + /** + * local luminance adaptation setup, this function should be applied for normal local adaptation (not for tone mapping operation) + * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect + */ + void setV0CompressionParameter(const double v0){ _v0=v0*_maxInputValue; _localLuminanceFactor=v0; _localLuminanceAddon=_maxInputValue*(1.0-v0);}; + + /** + * local luminance adaptation setup, this function should be applied for local adaptation applied to tone mapping operation + * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect + * @param maxInputValue: the maximum amplitude value measured after local adaptation processing (c.f. function runFilter_LocalAdapdation & runFilter_LocalAdapdation_autonomous) + * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI) + */ + void setV0CompressionParameterToneMapping(const double v0, const double maxInputValue, const double meanLuminance=128.0){ _v0=v0*maxInputValue; _localLuminanceFactor=1; _localLuminanceAddon=meanLuminance*_v0; _maxInputValue=maxInputValue;}; + + /** + * update compression parameters while keeping v0 parameter value + * @param meanLuminance the input frame mean luminance + */ + inline void updateCompressionParameter(const double meanLuminance){_localLuminanceFactor=1; _localLuminanceAddon=meanLuminance*_v0;}; + + /** + * @return the v0 compression parameter used to compute the local adaptation + */ + const double getV0CompressionParameter(){ return _v0/_maxInputValue;}; + + /** + * @return the output result of the object + */ + inline const std::valarray &getOutput() const {return _filterOutput;}; + + /** + * @return number of rows of the filter + */ + inline const unsigned int getNBrows(){return _filterOutput.getNBrows();}; + + /** + * @return number of columns of the filter + */ + inline const unsigned int getNBcolumns(){return _filterOutput.getNBcolumns();}; + + /** + * @return number of pixels of the filter + */ + inline const unsigned int getNBpixels(){return _filterOutput.getNBpixels();}; + + /** + * force filter output to be normalized between 0 and maxValue + * @param maxValue: the maximum output value that is required + */ + inline void normalizeGrayOutput_0_maxOutputValue(const double maxValue){_filterOutput.normalizeGrayOutput_0_maxOutputValue(maxValue);}; + + /** + * force filter output to be normalized around 0 and rescaled with a sigmoide effect (extrem values saturation) + * @param maxValue: the maximum output value that is required + */ + inline void normalizeGrayOutputCentredSigmoide(){_filterOutput.normalizeGrayOutputCentredSigmoide();}; + + /** + * force filter output to be normalized : data centering and std normalisation + * @param maxValue: the maximum output value that is required + */ + inline void centerReductImageLuminance(){_filterOutput.centerReductImageLuminance();}; + + /** + * @return the maximum input buffer value + */ + inline const double getMaxInputValue(){return this->_maxInputValue;}; + + /** + * @return the maximum input buffer value + */ + inline void setMaxInputValue(const double newMaxInputValue){this->_maxInputValue=newMaxInputValue;}; + +protected: + + ///////////////////////// + // data buffers + TemplateBuffer _filterOutput; // primary buffer (contains processing outputs) + std::valarray _localBuffer; // local secondary buffer + ///////////////////////// + // PARAMETERS + unsigned int _halfNBrows; + unsigned int _halfNBcolumns; + + // parameters buffers + std::valarray _filteringCoeficientsTable; + std::valarray _progressiveSpatialConstant;// pointer to a local table containing local spatial constant (allocated with the object) + std::valarray _progressiveGain;// pointer to a local table containing local spatial constant (allocated with the object) + + // local adaptation filtering parameters + double _v0; //value used for local luminance adaptation function + double _maxInputValue; + double _meanInputValue; + double _localLuminanceFactor; + double _localLuminanceAddon; + + // protected data related to standard low pass filters parameters + double _a; + double _tau; + double _gain; + + ///////////////////////// + // FILTERS METHODS + + // Basic low pass spation temporal low pass filter used by each retina filters + void _spatiotemporalLPfilter(const double *inputFrame, double *LPfilterOutput, const unsigned int coefTableOffset=0); + const double _squaringSpatiotemporalLPfilter(const double *inputFrame, double *outputFrame, const unsigned int filterIndex=0); + + // LP filter with an irregular spatial filtering + + // -> rewrites the input buffer + void _spatiotemporalLPfilter_Irregular(double *inputOutputFrame, const unsigned int filterIndex=0); + // writes the output on another buffer + void _spatiotemporalLPfilter_Irregular(const double *inputFrame, double *outputFrame, const unsigned int filterIndex=0); + // LP filter that squares the input and computes the output ONLY on the areas where the integrationAreas map are TRUE + void _localSquaringSpatioTemporalLPfilter(const double *inputFrame, double *LPfilterOutput, const unsigned int *integrationAreas, const unsigned int filterIndex=0); + + // local luminance adaptation of the input in regard of localLuminance buffer + void _localLuminanceAdaptation(const double *inputFrame, const double *localLuminance, double *outputFrame); + // local luminance adaptation of the input in regard of localLuminance buffer, the input is rewrited and becomes the output + void _localLuminanceAdaptation(double *inputOutputFrame, const double *localLuminance); + // local adaptation applied on a range of values which can be positive and negative + void _localLuminanceAdaptationPosNegValues(const double *inputFrame, const double *localLuminance, double *outputFrame); + + + ////////////////////////////////////////////////////////////// + // 1D directional filters used for the 2D low pass filtering + + // 1D filters with image input + void _horizontalCausalFilter_addInput(const double *inputFrame, double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + // 1D filters with image input that is squared in the function + void _squaringHorizontalCausalFilter(const double *inputFrame, double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + // vertical anticausal filter that returns the mean value of its result + const double _verticalAnticausalFilter_returnMeanValue(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); + + // most simple functions: only perform 1D filtering with output=input (no add on) + void _horizontalCausalFilter(double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + void _horizontalAnticausalFilter(double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + void _verticalCausalFilter(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); + void _verticalAnticausalFilter(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); + + // perform 1D filtering with output with varrying spatial coefficient + void _horizontalCausalFilter_Irregular(double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + void _horizontalCausalFilter_Irregular_addInput(const double *inputFrame, double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + void _horizontalAnticausalFilter_Irregular(double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd); + void _verticalCausalFilter_Irregular(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); + void _verticalAnticausalFilter_Irregular_multGain(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); + + + // 1D filters in which the output is multiplied by _gain + void _verticalAnticausalFilter_multGain(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); // this functions affects _gain at the output + void _horizontalAnticausalFilter_multGain(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); // this functions affects _gain at the output + + // LP filter on specific parts of the picture instead of all the image + // same functions (some of them) but take a binary flag to allow integration, false flag means, 0 at the output... + void _local_squaringHorizontalCausalFilter(const double *inputFrame, double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const unsigned int *integrationAreas); + void _local_horizontalAnticausalFilter(double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const unsigned int *integrationAreas); + void _local_verticalCausalFilter(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const unsigned int *integrationAreas); + void _local_verticalAnticausalFilter_multGain(double *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const unsigned int *integrationAreas); // this functions affects _gain at the output + +}; + +} +#endif + + diff --git a/modules/contrib/src/chamfermatching.cpp b/modules/contrib/src/chamfermatching.cpp index d45f72f486..12ae018ee7 100644 --- a/modules/contrib/src/chamfermatching.cpp +++ b/modules/contrib/src/chamfermatching.cpp @@ -736,7 +736,7 @@ float ChamferMatcher::Matching::getAngle(coordinate_t a, coordinate_t b, int& dx void ChamferMatcher::Matching::findContourOrientations(const template_coords_t& coords, template_orientations_t& orientations) { const int M = 5; - int coords_size = coords.size(); + int coords_size = (int)coords.size(); std::vector angles(2*M); orientations.insert(orientations.begin(), coords_size, float(-3*CV_PI)); // mark as invalid in the beginning @@ -808,11 +808,12 @@ ChamferMatcher::Template::Template(Mat& edge_image, float scale_) : addr_width(- size.width = max.x - min.x; size.height = max.y - min.y; + int coords_size = (int)coords.size(); - center.x /= (coords.size()==0?1:coords.size()); - center.y /= (coords.size()==0?1:coords.size()); + center.x /= MAX(coords_size, 1); + center.y /= MAX(coords_size, 1); - for (size_t i=0;i B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#include "precomp.hpp" +#include "imagelogpolprojection.hpp" + +#include +#include + +// @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ + +namespace cv +{ + +// constructor +ImageLogPolProjection::ImageLogPolProjection(const unsigned int nbRows, const unsigned int nbColumns, const PROJECTIONTYPE projection, const bool colorModeCapable) +:BasicRetinaFilter(nbRows, nbColumns), + _sampledFrame(0), + _tempBuffer(_localBuffer), + _transformTable(0), + _irregularLPfilteredFrame(_filterOutput) +{ + _inputDoubleNBpixels=nbRows*nbColumns*2; + _selectedProjection = projection; + _reductionFactor=0; + _initOK=false; + _usefullpixelIndex=0; + _colorModeCapable=colorModeCapable; +#ifdef IMAGELOGPOLPROJECTION_DEBUG + std::cout<<"ImageLogPolProjection::allocating"< private init functions dedicated to each projection +bool ImageLogPolProjection::_initLogRetinaSampling(const double reductionFactor, const double samplingStrenght) +{ + _initOK=false; + + if (_selectedProjection!=RETINALOGPROJECTION) + { + std::cerr<<"ImageLogPolProjection::initLogRetinaSampling: could not initialize logPolar projection for a log projection system\n -> you probably chose the wrong init function, use initLogPolarCortexSampling() instead"<getNBrows(), reductionFactor); + _outputNBcolumns=predictOutputSize(this->getNBcolumns(), reductionFactor); + _outputNBpixels=_outputNBrows*_outputNBcolumns; + _outputDoubleNBpixels=_outputNBrows*_outputNBcolumns*2; + +#ifdef IMAGELOGPOLPROJECTION_DEBUG + std::cout<<"ImageLogPolProjection::initLogRetinaSampling: Log resampled image resampling factor: "< ImageLogPolProjection::(u, v)="< ImageLogPolProjection::(u, v)="< "<<(halfInputRows-u)+_filterOutput.getNBrows()*(halfInputColumns+v)< you probably chose the wrong init function, use initLogRetinaSampling() instead"< radiusAxis(_outputNBcolumns); + double radiusStep=2.30/(double)_outputNBcolumns; + for (unsigned int i=0;i<_outputNBcolumns;++i) + { + radiusAxis[i]=i*radiusStep; + } + std::valarray orientationAxis(_outputNBrows); + double orientationStep=-2.0*CV_PI/(double)_outputNBrows; + for (unsigned int io=0;io<_outputNBrows;++io) + { + orientationAxis[io]=io*orientationStep; + } + // -> use a temporay transform table which is bigger than the final one, we only report pixels coordinates that are included in the sampled picture + std::valarray tempTransformTable(2*_outputNBpixels); // the structure would be: (pixelInputCoordinate n)(pixelOutputCoordinate n)(pixelInputCoordinate n+1)(pixelOutputCoordinate n+1) + _usefullpixelIndex=0; + + //std::cout<<"ImageLogPolProjection::Starting cortex projection"<0)&&(rowIndex<_filterOutput.getNBrows())&&(rowIndex>0)) + { + // set coordinate + tempTransformTable[_usefullpixelIndex++]=radiusIndex+orientationIndex*_outputNBcolumns; + tempTransformTable[_usefullpixelIndex++]= columnIndex+rowIndex*_filterOutput.getNBcolumns(); + } + } + + // (re)creating and filling the transform table + _transformTable.resize(_usefullpixelIndex); + memcpy(&_transformTable[0], &tempTransformTable[0], sizeof(unsigned int)*_usefullpixelIndex); + + // reset all buffers + clearAllBuffers(); + _initOK=true; + return true; +} + +// action function +std::valarray &ImageLogPolProjection::runProjection(const std::valarray &inputFrame, const double colorMode) +{ + if (_colorModeCapable&&colorMode) + { + // progressive filtering and storage of the result in _tempBuffer + _spatiotemporalLPfilter_Irregular(get_data(inputFrame), &_irregularLPfilteredFrame[0]); + _spatiotemporalLPfilter_Irregular(&_irregularLPfilteredFrame[0], &_tempBuffer[0]); // warning, temporal issue may occur, if the temporal constant is not NULL !!! + + _spatiotemporalLPfilter_Irregular(get_data(inputFrame)+_filterOutput.getNBpixels(), &_irregularLPfilteredFrame[0]); + _spatiotemporalLPfilter_Irregular(&_irregularLPfilteredFrame[0], &_tempBuffer[0]+_filterOutput.getNBpixels()); + + _spatiotemporalLPfilter_Irregular(get_data(inputFrame)+_filterOutput.getNBpixels()*2, &_irregularLPfilteredFrame[0]); + _spatiotemporalLPfilter_Irregular(&_irregularLPfilteredFrame[0], &_tempBuffer[0]+_filterOutput.getNBpixels()*2); + + // applying image projection/resampling + register unsigned int *transformTablePTR=&_transformTable[0]; + for (unsigned int i=0 ; i<_usefullpixelIndex ; i+=2, transformTablePTR+=2) + { +#ifdef IMAGELOGPOLPROJECTION_DEBUG + std::cout<<"ImageLogPolProjection::i:"< B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#ifndef IMAGELOGPOLPROJECTION_H_ +#define IMAGELOGPOLPROJECTION_H_ + +/** +* @class ImageLogPolProjection +* @brief class able to perform a log sampling of an image input (models the log sampling of the photoreceptors of the retina) +* or a log polar projection which models the retina information projection on the primary visual cortex: a linear projection in the center for detail analysis and a log projection of the borders (low spatial frequency motion information in general) +* +* collaboration: Barthelemy DURETTE who experimented the retina log projection +-> "Traitement visuels Bio mimtiques pour la supplance perceptive", internal technical report, May 2005, Gipsa-lab/DIS, Grenoble, FRANCE +* +* * TYPICAL USE: +* +* // create object, here for a log sampling (keyword:RETINALOGPROJECTION): (dynamic object allocation sample) +* ImageLogPolProjection *imageSamplingTool; +* imageSamplingTool = new ImageLogPolProjection(frameSizeRows, frameSizeColumns, RETINALOGPROJECTION); +* +* // init log projection: +* imageSamplingTool->initProjection(1.0, 15.0); +* +* // during program execution, call the log transform applied to a frame called "FrameBuffer" : +* imageSamplingTool->runProjection(FrameBuffer); +* // get output frame and its size: +* const unsigned int logSampledFrame_nbRows=imageSamplingTool->getOutputNBrows(); +* const unsigned int logSampledFrame_nbColumns=imageSamplingTool->getOutputNBcolumns(); +* const double *logSampledFrame=imageSamplingTool->getSampledFrame(); +* +* // at the end of the program, destroy object: +* delete imageSamplingTool; +* +* @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ +* Creation date 2007 +*/ + +//#define __IMAGELOGPOLPROJECTION_DEBUG // used for std output debug information + +#include "basicretinafilter.hpp" + + +namespace cv +{ + +class ImageLogPolProjection:public BasicRetinaFilter +{ +public: + + enum PROJECTIONTYPE{RETINALOGPROJECTION, CORTEXLOGPOLARPROJECTION}; + + /** + * constructor, just specifies the image input size and the projection type, no projection initialisation is done + * -> use initLogRetinaSampling() or initLogPolarCortexSampling() for that + * @param nbRows: number of rows of the input image + * @param nbColumns: number of columns of the input image + * @param projection: the type of projection, RETINALOGPROJECTION or CORTEXLOGPOLARPROJECTION + * @param colorMode: specifies if the projection is applied on a grayscale image (false) or color images (3 layers) (true) + */ + ImageLogPolProjection(const unsigned int nbRows, const unsigned int nbColumns, const PROJECTIONTYPE projection, const bool colorMode=false); + + /** + * standard destructor + */ + virtual ~ImageLogPolProjection(); + + /** + * function that clears all buffers of the object + */ + void clearAllBuffers(); + + /** + * resize retina color filter object (resize all allocated buffers) + * @param NBrows: the new height size + * @param NBcolumns: the new width size + */ + void resize(const unsigned int NBrows, const unsigned int NBcolumns); + + /** + * init function depending on the projection type + * @param reductionFactor: the size reduction factor of the ouptup image in regard of the size of the input image, must be superior to 1 + * @param samplingStrenght: specifies the strenght of the log compression effect (magnifying coefficient) + * @return true if the init was performed without any errors + */ + bool initProjection(const double reductionFactor, const double samplingStrenght); + + /** + * main funtion of the class: run projection function + * @param inputFrame: the input frame to be processed + * @return the output frame + */ + std::valarray &runProjection(const std::valarray &inputFrame, const double colorMode=false); + + /** + * @return the numbers of rows (height) of the images OUTPUTS of the object + */ + inline const unsigned int getOutputNBrows(){return _outputNBrows;}; + + /** + * @return the numbers of columns (width) of the images OUTPUTS of the object + */ + inline const unsigned int getOutputNBcolumns(){return _outputNBcolumns;}; + + /** + * main funtion of the class: run projection function + * @param size: one of the input frame initial dimensions to be processed + * @return the output frame dimension + */ + inline static const unsigned int predictOutputSize(const unsigned int size, const double reductionFactor){return (unsigned int)((double)size/reductionFactor);}; + + /** + * @return the output of the filter which applies an irregular Low Pass spatial filter to the imag input (see function + */ + inline const std::valarray &getIrregularLPfilteredInputFrame() const {return _irregularLPfilteredFrame;}; + + /** + * function which allows to retrieve the output frame which was updated after the "runProjection(...) function BasicRetinaFilter::runProgressiveFilter(...) + * @return the projection result + */ + inline const std::valarray &getSampledFrame() const {return _sampledFrame;}; + + /** + * function which allows gives the tranformation table, its size is (getNBrows()*getNBcolumns()*2) + * @return the transformation matrix [outputPixIndex_i, inputPixIndex_i, outputPixIndex_i+1, inputPixIndex_i+1....] + */ + inline const std::valarray &getSamplingMap() const {return _transformTable;}; + + inline const double getOriginalRadiusLength(const double projectedRadiusLength){return _azero/(_alim-projectedRadiusLength*2.0/_minDimension);}; + + // unsigned int getInputPixelIndex(const unsigned int ){ return _transformTable[index*2+1]}; + +private: + PROJECTIONTYPE _selectedProjection; + + // size of the image output + unsigned int _outputNBrows; + unsigned int _outputNBcolumns; + unsigned int _outputNBpixels; + unsigned int _outputDoubleNBpixels; + unsigned int _inputDoubleNBpixels; + + // is the object able to manage color flag + bool _colorModeCapable; + // sampling strenght factor + double _samplingStrenght; + // sampling reduction factor + double _reductionFactor; + + // log sampling parameters + double _azero; + double _alim; + double _minDimension; + + // template buffers + std::valarray_sampledFrame; + std::valarray&_tempBuffer; + std::valarray_transformTable; + + std::valarray &_irregularLPfilteredFrame; // just a reference for easier understanding + unsigned int _usefullpixelIndex; + + // init transformation tables + bool _computeLogProjection(); + bool _computeLogPolarProjection(); + + // specifies if init was done correctly + bool _initOK; + // private init projections functions called by "initProjection(...)" function + bool _initLogRetinaSampling(const double reductionFactor, const double samplingStrenght); + bool _initLogPolarCortexSampling(const double reductionFactor, const double samplingStrenght); + +}; + +} +#endif /*IMAGELOGPOLPROJECTION_H_*/ diff --git a/modules/contrib/src/magnoretinafilter.cpp b/modules/contrib/src/magnoretinafilter.cpp new file mode 100644 index 0000000000..8956539f26 --- /dev/null +++ b/modules/contrib/src/magnoretinafilter.cpp @@ -0,0 +1,207 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#include "precomp.hpp" + +#include + +#include "magnoretinafilter.hpp" + +#include + +namespace cv +{ +// Constructor and Desctructor of the OPL retina filter +MagnoRetinaFilter::MagnoRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns) +:BasicRetinaFilter(NBrows, NBcolumns, 2), + _previousInput_ON(NBrows*NBcolumns), + _previousInput_OFF(NBrows*NBcolumns), + _amacrinCellsTempOutput_ON(NBrows*NBcolumns), + _amacrinCellsTempOutput_OFF(NBrows*NBcolumns), + _magnoXOutputON(NBrows*NBcolumns), + _magnoXOutputOFF(NBrows*NBcolumns), + _localProcessBufferON(NBrows*NBcolumns), + _localProcessBufferOFF(NBrows*NBcolumns) +{ + _magnoYOutput=&_filterOutput; + _magnoYsaturated=&_localBuffer; + + + clearAllBuffers(); + +#ifdef IPL_RETINA_ELEMENT_DEBUG + std::cout<<"MagnoRetinaFilter::Init IPL retina filter at specified frame size OK"<getNBpixels(); ++IDpixel) + { + + /* Compute ON and OFF amacrin cells high pass temporal filter */ + double magnoXonPixelResult = _temporalCoefficient*(*amacrinCellsTempOutput_ON_PTR+ *OPL_ON_PTR-*previousInput_ON_PTR); + *(amacrinCellsTempOutput_ON_PTR++)=((double)(magnoXonPixelResult>0))*magnoXonPixelResult; + + double magnoXoffPixelResult = _temporalCoefficient*(*amacrinCellsTempOutput_OFF_PTR+ *OPL_OFF_PTR-*previousInput_OFF_PTR); + *(amacrinCellsTempOutput_OFF_PTR++)=((double)(magnoXoffPixelResult>0))*magnoXoffPixelResult; + + /* prepare next loop */ + *(previousInput_ON_PTR++)=*(OPL_ON_PTR++); + *(previousInput_OFF_PTR++)=*(OPL_OFF_PTR++); + + } +} + +// launch filter that runs all the IPL filter +const std::valarray &MagnoRetinaFilter::runFilter(const std::valarray &OPL_ON, const std::valarray &OPL_OFF) +{ + // Compute the high pass temporal filter + _amacrineCellsComputing(get_data(OPL_ON), get_data(OPL_OFF)); + + // apply low pass filtering on ON and OFF ways after temporal high pass filtering + _spatiotemporalLPfilter(&_amacrinCellsTempOutput_ON[0], &_magnoXOutputON[0], 0); + _spatiotemporalLPfilter(&_amacrinCellsTempOutput_OFF[0], &_magnoXOutputOFF[0], 0); + + // local adaptation of the ganglion cells to the local contrast of the moving contours + _spatiotemporalLPfilter(&_magnoXOutputON[0], &_localProcessBufferON[0], 1); + _localLuminanceAdaptation(&_magnoXOutputON[0], &_localProcessBufferON[0]); + _spatiotemporalLPfilter(&_magnoXOutputOFF[0], &_localProcessBufferOFF[0], 1); + _localLuminanceAdaptation(&_magnoXOutputOFF[0], &_localProcessBufferOFF[0]); + + /* Compute MagnoY */ + register double *magnoYOutput= &(*_magnoYOutput)[0]; + register double *magnoXOutputON_PTR= &_magnoXOutputON[0]; + register double *magnoXOutputOFF_PTR= &_magnoXOutputOFF[0]; + for (register unsigned int IDpixel=0 ; IDpixel<_filterOutput.getNBpixels() ; ++IDpixel) + *(magnoYOutput++)=*(magnoXOutputON_PTR++)+*(magnoXOutputOFF_PTR++); + + return (*_magnoYOutput); +} +} + + diff --git a/modules/contrib/src/magnoretinafilter.hpp b/modules/contrib/src/magnoretinafilter.hpp new file mode 100644 index 0000000000..8a6d329cbe --- /dev/null +++ b/modules/contrib/src/magnoretinafilter.hpp @@ -0,0 +1,203 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#ifndef MagnoRetinaFilter_H_ +#define MagnoRetinaFilter_H_ + +/** +* @class MagnoRetinaFilter +* @brief class which describes the magnocellular channel of the retina: +* -> performs a moving contours extraction with powerfull local data enhancement +* +* TYPICAL USE: +* +* // create object at a specified picture size +* MagnoRetinaFilter *movingContoursExtractor; +* movingContoursExtractor =new MagnoRetinaFilter(frameSizeRows, frameSizeColumns); +* +* // init gain, spatial and temporal parameters: +* movingContoursExtractor->setCoefficientsTable(0, 0.7, 5, 3); +* +* // during program execution, call the filter for contours extraction for an input picture called "FrameBuffer": +* movingContoursExtractor->runfilter(FrameBuffer); +* +* // get the output frame, check in the class description below for more outputs: +* const double *movingContours=movingContoursExtractor->getMagnoYsaturated(); +* +* // at the end of the program, destroy object: +* delete movingContoursExtractor; + +* @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ +* Creation date 2007 +* Based on Alexandre BENOIT thesis: "Le système visuel humain au secours de la vision par ordinateur" +*/ + +#include "basicretinafilter.hpp" + +//#define _IPL_RETINA_ELEMENT_DEBUG + +namespace cv +{ + +class MagnoRetinaFilter: public BasicRetinaFilter +{ +public: + /** + * constructor parameters are only linked to image input size + * @param NBrows: number of rows of the input image + * @param NBcolumns: number of columns of the input image + */ + MagnoRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns); + + + /** + * destructor + */ + virtual ~MagnoRetinaFilter(); + + /** + * function that clears all buffers of the object + */ + void clearAllBuffers(); + + /** + * resize retina magno filter object (resize all allocated buffers) + * @param NBrows: the new height size + * @param NBcolumns: the new width size + */ + void resize(const unsigned int NBrows, const unsigned int NBcolumns); + + /** + * set parameters values + * @param parasolCells_beta: the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 + * @param parasolCells_tau: the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) + * @param parasolCells_k: the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 + * @param amacrinCellsTemporalCutFrequency: the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, tipicall value is 5 + * @param localAdaptIntegration_tau: specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + * @param localAdaptIntegration_k: specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + */ + void setCoefficientsTable(const double parasolCells_beta, const double parasolCells_tau, const double parasolCells_k, const double amacrinCellsTemporalCutFrequency, const double localAdaptIntegration_tau, const double localAdaptIntegration_k); + + /** + * launch filter that runs all the IPL magno filter (model of the magnocellular channel of the Inner Plexiform Layer of the retina) + * @param OPL_ON: the output of the bipolar ON cells of the retina (available from the ParvoRetinaFilter class (getBipolarCellsON() function) + * @param OPL_OFF: the output of the bipolar OFF cells of the retina (available from the ParvoRetinaFilter class (getBipolarCellsOFF() function) + * @return the processed result without post-processing + */ + const std::valarray &runFilter(const std::valarray &OPL_ON, const std::valarray &OPL_OFF); + + /** + * @return the Magnocellular ON channel filtering output + */ + inline const std::valarray &getMagnoON() const {return _magnoXOutputON;}; + + /** + * @return the Magnocellular OFF channel filtering output + */ + inline const std::valarray &getMagnoOFF() const {return _magnoXOutputOFF;}; + + /** + * @return the Magnocellular Y (sum of the ON and OFF magno channels) filtering output + */ + inline const std::valarray &getMagnoYsaturated() const {return *_magnoYsaturated;}; + + /** + * applies an image normalization which saturates the high output values by the use of an assymetric sigmoide + */ + inline void normalizeGrayOutputNearZeroCentreredSigmoide(){_filterOutput.normalizeGrayOutputNearZeroCentreredSigmoide(&(*_magnoYOutput)[0], &(*_magnoYsaturated)[0]);}; + + /** + * @return the horizontal cells' temporal constant + */ + inline const double getTemporalConstant(){return this->_filteringCoeficientsTable[2];}; + +private: + + // related pointers to these buffers + std::valarray _previousInput_ON; + std::valarray _previousInput_OFF; + std::valarray _amacrinCellsTempOutput_ON; + std::valarray _amacrinCellsTempOutput_OFF; + std::valarray _magnoXOutputON; + std::valarray _magnoXOutputOFF; + std::valarray _localProcessBufferON; + std::valarray _localProcessBufferOFF; + // reference to parent buffers and allow better readability + TemplateBuffer *_magnoYOutput; + std::valarray *_magnoYsaturated; + + // varialbles + double _temporalCoefficient; + + // amacrine cells filter : high pass temporal filter + void _amacrineCellsComputing(const double *ONinput, const double *OFFinput); + + +}; + +} + +#endif /*MagnoRetinaFilter_H_*/ + + diff --git a/modules/contrib/src/parvoretinafilter.cpp b/modules/contrib/src/parvoretinafilter.cpp new file mode 100644 index 0000000000..4b730d024d --- /dev/null +++ b/modules/contrib/src/parvoretinafilter.cpp @@ -0,0 +1,227 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#include "precomp.hpp" + +#include "parvoretinafilter.hpp" + +// @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ + +#include +#include + +namespace cv +{ +////////////////////////////////////////////////////////// +// OPL RETINA FILTER +////////////////////////////////////////////////////////// + +// Constructor and Desctructor of the OPL retina filter + +ParvoRetinaFilter::ParvoRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns) +:BasicRetinaFilter(NBrows, NBcolumns, 3), + _photoreceptorsOutput(NBrows*NBcolumns), + _horizontalCellsOutput(NBrows*NBcolumns), + _parvocellularOutputON(NBrows*NBcolumns), + _parvocellularOutputOFF(NBrows*NBcolumns), + _bipolarCellsOutputON(NBrows*NBcolumns), + _bipolarCellsOutputOFF(NBrows*NBcolumns), + _localAdaptationOFF(NBrows*NBcolumns) +{ + // link to the required local parent adaptation buffers + _localAdaptationON=&_localBuffer; + _parvocellularOutputONminusOFF=&_filterOutput; + // (*_localAdaptationON)=&_localBuffer; + // (*_parvocellularOutputONminusOFF)=&(BasicRetinaFilter::TemplateBuffer); + + // init: set all the values to 0 + clearAllBuffers(); + + +#ifdef OPL_RETINA_ELEMENT_DEBUG + std::cout<<"ParvoRetinaFilter::Init OPL retina filter at specified frame size OK\n"< &ParvoRetinaFilter::runFilter(const std::valarray &inputFrame, const bool useParvoOutput) +{ + _spatiotemporalLPfilter(get_data(inputFrame), &_photoreceptorsOutput[0]); + _spatiotemporalLPfilter(&_photoreceptorsOutput[0], &_horizontalCellsOutput[0], 1); + _OPL_OnOffWaysComputing(); + + if (useParvoOutput) + { + // local adaptation processes on ON and OFF ways + _spatiotemporalLPfilter(&_bipolarCellsOutputON[0], &(*_localAdaptationON)[0], 2); + _localLuminanceAdaptation(&_parvocellularOutputON[0], &(*_localAdaptationON)[0]); + + _spatiotemporalLPfilter(&_bipolarCellsOutputOFF[0], &_localAdaptationOFF[0], 2); + _localLuminanceAdaptation(&_parvocellularOutputOFF[0], &_localAdaptationOFF[0]); + + //// Final loop that computes the main output of this filter + // + //// loop that makes the difference between photoreceptor cells output and horizontal cells + //// positive part goes on the ON way, negative pat goes on the OFF way + register double *parvocellularOutputONminusOFF_PTR=&(*_parvocellularOutputONminusOFF)[0]; + register double *parvocellularOutputON_PTR=&_parvocellularOutputON[0]; + register double *parvocellularOutputOFF_PTR=&_parvocellularOutputOFF[0]; + + for (register unsigned int IDpixel=0 ; IDpixel<_filterOutput.getNBpixels() ; ++IDpixel) + *(parvocellularOutputONminusOFF_PTR++)= (*(parvocellularOutputON_PTR++)-*(parvocellularOutputOFF_PTR++)); + } + return (*_parvocellularOutputONminusOFF); +} + +void ParvoRetinaFilter::_OPL_OnOffWaysComputing() +{ + // loop that makes the difference between photoreceptor cells output and horizontal cells + // positive part goes on the ON way, negative pat goes on the OFF way + register double *photoreceptorsOutput_PTR= &_photoreceptorsOutput[0]; + register double *horizontalCellsOutput_PTR= &_horizontalCellsOutput[0]; + register double *bipolarCellsON_PTR = &_bipolarCellsOutputON[0]; + register double *bipolarCellsOFF_PTR = &_bipolarCellsOutputOFF[0]; + register double *parvocellularOutputON_PTR= &_parvocellularOutputON[0]; + register double *parvocellularOutputOFF_PTR= &_parvocellularOutputOFF[0]; + + // compute bipolar cells response equal to photoreceptors minus horizontal cells response + // and copy the result on parvo cellular outputs... keeping time before their local contrast adaptation for final result + for (register unsigned int IDpixel=0 ; IDpixel<_filterOutput.getNBpixels() ; ++IDpixel) + { + double pixelDifference = *(photoreceptorsOutput_PTR++) -*(horizontalCellsOutput_PTR++); + // test condition to allow write pixelDifference in ON or OFF buffer and 0 in the over + double isPositive=(double) (pixelDifference>0); + + // ON and OFF channels writing step + *(parvocellularOutputON_PTR++)=*(bipolarCellsON_PTR++) = isPositive*pixelDifference; + *(parvocellularOutputOFF_PTR++)=*(bipolarCellsOFF_PTR++)= (isPositive-1.0)*pixelDifference; + } +} +} + diff --git a/modules/contrib/src/parvoretinafilter.hpp b/modules/contrib/src/parvoretinafilter.hpp new file mode 100644 index 0000000000..9ce75a2906 --- /dev/null +++ b/modules/contrib/src/parvoretinafilter.hpp @@ -0,0 +1,222 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#ifndef ParvoRetinaFilter_H_ +#define ParvoRetinaFilter_H_ + +/** +* @class ParvoRetinaFilter +* @brief class which describes the OPL retina model and the Inner Plexiform Layer parvocellular channel of the retina: +* -> performs a contours extraction with powerfull local data enhancement as at the retina level +* -> spectrum whitening occurs at the OPL (Outer Plexiform Layer) of the retina: corrects the 1/f spectrum tendancy of natural images +* ---> enhances details with mid spatial frequencies, attenuates low spatial frequencies (luminance), attenuates high temporal frequencies and high spatial frequencies, etc. +* +* TYPICAL USE: +* +* // create object at a specified picture size +* ParvoRetinaFilter *contoursExtractor; +* contoursExtractor =new ParvoRetinaFilter(frameSizeRows, frameSizeColumns); +* +* // init gain, spatial and temporal parameters: +* contoursExtractor->setCoefficientsTable(0, 0.7, 1, 0, 7, 1); +* +* // during program execution, call the filter for contours extraction for an input picture called "FrameBuffer": +* contoursExtractor->runfilter(FrameBuffer); +* +* // get the output frame, check in the class description below for more outputs: +* const double *contours=contoursExtractor->getParvoONminusOFF(); +* +* // at the end of the program, destroy object: +* delete contoursExtractor; + +* @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ +* Creation date 2007 +* Based on Alexandre BENOIT thesis: "Le système visuel humain au secours de la vision par ordinateur" +* +*/ + +#include "basicretinafilter.hpp" + + +//#define _OPL_RETINA_ELEMENT_DEBUG + +namespace cv +{ +//retina classes that derivate from the Basic Retrina class +class ParvoRetinaFilter: public BasicRetinaFilter +{ + +public: + /** + * constructor parameters are only linked to image input size + * @param NBrows: number of rows of the input image + * @param NBcolumns: number of columns of the input image + */ + ParvoRetinaFilter(const unsigned int NBrows=480, const unsigned int NBcolumns=640); + + /** + * standard desctructor + */ + virtual ~ParvoRetinaFilter(); + + /** + * resize method, keeps initial parameters, all buffers are flushed + * @param NBrows: number of rows of the input image + * @param NBcolumns: number of columns of the input image + */ + void resize(const unsigned int NBrows, const unsigned int NBcolumns); + + /** + * function that clears all buffers of the object + */ + void clearAllBuffers(); + + /** + * setup the OPL and IPL parvo channels + * @param beta1: gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, the amplitude is boosted but it should only be used for values rescaling... if needed + * @param tau1: the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame + * @param k1: the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel + * @param beta2: gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 + * @param tau2: the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors + * @param k2: the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) + */ + void setOPLandParvoFiltersParameters(const double beta1, const double tau1, const double k1, const double beta2, const double tau2, const double k2); + + /** + * setup more precisely the low pass filter used for the ganglion cells low pass filtering (used for local luminance adaptation) + * @param tau: time constant of the filter (unit is frame for video processing) + * @param k: spatial constant of the filter (unit is pixels) + */ + void setGanglionCellsLocalAdaptationLPfilterParameters(const double tau, const double k){BasicRetinaFilter::setLPfilterParameters(0, tau, k, 2);}; // change the parameters of the filter + + + /** + * launch filter that runs the OPL spatiotemporal filtering and optionally finalizes IPL Pagno filter (model of the Parvocellular channel of the Inner Plexiform Layer of the retina) + * @param inputFrame: the input image to be processed, this can be the direct gray level input frame, but a better efficacy is expected if the input is preliminary processed by the photoreceptors local adaptation possible to acheive with the help of a BasicRetinaFilter object + * @param useParvoOutput: set true if the final IPL filtering step has to be computed (local contrast enhancement) + * @return the processed Parvocellular channel output (updated only if useParvoOutput is true) + * @details: in any case, after this function call, photoreceptors and horizontal cells output are updated, use getPhotoreceptorsLPfilteringOutput() and getHorizontalCellsOutput() to get them + * also, bipolar cells output are accessible (difference between photoreceptors and horizontal cells, ON output has positive values, OFF ouput has negative values), use the following access methods: getBipolarCellsON() and getBipolarCellsOFF()if useParvoOutput is true, + * if useParvoOutput is true, the complete Parvocellular channel is computed, more outputs are updated and can be accessed threw: getParvoON(), getParvoOFF() and their difference with getOutput() + */ + const std::valarray &runFilter(const std::valarray &inputFrame, const bool useParvoOutput=true); // output return is _parvocellularOutputONminusOFF + + /** + * @return the output of the photoreceptors filtering step (high cut frequency spatio-temporal low pass filter) + */ + inline const std::valarray &getPhotoreceptorsLPfilteringOutput() const {return _photoreceptorsOutput;}; + + /** + * @return the output of the photoreceptors filtering step (low cut frequency spatio-temporal low pass filter) + */ + inline const std::valarray &getHorizontalCellsOutput() const { return _horizontalCellsOutput;}; + + /** + * @return the output Parvocellular ON channel of the retina model + */ + inline const std::valarray &getParvoON() const {return _parvocellularOutputON;}; + + /** + * @return the output Parvocellular OFF channel of the retina model + */ + inline const std::valarray &getParvoOFF() const {return _parvocellularOutputOFF;}; + + /** + * @return the output of the Bipolar cells of the ON channel of the retina model same as function getParvoON() but without luminance local adaptation + */ + inline const std::valarray &getBipolarCellsON() const {return _bipolarCellsOutputON;}; + + /** + * @return the output of the Bipolar cells of the OFF channel of the retina model same as function getParvoON() but without luminance local adaptation + */ + inline const std::valarray &getBipolarCellsOFF() const {return _bipolarCellsOutputOFF;}; + + /** + * @return the photoreceptors's temporal constant + */ + inline const double getPhotoreceptorsTemporalConstant(){return this->_filteringCoeficientsTable[2];}; + + /** + * @return the horizontal cells' temporal constant + */ + inline const double getHcellsTemporalConstant(){return this->_filteringCoeficientsTable[5];}; + +private: + // template buffers + std::valarray _photoreceptorsOutput; + std::valarray _horizontalCellsOutput; + std::valarray _parvocellularOutputON; + std::valarray _parvocellularOutputOFF; + std::valarray _bipolarCellsOutputON; + std::valarray _bipolarCellsOutputOFF; + std::valarray _localAdaptationOFF; + std::valarray *_localAdaptationON; + TemplateBuffer *_parvocellularOutputONminusOFF; + // private functions + void _OPL_OnOffWaysComputing(); + +}; +} +#endif + diff --git a/modules/contrib/src/precomp.hpp b/modules/contrib/src/precomp.hpp index aab2c8fa66..1f0ef9b063 100644 --- a/modules/contrib/src/precomp.hpp +++ b/modules/contrib/src/precomp.hpp @@ -58,4 +58,14 @@ #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/core/internal.hpp" +namespace cv +{ + +// special function to get pointer to constant valarray elements, since +// simple &arr[0] does not compile on VS2005/VS2008. +template inline const T* get_data(const std::valarray& arr) +{ return &((std::valarray&)arr)[0]; } + +} + #endif diff --git a/modules/contrib/src/retina.cpp b/modules/contrib/src/retina.cpp new file mode 100644 index 0000000000..faa9b46629 --- /dev/null +++ b/modules/contrib/src/retina.cpp @@ -0,0 +1,409 @@ +/*#****************************************************************************** + ** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + ** + ** By downloading, copying, installing or using the software you agree to this license. + ** If you do not agree to this license, do not download, install, + ** copy or use the software. + ** + ** + ** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. + ** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. + ** + ** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) + ** + ** Creation - enhancement process 2007-2011 + ** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France + ** + ** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). + ** Refer to the following research paper for more information: + ** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + ** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: + ** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + ** + ** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : + ** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: + ** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 + ** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. + ** ====> more informations in the above cited Jeanny Heraults's book. + ** + ** License Agreement + ** For Open Source Computer Vision Library + ** + ** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + ** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. + ** + ** For Human Visual System tools (hvstools) + ** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. + ** + ** Third party copyrights are property of their respective owners. + ** + ** Redistribution and use in source and binary forms, with or without modification, + ** are permitted provided that the following conditions are met: + ** + ** * Redistributions of source code must retain the above copyright notice, + ** this list of conditions and the following disclaimer. + ** + ** * Redistributions in binary form must reproduce the above copyright notice, + ** this list of conditions and the following disclaimer in the documentation + ** and/or other materials provided with the distribution. + ** + ** * The name of the copyright holders may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** This software is provided by the copyright holders and contributors "as is" and + ** any express or implied warranties, including, but not limited to, the implied + ** warranties of merchantability and fitness for a particular purpose are disclaimed. + ** In no event shall the Intel Corporation or contributors be liable for any direct, + ** indirect, incidental, special, exemplary, or consequential damages + ** (including, but not limited to, procurement of substitute goods or services; + ** loss of use, data, or profits; or business interruption) however caused + ** and on any theory of liability, whether in contract, strict liability, + ** or tort (including negligence or otherwise) arising in any way out of + ** the use of this software, even if advised of the possibility of such damage. + *******************************************************************************/ + +/* + * Retina.cpp + * + * Created on: Jul 19, 2011 + * Author: Alexandre Benoit + */ +#include "precomp.hpp" +#include "retinafilter.hpp" +#include + +namespace cv +{ + +Retina::Retina(const std::string parametersSaveFile, const cv::Size inputSize) +{ + _retinaFilter = 0; + _init(parametersSaveFile, inputSize, true, RETINA_COLOR_BAYER, false); +} + +Retina::Retina(const std::string parametersSaveFile, const cv::Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod, const bool useRetinaLogSampling, const double reductionFactor, const double samplingStrenght) +{ + _retinaFilter = 0; + _init(parametersSaveFile, inputSize, colorMode, colorSamplingMethod, useRetinaLogSampling, reductionFactor, samplingStrenght); +}; + +Retina::~Retina() +{ + delete _retinaFilter; +} + +void Retina::setup(std::string retinaParameterFile, const bool applyDefaultSetupOnFailure) +{ + // open specified parameters file + std::cout<<"Retina::setup: setting up retina from parameter file : "<>colorMode; + currFn["normaliseOutput"]>>normaliseOutput; + currFn["photoreceptorsLocalAdaptationSensitivity"]>>photoreceptorsLocalAdaptationSensitivity; + currFn["photoreceptorsTemporalConstant"]>>photoreceptorsTemporalConstant; + currFn["photoreceptorsSpatialConstant"]>>photoreceptorsSpatialConstant; + currFn["horizontalCellsGain"]>>horizontalCellsGain; + currFn["hcellsTemporalConstant"]>>hcellsTemporalConstant; + currFn["hcellsSpatialConstant"]>>hcellsSpatialConstant; + currFn["ganglionCellsSensitivity"]>>ganglionCellsSensitivity; + setupOPLandIPLParvoChannel(colorMode, normaliseOutput, photoreceptorsLocalAdaptationSensitivity, photoreceptorsTemporalConstant, photoreceptorsSpatialConstant, horizontalCellsGain, hcellsTemporalConstant, hcellsSpatialConstant, ganglionCellsSensitivity); + + // init retina IPL magno setup + currFn=rootFn["IPLmagno"]; + currFn["normaliseOutput"]>>normaliseOutput; + double parasolCells_beta, parasolCells_tau, parasolCells_k, amacrinCellsTemporalCutFrequency, V0CompressionParameter, localAdaptintegration_tau, localAdaptintegration_k; + currFn["parasolCells_beta"]>>parasolCells_beta; + currFn["parasolCells_tau"]>>parasolCells_tau; + currFn["parasolCells_k"]>>parasolCells_k; + currFn["amacrinCellsTemporalCutFrequency"]>>amacrinCellsTemporalCutFrequency; + currFn["V0CompressionParameter"]>>V0CompressionParameter; + currFn["localAdaptintegration_tau"]>>localAdaptintegration_tau; + currFn["localAdaptintegration_k"]>>localAdaptintegration_k; + + setupIPLMagnoChannel(normaliseOutput, parasolCells_beta, parasolCells_tau, parasolCells_k, amacrinCellsTemporalCutFrequency, + V0CompressionParameter, localAdaptintegration_tau, localAdaptintegration_k); + + }catch(Exception &e) + { + std::cout<<"Retina::setup: resetting retina with default parameters"<"< keeping current parameters"< colorMode : " << currFn["colorMode"].operator int() + << "\n==> normalizeParvoOutput :" << currFn["normaliseOutput"].operator int() + << "\n==> photoreceptorsLocalAdaptationSensitivity : " << currFn["photoreceptorsLocalAdaptationSensitivity"].operator float() + << "\n==> photoreceptorsTemporalConstant : " << currFn["photoreceptorsTemporalConstant"].operator float() + << "\n==> photoreceptorsSpatialConstant : " << currFn["photoreceptorsSpatialConstant"].operator float() + << "\n==> horizontalCellsGain : " << currFn["horizontalCellsGain"].operator float() + << "\n==> hcellsTemporalConstant : " << currFn["hcellsTemporalConstant"].operator float() + << "\n==> hcellsSpatialConstant : " << currFn["hcellsSpatialConstant"].operator float() + << "\n==> parvoGanglionCellsSensitivity : " << currFn["ganglionCellsSensitivity"].operator float() + <<"}\n"; + + // displaying IPL magno setup + currFn=rootFn["IPLmagno"]; + outmessage<<"Current Retina instance setup :" + <<"\nIPLmagno"<<"{" + << "\n==> normaliseOutput : " << currFn["normaliseOutput"].operator int() + << "\n==> parasolCells_beta : " << currFn["parasolCells_beta"].operator float() + << "\n==> parasolCells_tau : " << currFn["parasolCells_tau"].operator float() + << "\n==> parasolCells_k : " << currFn["parasolCells_k"].operator float() + << "\n==> amacrinCellsTemporalCutFrequency : " << currFn["amacrinCellsTemporalCutFrequency"].operator float() + << "\n==> V0CompressionParameter : " << currFn["V0CompressionParameter"].operator float() + << "\n==> localAdaptintegration_tau : " << currFn["localAdaptintegration_tau"].operator float() + << "\n==> localAdaptintegration_k : " << currFn["localAdaptintegration_k"].operator float() + <<"}"; + } + }catch(cv::Exception &e) + { + outmessage<<"Error reading parameters configuration file : "<setColorMode(colorMode); + _retinaFilter->setPhotoreceptorsLocalAdaptationSensitivity(photoreceptorsLocalAdaptationSensitivity); + _retinaFilter->setOPLandParvoParameters(0, photoreceptorsTemporalConstant, photoreceptorsSpatialConstant, horizontalCellsGain, HcellsTemporalConstant, HcellsSpatialConstant, ganglionCellsSensitivity); + _retinaFilter->setParvoGanglionCellsLocalAdaptationSensitivity(ganglionCellsSensitivity); + _retinaFilter->activateNormalizeParvoOutput_0_maxOutputValue(normaliseOutput); + + // save parameters in the xml parameters tree... if parameters file is already open + if (!_parametersSaveFile.isOpened()) + return; + _parametersSaveFile<<"OPLandIPLparvo"<<"{"; + _parametersSaveFile << "colorMode" << colorMode; + _parametersSaveFile << "normaliseOutput" << normaliseOutput; + _parametersSaveFile << "photoreceptorsLocalAdaptationSensitivity" << photoreceptorsLocalAdaptationSensitivity; + _parametersSaveFile << "photoreceptorsTemporalConstant" << photoreceptorsTemporalConstant; + _parametersSaveFile << "photoreceptorsSpatialConstant" << photoreceptorsSpatialConstant; + _parametersSaveFile << "horizontalCellsGain" << horizontalCellsGain; + _parametersSaveFile << "hcellsTemporalConstant" << HcellsTemporalConstant; + _parametersSaveFile << "hcellsSpatialConstant" << HcellsSpatialConstant; + _parametersSaveFile << "ganglionCellsSensitivity" << ganglionCellsSensitivity; + _parametersSaveFile << "}"; +} + +void Retina::setupIPLMagnoChannel(const bool normaliseOutput, const double parasolCells_beta, const double parasolCells_tau, const double parasolCells_k, const double amacrinCellsTemporalCutFrequency, const double V0CompressionParameter, const double localAdaptintegration_tau, const double localAdaptintegration_k) +{ + + _retinaFilter->setMagnoCoefficientsTable(parasolCells_beta, parasolCells_tau, parasolCells_k, amacrinCellsTemporalCutFrequency, V0CompressionParameter, localAdaptintegration_tau, localAdaptintegration_k); + _retinaFilter->activateNormalizeMagnoOutput_0_maxOutputValue(normaliseOutput); + + // save parameters in the xml parameters tree... if parameters file is already open + if (!_parametersSaveFile.isOpened()) + return; + _parametersSaveFile<<"IPLmagno"<<"{"; + _parametersSaveFile << "normaliseOutput" << normaliseOutput; + _parametersSaveFile << "parasolCells_beta" << parasolCells_beta; + _parametersSaveFile << "parasolCells_tau" << parasolCells_tau; + _parametersSaveFile << "parasolCells_k" << parasolCells_k; + _parametersSaveFile << "amacrinCellsTemporalCutFrequency" << amacrinCellsTemporalCutFrequency; + _parametersSaveFile << "V0CompressionParameter" << V0CompressionParameter; + _parametersSaveFile << "localAdaptintegration_tau" << localAdaptintegration_tau; + _parametersSaveFile << "localAdaptintegration_k" << localAdaptintegration_k; + _parametersSaveFile<<"}"; + +} + +void Retina::run(const cv::Mat &inputImage) +{ + + // first check input consistency + if (inputImage.empty()) + throw cv::Exception(-1, "Retina cannot be applied, input buffer is empty", "Retina::run", "Retina.h", 0); + + // retreive color mode from image input + bool colorMode = inputImage.channels() >=3; + + // TODO : ensure input color image is CV_BGR coded + //if (inputImage.flags!=CV_BGR) + // throw cv::Exception(-1, "Retina color input must be BGR coded", "Retina::run", "Retina.h", 0); + + // first convert input image to the compatible format : std::valarray + double *imagePTR=&_inputBuffer[0]; + + if (!colorMode) + { + for (int i=0;i(i); + for (int j=0;jgetInputNBpixels()*2; + for (int i=0;i(pixel); + *(imagePTR) =(double)pixelValue[2]; + *(imagePTR+_retinaFilter->getInputNBpixels()) =(double)pixelValue[1]; + *(imagePTR+doubleNBpixelsPerLayer ) =(double)pixelValue[0]; + } + } + } + + // process the retina + if (!_retinaFilter->runFilter(_inputBuffer, colorMode, false, colorMode, false)) + throw cv::Exception(-1, "Retina cannot be applied, wrong input buffer size", "Retina::run", "Retina.h", 0); +} + +void Retina::getParvo(cv::Mat &retinaOutput_parvo) +{ + if (_retinaFilter->getColorMode()) + { + // reallocate output buffer (if necessary) + _convertValarrayGrayBuffer2cvMat(_retinaFilter->getColorOutput(), _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), true, retinaOutput_parvo); + }else + { + // reallocate output buffer (if necessary) + _convertValarrayGrayBuffer2cvMat(_retinaFilter->getContours(), _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), false, retinaOutput_parvo); + } + //retinaOutput_parvo/=255.0; +} +void Retina::getMagno(cv::Mat &retinaOutput_magno) +{ + // reallocate output buffer (if necessary) + _convertValarrayGrayBuffer2cvMat(_retinaFilter->getMovingContours(), _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), false, retinaOutput_magno); + //retinaOutput_magno/=255.0; +} + +// private method called by constructirs +void Retina::_init(const std::string parametersSaveFile, const cv::Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod, const bool useRetinaLogSampling, const double reductionFactor, const double samplingStrenght) +{ + _parametersSaveFileName = parametersSaveFile; + + // basic error check + if (inputSize.height*inputSize.width <= 0) + throw cv::Exception(-1, "Bad retina size setup : size height and with must be superior to zero", "Retina::setup", "Retina.h", 0); + + unsigned int nbPixels=inputSize.height*inputSize.width; + // resize buffers if size does not match + _inputBuffer.resize(nbPixels*3); // buffer supports gray images but also 3 channels color buffers... (larger is better...) + + // allocate the retina model + delete _retinaFilter; + _retinaFilter = new RetinaFilter(inputSize.height, inputSize.width, colorMode, colorSamplingMethod, useRetinaLogSampling, reductionFactor, samplingStrenght); + + // prepare the parameter XML tree + _parametersSaveFile.open(parametersSaveFile, cv::FileStorage::WRITE ); + + _parametersSaveFile<<"InputSize"<<"{"; + _parametersSaveFile<<"height"<clearAllBuffers(); + + // report current configuration + std::cout< &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, cv::Mat &outBuffer) +{ + // fill output buffer with the valarray buffer + const double *valarrayPTR=get_data(grayMatrixToConvert); + if (!colorMode) + { + outBuffer.create(cv::Size(nbColumns, nbRows), CV_8U); + for (unsigned int i=0;i(pixel)=(unsigned char)*(valarrayPTR++); + } + } + }else + { + const unsigned int doubleNBpixels=_retinaFilter->getOutputNBpixels()*2; + outBuffer.create(cv::Size(nbColumns, nbRows), CV_8UC3); + for (unsigned int i=0;igetOutputNBpixels()); + pixelValues[0]=(unsigned char)*(valarrayPTR+doubleNBpixels); + + outBuffer.at(pixel)=pixelValues; + } + } + } +} + +void Retina::clearBuffers() {_retinaFilter->clearAllBuffers();} + +} // end of namespace cv diff --git a/modules/contrib/src/retinacolor.cpp b/modules/contrib/src/retinacolor.cpp new file mode 100644 index 0000000000..403dab4774 --- /dev/null +++ b/modules/contrib/src/retinacolor.cpp @@ -0,0 +1,744 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#include "precomp.hpp" + +#include "retinacolor.hpp" + +// @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ + +#include +#include + +namespace cv +{ + +// init static values +static double _LMStoACr1Cr2[]={1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -0.5, -0.5, 1.0}; +//static double _ACr1Cr2toLMS[]={0.5, 0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.0, 1.0}; +static double _LMStoLab[]={0.5774, 0.5774, 0.5774, 0.4082, 0.4082, -0.8165, 0.7071, -0.7071, 0.0}; + +// constructor/desctructor +RetinaColor::RetinaColor(const unsigned int NBrows, const unsigned int NBcolumns, const RETINA_COLORSAMPLINGMETHOD samplingMethod) +:BasicRetinaFilter(NBrows, NBcolumns, 3), + _colorSampling(NBrows*NBcolumns), + _RGBmosaic(NBrows*NBcolumns*3), + _tempMultiplexedFrame(NBrows*NBcolumns), + _demultiplexedTempBuffer(NBrows*NBcolumns*3), + _demultiplexedColorFrame(NBrows*NBcolumns*3), + _chrominance(NBrows*NBcolumns*3), + _colorLocalDensity(NBrows*NBcolumns*3), + _imageGradient(NBrows*NBcolumns*3) +{ + // link to parent buffers (let's recycle !) + _luminance=&_filterOutput; + _multiplexedFrame=&_localBuffer; + + _objectInit=false; + _samplingMethod=samplingMethod; + _saturateColors=false; + _colorSaturationValue=4.0; + + // set default spatio-temporal filter parameters + setLPfilterParameters(0.0, 0.0, 1.5); + setLPfilterParameters(0.0, 0.0, 10.5, 1);// for the low pass filter dedicated to contours energy extraction (demultiplexing process) + setLPfilterParameters(0.0, 0.0, 0.9, 2); + + // init default value on image Gradient + _imageGradient=0.57; + + // init color sampling map + _initColorSampling(); + + // flush all buffers + clearAllBuffers(); +} + +RetinaColor::~RetinaColor() +{ + +} + +/** +* function that clears all buffers of the object +*/ +void RetinaColor::clearAllBuffers() +{ + BasicRetinaFilter::clearAllBuffers(); + _tempMultiplexedFrame=0; + _demultiplexedTempBuffer=0; + + _demultiplexedColorFrame=0; + _chrominance=0; + _imageGradient=1; +} + +/** +* resize retina color filter object (resize all allocated buffers) +* @param NBrows: the new height size +* @param NBcolumns: the new width size +*/ +void RetinaColor::resize(const unsigned int NBrows, const unsigned int NBcolumns) +{ + BasicRetinaFilter::clearAllBuffers(); + _colorSampling.resize(NBrows*NBcolumns); + _RGBmosaic.resize(NBrows*NBcolumns*3); + _tempMultiplexedFrame.resize(NBrows*NBcolumns); + _demultiplexedTempBuffer.resize(NBrows*NBcolumns*3); + _demultiplexedColorFrame.resize(NBrows*NBcolumns*3); + _chrominance.resize(NBrows*NBcolumns*3); + _colorLocalDensity.resize(NBrows*NBcolumns*3); + _imageGradient.resize(NBrows*NBcolumns*3); + + // link to parent buffers (let's recycle !) + _luminance=&_filterOutput; + _multiplexedFrame=&_localBuffer; + + // init color sampling map + _initColorSampling(); + + // clean buffers + clearAllBuffers(); +} + + +void RetinaColor::_initColorSampling() +{ + + // filling the conversion table for multiplexed <=> demultiplexed frame + srand(time(NULL)); + + // preInit cones probabilities + _pR=_pB=_pG=0; + switch (_samplingMethod) + { + case RETINA_COLOR_RANDOM: + for (unsigned int index=0 ; indexgetNBpixels(); ++index) + { + + // random RGB sampling + unsigned int colorIndex=rand()%24; + + if (colorIndex<8){ + colorIndex=0; + + ++_pR; + }else + { + if (colorIndex<21){ + colorIndex=1; + ++_pG; + }else{ + colorIndex=2; + ++_pB; + } + } + _colorSampling[index] = colorIndex*this->getNBpixels()+index; + } + _pR/=(double)this->getNBpixels(); + _pG/=(double)this->getNBpixels(); + _pB/=(double)this->getNBpixels(); + std::cout<<"Color channels proportions: pR, pG, pB= "<<_pR<<", "<<_pG<<", "<<_pB<<", "<getNBpixels(); ++index) + { + _colorSampling[index] = index+((index%3+(index%_filterOutput.getNBcolumns()))%3)*_filterOutput.getNBpixels(); + } + _pR=_pB=_pG=1.0/3.0; + break; + case RETINA_COLOR_BAYER: // default sets bayer sampling + for (unsigned int index=0 ; index<_filterOutput.getNBpixels(); ++index) + { + //First line: R G R G + _colorSampling[index] = index+((index/_filterOutput.getNBcolumns())%2)*_filterOutput.getNBpixels()+((index%_filterOutput.getNBcolumns())%2)*_filterOutput.getNBpixels(); + //First line: G R G R + //_colorSampling[index] = 3*index+((index/_filterOutput.getNBcolumns())%2)+((index%_filterOutput.getNBcolumns()+1)%2); + } + _pR=_pB=0.25; + _pG=0.5; + break; + default: +#ifdef RETINACOLORDEBUG + std::cerr<<"RetinaColor::No or wrong color sampling method, skeeping"< &multiplexedColorFrame, const bool adaptiveFiltering, const double maxInputValue) +{ + // demultiplex the grey frame to RGB frame + // -> first set demultiplexed frame to 0 + _demultiplexedTempBuffer=0; + // -> demultiplex process + register unsigned int *colorSamplingPRT=&_colorSampling[0]; + register const double *multiplexedColorFramePTR=get_data(multiplexedColorFrame); + for (unsigned int indexa=0; indexa<_filterOutput.getNBpixels() ; ++indexa) + _demultiplexedTempBuffer[*(colorSamplingPRT++)]=*(multiplexedColorFramePTR++); + + // interpolate the demultiplexed frame depending on the color sampling method + if (!adaptiveFiltering) + _interpolateImageDemultiplexedImage(&_demultiplexedTempBuffer[0]); + + // low pass filtering the demultiplexed frame + _spatiotemporalLPfilter(&_demultiplexedTempBuffer[0], &_chrominance[0]); + _spatiotemporalLPfilter(&_demultiplexedTempBuffer[0]+_filterOutput.getNBpixels(), &_chrominance[0]+_filterOutput.getNBpixels()); + _spatiotemporalLPfilter(&_demultiplexedTempBuffer[0]+_filterOutput.getDoubleNBpixels(), &_chrominance[0]+_filterOutput.getDoubleNBpixels()); + + /*if (_samplingMethod=BAYER) + { + _applyRIFfilter(_chrominance, _chrominance); + _applyRIFfilter(_chrominance+_filterOutput.getNBpixels(), _chrominance+_filterOutput.getNBpixels()); + _applyRIFfilter(_chrominance+_filterOutput.getDoubleNBpixels(), _chrominance+_filterOutput.getDoubleNBpixels()); + }*/ + + // normalize by the photoreceptors local density and retrieve the local luminance + register double *chrominancePTR= &_chrominance[0]; + register double *colorLocalDensityPTR= &_colorLocalDensity[0]; + register double *luminance= &(*_luminance)[0]; + if (!adaptiveFiltering)// compute the gradient on the luminance + { + if (_samplingMethod==RETINA_COLOR_RANDOM) + for (unsigned int indexc=0; indexc<_filterOutput.getNBpixels() ; ++indexc, ++chrominancePTR, ++colorLocalDensityPTR, ++luminance) + { + // normalize by photoreceptors density + double Cr=*(chrominancePTR)*_colorLocalDensity[indexc]; + double Cg=*(chrominancePTR+_filterOutput.getNBpixels())*_colorLocalDensity[indexc+_filterOutput.getNBpixels()]; + double Cb=*(chrominancePTR+_filterOutput.getDoubleNBpixels())*_colorLocalDensity[indexc+_filterOutput.getDoubleNBpixels()]; + *luminance=(Cr+Cg+Cb)*_pG; + *(chrominancePTR)=Cr-*luminance; + *(chrominancePTR+_filterOutput.getNBpixels())=Cg-*luminance; + *(chrominancePTR+_filterOutput.getDoubleNBpixels())=Cb-*luminance; + } + else + for (unsigned int indexc=0; indexc<_filterOutput.getNBpixels() ; ++indexc, ++chrominancePTR, ++colorLocalDensityPTR, ++luminance) + { + double Cr=*(chrominancePTR); + double Cg=*(chrominancePTR+_filterOutput.getNBpixels()); + double Cb=*(chrominancePTR+_filterOutput.getDoubleNBpixels()); + *luminance=_pR*Cr+_pG*Cg+_pB*Cb; + *(chrominancePTR)=Cr-*luminance; + *(chrominancePTR+_filterOutput.getNBpixels())=Cg-*luminance; + *(chrominancePTR+_filterOutput.getDoubleNBpixels())=Cb-*luminance; + } + + // in order to get the color image, each colored map needs to be added the luminance + // -> to do so, compute: multiplexedColorFrame - remultiplexed chrominances + runColorMultiplexing(_chrominance, _tempMultiplexedFrame); + //lum = 1/3((f*(ImR))/(f*mR) + (f*(ImG))/(f*mG) + (f*(ImB))/(f*mB)); + double *luminancePTR= &(*_luminance)[0]; + chrominancePTR= &_chrominance[0]; + double *demultiplexedColorFramePTR= &_demultiplexedColorFrame[0]; + for (unsigned int indexp=0; indexp<_filterOutput.getNBpixels() ; ++indexp, ++luminancePTR, ++chrominancePTR, ++demultiplexedColorFramePTR) + { + *luminancePTR=(multiplexedColorFrame[indexp]-_tempMultiplexedFrame[indexp]); + *(demultiplexedColorFramePTR)=*(chrominancePTR)+*luminancePTR; + *(demultiplexedColorFramePTR+_filterOutput.getNBpixels())=*(chrominancePTR+_filterOutput.getNBpixels())+*luminancePTR; + *(demultiplexedColorFramePTR+_filterOutput.getDoubleNBpixels())=*(chrominancePTR+_filterOutput.getDoubleNBpixels())+*luminancePTR; + } + + }else + { + register const double *multiplexedColorFramePTR= get_data(multiplexedColorFrame); + for (unsigned int indexc=0; indexc<_filterOutput.getNBpixels() ; ++indexc, ++chrominancePTR, ++colorLocalDensityPTR, ++luminance, ++multiplexedColorFramePTR) + { + // normalize by photoreceptors density + double Cr=*(chrominancePTR)*_colorLocalDensity[indexc]; + double Cg=*(chrominancePTR+_filterOutput.getNBpixels())*_colorLocalDensity[indexc+_filterOutput.getNBpixels()]; + double Cb=*(chrominancePTR+_filterOutput.getDoubleNBpixels())*_colorLocalDensity[indexc+_filterOutput.getDoubleNBpixels()]; + *luminance=(Cr+Cg+Cb)*_pG; + _demultiplexedTempBuffer[_colorSampling[indexc]] = *multiplexedColorFramePTR - *luminance; + + } + + // compute the gradient of the luminance + _computeGradient(&(*_luminance)[0]); + + // adaptively filter the submosaics to get the adaptive densities, here the buffer _chrominance is used as a temp buffer + _adaptiveSpatialLPfilter(&_RGBmosaic[0], &_chrominance[0]); + _adaptiveSpatialLPfilter(&_RGBmosaic[0]+_filterOutput.getNBpixels(), &_chrominance[0]+_filterOutput.getNBpixels()); + _adaptiveSpatialLPfilter(&_RGBmosaic[0]+_filterOutput.getDoubleNBpixels(), &_chrominance[0]+_filterOutput.getDoubleNBpixels()); + + _adaptiveSpatialLPfilter(&_demultiplexedTempBuffer[0], &_demultiplexedColorFrame[0]); + _adaptiveSpatialLPfilter(&_demultiplexedTempBuffer[0]+_filterOutput.getNBpixels(), &_demultiplexedColorFrame[0]+_filterOutput.getNBpixels()); + _adaptiveSpatialLPfilter(&_demultiplexedTempBuffer[0]+_filterOutput.getDoubleNBpixels(), &_demultiplexedColorFrame[0]+_filterOutput.getDoubleNBpixels()); + + for (unsigned int index=0; index<_filterOutput.getNBpixels()*3 ; ++index) // cette boucle pourrait �tre supprimee en passant la densit� � la fonction de filtrage + _demultiplexedColorFrame[index] /= _chrominance[index]; + + // compute and substract the residual luminance + for (unsigned int index=0; index<_filterOutput.getNBpixels() ; ++index) + { + double residu = _pR*_demultiplexedColorFrame[index] + _pG*_demultiplexedColorFrame[index+_filterOutput.getNBpixels()] + _pB*_demultiplexedColorFrame[index+_filterOutput.getDoubleNBpixels()]; + _demultiplexedColorFrame[index] = _demultiplexedColorFrame[index] - residu; + _demultiplexedColorFrame[index+_filterOutput.getNBpixels()] = _demultiplexedColorFrame[index+_filterOutput.getNBpixels()] - residu; + _demultiplexedColorFrame[index+_filterOutput.getDoubleNBpixels()] = _demultiplexedColorFrame[index+_filterOutput.getDoubleNBpixels()] - residu; + } + + // multiplex the obtained chrominance + runColorMultiplexing(_demultiplexedColorFrame, _tempMultiplexedFrame); + _demultiplexedTempBuffer=0; + + // get the luminance, et and add it to each chrominance + for (unsigned int index=0; index<_filterOutput.getNBpixels() ; ++index) + { + (*_luminance)[index]=multiplexedColorFrame[index]-_tempMultiplexedFrame[index]; + _demultiplexedTempBuffer[_colorSampling[index]] = _demultiplexedColorFrame[_colorSampling[index]];//multiplexedColorFrame[index] - (*_luminance)[index]; + } + + _spatiotemporalLPfilter(&_demultiplexedTempBuffer[0], &_demultiplexedTempBuffer[0]); + _spatiotemporalLPfilter(&_demultiplexedTempBuffer[0]+_filterOutput.getNBpixels(), &_demultiplexedTempBuffer[0]+_filterOutput.getNBpixels()); + _spatiotemporalLPfilter(&_demultiplexedTempBuffer[0]+_filterOutput.getDoubleNBpixels(), &_demultiplexedTempBuffer[0]+_filterOutput.getDoubleNBpixels()); + + // get the luminance and add it to each chrominance + for (unsigned int index=0; index<_filterOutput.getNBpixels() ; ++index) + { + _demultiplexedColorFrame[index] = _demultiplexedTempBuffer[index]*_colorLocalDensity[index]+ (*_luminance)[index]; + _demultiplexedColorFrame[index+_filterOutput.getNBpixels()] = _demultiplexedTempBuffer[index+_filterOutput.getNBpixels()]*_colorLocalDensity[index+_filterOutput.getNBpixels()]+ (*_luminance)[index]; + _demultiplexedColorFrame[index+_filterOutput.getDoubleNBpixels()] = _demultiplexedTempBuffer[index+_filterOutput.getDoubleNBpixels()]*_colorLocalDensity[index+_filterOutput.getDoubleNBpixels()]+ (*_luminance)[index]; + } + } + + // eliminate saturated colors by simple clipping values to the input range + clipRGBOutput_0_maxInputValue(NULL, maxInputValue); + + /* transfert image gradient in order to check validity + memcpy((*_luminance), _imageGradient, sizeof(double)*_filterOutput.getNBpixels()); + memcpy(_demultiplexedColorFrame, _imageGradient+_filterOutput.getNBpixels(), sizeof(double)*_filterOutput.getNBpixels()); + memcpy(_demultiplexedColorFrame+_filterOutput.getNBpixels(), _imageGradient+_filterOutput.getNBpixels(), sizeof(double)*_filterOutput.getNBpixels()); + memcpy(_demultiplexedColorFrame+2*_filterOutput.getNBpixels(), _imageGradient+_filterOutput.getNBpixels(), sizeof(double)*_filterOutput.getNBpixels()); + */ + + if (_saturateColors) + { + TemplateBuffer::normalizeGrayOutputCentredSigmoide(128, _colorSaturationValue, maxInputValue, &_demultiplexedColorFrame[0], &_demultiplexedColorFrame[0], _filterOutput.getNBpixels()); + TemplateBuffer::normalizeGrayOutputCentredSigmoide(128, _colorSaturationValue, maxInputValue, &_demultiplexedColorFrame[0]+_filterOutput.getNBpixels(), &_demultiplexedColorFrame[0]+_filterOutput.getNBpixels(), _filterOutput.getNBpixels()); + TemplateBuffer::normalizeGrayOutputCentredSigmoide(128, _colorSaturationValue, maxInputValue, &_demultiplexedColorFrame[0]+_filterOutput.getNBpixels()*2, &_demultiplexedColorFrame[0]+_filterOutput.getNBpixels()*2, _filterOutput.getNBpixels()); + } +} + +// color multiplexing: input frame size=_NBrows*_filterOutput.getNBcolumns()*3, multiplexedFrame output size=_NBrows*_filterOutput.getNBcolumns() +void RetinaColor::runColorMultiplexing(const std::valarray &demultiplexedInputFrame, std::valarray &multiplexedFrame) +{ + // multiply each color layer by its bayer mask + register unsigned int *colorSamplingPTR= &_colorSampling[0]; + register double *multiplexedFramePTR= &multiplexedFrame[0]; + for (unsigned int indexp=0; indexp<_filterOutput.getNBpixels(); ++indexp) + *(multiplexedFramePTR++)=demultiplexedInputFrame[*(colorSamplingPTR++)]; +} + +void RetinaColor::normalizeRGBOutput_0_maxOutputValue(const double maxOutputValue) +{ + //normalizeGrayOutputCentredSigmoide(0.0, 2, _chrominance); + TemplateBuffer::normalizeGrayOutput_0_maxOutputValue(&_demultiplexedColorFrame[0], 3*_filterOutput.getNBpixels(), maxOutputValue); + //normalizeGrayOutputCentredSigmoide(0.0, 2, _chrominance+_filterOutput.getNBpixels()); + //normalizeGrayOutput_0_maxOutputValue(_demultiplexedColorFrame+_filterOutput.getNBpixels(), _filterOutput.getNBpixels(), maxOutputValue); + //normalizeGrayOutputCentredSigmoide(0.0, 2, _chrominance+2*_filterOutput.getNBpixels()); + //normalizeGrayOutput_0_maxOutputValue(_demultiplexedColorFrame+_filterOutput.getDoubleNBpixels(), _filterOutput.getNBpixels(), maxOutputValue); + TemplateBuffer::normalizeGrayOutput_0_maxOutputValue(&(*_luminance)[0], _filterOutput.getNBpixels(), maxOutputValue); +} + +/// normalize output between 0 and maxOutputValue; +void RetinaColor::clipRGBOutput_0_maxInputValue(double *inputOutputBuffer, const double maxInputValue) +{ + //std::cout<<"RetinaColor::normalizing RGB frame..."<maxInputValue) + *inputOutputBufferPTR=maxInputValue; + else if (*inputOutputBufferPTR<0) + *inputOutputBufferPTR=0; + } + //std::cout<<"RetinaColor::...normalizing RGB frame OK"<maxValue) + maxValue=outputFrame[index]; + } + } + normalisationFactor=1.0/maxValue; + // normalisation [0, 1] + for (unsigned int indexp=1 ; indexp<_filterOutput.getNBrows()-1; ++indexp) + outputFrame[indexp]=outputFrame[indexp]*normalisationFactor; +} + +////////////////////////////////////////////////////////// +// ADAPTIVE BASIC RETINA FILTER +////////////////////////////////////////////////////////// +// run LP filter for a new frame input and save result at a specific output adress +void RetinaColor::_adaptiveSpatialLPfilter(const double *inputFrame, double *outputFrame) +{ + + /**********/ + _gain = (1-0.57)*(1-0.57)*(1-0.06)*(1-0.06); + + // launch the serie of 1D directional filters in order to compute the 2D low pass filter + _adaptiveHorizontalCausalFilter_addInput(inputFrame, outputFrame, 0, _filterOutput.getNBrows()); + _adaptiveHorizontalAnticausalFilter(outputFrame, 0, _filterOutput.getNBrows()); + _adaptiveVerticalCausalFilter(outputFrame, 0, _filterOutput.getNBcolumns()); + _adaptiveVerticalAnticausalFilter_multGain(outputFrame, 0, _filterOutput.getNBcolumns()); + +} + +// horizontal causal filter which adds the input inside +void RetinaColor::_adaptiveHorizontalCausalFilter_addInput(const double *inputFrame, double *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd) +{ + register double* outputPTR=outputFrame+IDrowStart*_filterOutput.getNBcolumns(); + register const double* inputPTR=inputFrame+IDrowStart*_filterOutput.getNBcolumns(); + register double *imageGradientPTR= &_imageGradient[0]+IDrowStart*_filterOutput.getNBcolumns(); + for (unsigned int IDrow=IDrowStart; IDrow &result) +{ + bool processSuccess=true; + // basic preliminary error check + if (result.size()!=_demultiplexedColorFrame.size()) + { + std::cerr<<"RetinaColor::applyKrauskopfLMS2Acr1cr2Transform: input buffer does not match retina buffer size, conversion aborted"< &result) +{ + bool processSuccess=true; + // basic preliminary error check + if (result.size()!=_demultiplexedColorFrame.size()) + { + std::cerr<<"RetinaColor::applyKrauskopfLMS2Acr1cr2Transform: input buffer does not match retina buffer size, conversion aborted"< &inputFrameBuffer, std::valarray &outputFrameBuffer, const double *transformTable) +{ + // two step methods in order to allow inputFrame and outputFrame to be the same + unsigned int nbPixels=(unsigned int)(inputFrameBuffer.size()/3), dbpixels=(unsigned int)(2*inputFrameBuffer.size()/3); + + const double *inputFrame=get_data(inputFrameBuffer); + double *outputFrame= &outputFrameBuffer[0]; + + for (unsigned int dataIndex=0; dataIndex B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +/** +* @class RetinaColor a color multilexing/demultiplexing (demosaicing) based on a human vision inspiration. Different mosaicing strategies can be used, included random sampling ! +* => please take a look at the nice and efficient demosaicing strategy introduced by B.Chaix de Lavarene, take a look at the cited paper for more mathematical details +* @brief Retina color sampling model which allows classical bayer sampling, random and potentially several other method ! Low color errors on corners ! +* -> Based on the research of: +* .Brice Chaix Lavarene (chaix@lis.inpg.fr) +* .Jeanny Herault (herault@lis.inpg.fr) +* .David Alleyson (david.alleyson@upmf-grenoble.fr) +* .collaboration: alexandre benoit (benoit.alexandre.vision@gmail.com or benoit@lis.inpg.fr) +* Please cite: B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +* @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC / Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ +* Creation date 2007 +*/ + +#ifndef RETINACOLOR_HPP_ +#define RETINACOLOR_HPP_ + +#include "basicretinafilter.hpp" + +//#define __RETINACOLORDEBUG //define RETINACOLORDEBUG in order to display debug data + +namespace cv +{ + +class RetinaColor: public BasicRetinaFilter +{ +public: + /** + * @typedef which allows to select the type of photoreceptors color sampling + */ + + /** + * constructor of the retina color processing model + * @param NBrows: number of rows of the input image + * @param NBcolumns: number of columns of the input image + * @param samplingMethod: the chosen color sampling method + */ + RetinaColor(const unsigned int NBrows, const unsigned int NBcolumns, const RETINA_COLORSAMPLINGMETHOD samplingMethod=RETINA_COLOR_DIAGONAL); + + /** + * standard destructor + */ + virtual ~RetinaColor(); + + /** + * function that clears all buffers of the object + */ + void clearAllBuffers(); + + /** + * resize retina color filter object (resize all allocated buffers) + * @param NBrows: the new height size + * @param NBcolumns: the new width size + */ + void resize(const unsigned int NBrows, const unsigned int NBcolumns); + + + /** + * color multiplexing function: a demultiplexed RGB frame of size M*N*3 is transformed into a multiplexed M*N*1 pixels frame where each pixel is either Red, or Green or Blue + * @param inputRGBFrame: the input RGB frame to be processed + * @return, nothing but the multiplexed frame is available by the use of the getMultiplexedFrame() function + */ + inline void runColorMultiplexing(const std::valarray &inputRGBFrame){runColorMultiplexing(inputRGBFrame, *_multiplexedFrame);}; + + /** + * color multiplexing function: a demultipleed RGB frame of size M*N*3 is transformed into a multiplexed M*N*1 pixels frame where each pixel is either Red, or Green or Blue if using RGB images + * @param demultiplexedInputFrame: the demultiplexed input frame to be processed of size M*N*3 + * @param multiplexedFrame: the resulting multiplexed frame + */ + void runColorMultiplexing(const std::valarray &demultiplexedInputFrame, std::valarray &multiplexedFrame); + + /** + * color demultiplexing function: a multiplexed frame of size M*N*1 pixels is transformed into a RGB demultiplexed M*N*3 pixels frame + * @param multiplexedColorFrame: the input multiplexed frame to be processed + * @param adaptiveFiltering: specifies if an adaptive filtering has to be perform rather than standard filtering (adaptive filtering allows a better rendering) + * @param maxInputValue: the maximum input data value (should be 255 for 8 bits images but it can change in the case of High Dynamic Range Images (HDRI) + * @return, nothing but the output demultiplexed frame is available by the use of the getDemultiplexedColorFrame() function, also use getLuminance() and getChrominance() in order to retreive either luminance or chrominance + */ + void runColorDemultiplexing(const std::valarray &multiplexedColorFrame, const bool adaptiveFiltering=false, const double maxInputValue=255.0); + + /** + * activate color saturation as the final step of the color demultiplexing process + * -> this saturation is a sigmoide function applied to each channel of the demultiplexed image. + * @param saturateColors: boolean that activates color saturation (if true) or desactivate (if false) + * @param colorSaturationValue: the saturation factor + * */ + void setColorSaturation(const bool saturateColors=true, const double colorSaturationValue=4.0){_saturateColors=saturateColors; _colorSaturationValue=colorSaturationValue;}; + + /** + * set parameters of the low pass spatio-temporal filter used to retreive the low chrominance + * @param beta: gain of the filter (generally set to zero) + * @param tau: time constant of the filter (unit is frame for video processing), typically 0 when considering static processing, 1 or more if a temporal smoothing effect is required + * @param k: spatial constant of the filter (unit is pixels), typical value is 2.5 + */ + void setChrominanceLPfilterParameters(const double beta, const double tau, const double k){setLPfilterParameters(beta, tau, k);}; + + /** + * apply to the retina color output the Krauskopf transformation which leads to an opponent color system: output colorspace if Acr1cr2 if input of the retina was LMS color space + * @param result: the input buffer to fill with the transformed colorspace retina output + * @return true if process ended successfully + */ + const bool applyKrauskopfLMS2Acr1cr2Transform(std::valarray &result); + + /** + * apply to the retina color output the CIE Lab color transformation + * @param result: the input buffer to fill with the transformed colorspace retina output + * @return true if process ended successfully + */ + const bool applyLMS2LabTransform(std::valarray &result); + + /** + * @return the multiplexed frame result (use this after function runColorMultiplexing) + */ + inline const std::valarray &getMultiplexedFrame() const {return *_multiplexedFrame;}; + + /** + * @return the demultiplexed frame result (use this after function runColorDemultiplexing) + */ + inline const std::valarray &getDemultiplexedColorFrame() const {return _demultiplexedColorFrame;}; + + /** + * @return the luminance of the processed frame (use this after function runColorDemultiplexing) + */ + inline const std::valarray &getLuminance() const {return *_luminance;}; + + /** + * @return the chrominance of the processed frame (use this after function runColorDemultiplexing) + */ + inline const std::valarray &getChrominance() const {return _chrominance;}; + + /** + * standard 0 to 255 image clipping function appled to RGB images (of size M*N*3 pixels) + * @param inputOutputBuffer: the image to be normalized (rewrites the input), if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param maxOutputValue: the maximum value allowed at the output (values superior to it would be clipped + */ + void clipRGBOutput_0_maxInputValue(double *inputOutputBuffer, const double maxOutputValue=255.0); + + /** + * standard 0 to 255 image normalization function appled to RGB images (of size M*N*3 pixels) + * @param maxOutputValue: the maximum value allowed at the output (values superior to it would be clipped + */ + void normalizeRGBOutput_0_maxOutputValue(const double maxOutputValue=255.0); + + /** + * return the color sampling map: a Nrows*Mcolumns image in which each pixel value is the ofsset adress which gives the adress of the sampled pixel on an Nrows*Mcolumns*3 color image ordered by layers: layer1, layer2, layer3 + */ + inline const std::valarray &getSamplingMap() const {return _colorSampling;}; + + /** + * function used (to bypass processing) to manually set the color output + * @param demultiplexedImage: the color image (luminance+chrominance) which has to be written in the object buffer + */ + inline void setDemultiplexedColorFrame(const std::valarray &demultiplexedImage){_demultiplexedColorFrame=demultiplexedImage;}; + +protected: + + // private functions + RETINA_COLORSAMPLINGMETHOD _samplingMethod; + bool _saturateColors; + double _colorSaturationValue; + // links to parent buffers (more convienient names + TemplateBuffer *_luminance; + std::valarray *_multiplexedFrame; + // instance buffers + std::valarray _colorSampling; // table (size (_nbRows*_nbColumns) which specifies the color of each pixel + std::valarray _RGBmosaic; + std::valarray _tempMultiplexedFrame; + std::valarray _demultiplexedTempBuffer; + std::valarray _demultiplexedColorFrame; + std::valarray _chrominance; + std::valarray _colorLocalDensity;// buffer which contains the local density of the R, G and B photoreceptors for a normalization use + std::valarray _imageGradient; + + // variables + double _pR, _pG, _pB; // probabilities of color R, G and B + bool _objectInit; + + // protected functions + void _initColorSampling(); + void _interpolateImageDemultiplexedImage(double *inputOutputBuffer); + void _interpolateSingleChannelImage111(double *inputOutputBuffer); + void _interpolateBayerRGBchannels(double *inputOutputBuffer); + void _applyRIFfilter(const double *sourceBuffer, double *destinationBuffer); + void _getNormalizedContoursImage(const double *inputFrame, double *outputFrame); + // -> special adaptive filters dedicated to low pass filtering on the chrominance (skeeps filtering on the edges) + void _adaptiveSpatialLPfilter(const double *inputFrame, double *outputFrame); + void _adaptiveHorizontalCausalFilter_addInput(const double *inputFrame, double *outputFrame, const unsigned int IDrowStart, const unsigned int IDrowEnd); + void _adaptiveHorizontalAnticausalFilter(double *outputFrame, const unsigned int IDrowStart, const unsigned int IDrowEnd); + void _adaptiveVerticalCausalFilter(double *outputFrame, const unsigned int IDcolumnStart, const unsigned int IDcolumnEnd); + void _adaptiveVerticalAnticausalFilter_multGain(double *outputFrame, const unsigned int IDcolumnStart, const unsigned int IDcolumnEnd); + void _computeGradient(const double *luminance); + void _normalizeOutputs_0_maxOutputValue(void); + + // color space transform + void _applyImageColorSpaceConversion(const std::valarray &inputFrame, std::valarray &outputFrame, const double *transformTable); + +}; +} + +#endif /*RETINACOLOR_HPP_*/ + + diff --git a/modules/contrib/src/retinafilter.cpp b/modules/contrib/src/retinafilter.cpp new file mode 100644 index 0000000000..672963554d --- /dev/null +++ b/modules/contrib/src/retinafilter.cpp @@ -0,0 +1,531 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#include "precomp.hpp" + +#include "retinafilter.hpp" + +// @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ + +#include +#include + +namespace cv +{ +// standard constructor without any log sampling of the input frame +RetinaFilter::RetinaFilter(const unsigned int sizeRows, const unsigned int sizeColumns, const bool colorMode, const RETINA_COLORSAMPLINGMETHOD samplingMethod, const bool useRetinaLogSampling, const double reductionFactor, const double samplingStrenght) +: + _retinaParvoMagnoMappedFrame(0), + _retinaParvoMagnoMapCoefTable(0), + _photoreceptorsPrefilter((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor), 4), + _ParvoRetinaFilter((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor)), + _MagnoRetinaFilter((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor)), + _colorEngine((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor), samplingMethod), + // configure retina photoreceptors log sampling... if necessary + _photoreceptorsLogSampling(NULL) +{ + +#ifdef RETINADEBUG + std::cout<<"RetinaFilter::size( "<<_photoreceptorsPrefilter.getNBrows()<<", "<<_photoreceptorsPrefilter.getNBcolumns()<<")"<<" =? "<<_photoreceptorsPrefilter.getNBpixels()<initProjection(reductionFactor, samplingStrenght)) + { + std::cerr<<"RetinaFilter::Problem initializing photoreceptors log sampling, could not setup retina filter"<getNBrows()<<", "<<_photoreceptorsLogSampling->getNBcolumns()<<")"<<" =? "<<_photoreceptorsLogSampling->getNBpixels()<getNBrows()<<", "<getNBcolumns()<<")"<<_filterOutput.size()<<" =? "<<_filterOutput.getNBpixels()<clearAllBuffers(); + // stability controls value init + _setInitPeriodCount(); +} + +/** +* resize retina filter object (resize all allocated buffers +* @param NBrows: the new height size +* @param NBcolumns: the new width size +*/ +void RetinaFilter::resize(const unsigned int NBrows, const unsigned int NBcolumns) +{ + unsigned int rows=NBrows, cols=NBcolumns; + + // resize optionnal member and adjust other modules size if required + if (_photoreceptorsLogSampling) + { + _photoreceptorsLogSampling->resize(NBrows, NBcolumns); + rows=_photoreceptorsLogSampling->getOutputNBrows(); + cols=_photoreceptorsLogSampling->getOutputNBcolumns(); + } + + _photoreceptorsPrefilter.resize(rows, cols); + _ParvoRetinaFilter.resize(rows, cols); + _MagnoRetinaFilter.resize(rows, cols); + _colorEngine.resize(rows, cols); + + // reset parvo magno mapping + _createHybridTable(); + + // clean buffers + clearAllBuffers(); + +} + +// stability controls value init +void RetinaFilter::_setInitPeriodCount() +{ + + // find out the maximum temporal constant value and apply a security factor + // false value (obviously too long) but appropriate for simple use + _globalTemporalConstant=(unsigned int)(_ParvoRetinaFilter.getPhotoreceptorsTemporalConstant()+_ParvoRetinaFilter.getHcellsTemporalConstant()+_MagnoRetinaFilter.getTemporalConstant()); + // reset frame counter + _ellapsedFramesSinceLastReset=0; +} + +void RetinaFilter::_createHybridTable() +{ + // create hybrid output and related coefficient table + _retinaParvoMagnoMappedFrame.resize(_photoreceptorsPrefilter.getNBpixels()); + + _retinaParvoMagnoMapCoefTable.resize(_photoreceptorsPrefilter.getNBpixels()*2); + + // fill _hybridParvoMagnoCoefTable + int i, j, halfRows=_photoreceptorsPrefilter.getNBrows()/2, halfColumns=_photoreceptorsPrefilter.getNBcolumns()/2; + double *hybridParvoMagnoCoefTablePTR= &_retinaParvoMagnoMapCoefTable[0]; + double minDistance=MIN(halfRows, halfColumns)*0.7; + for (i=0;i<(int)_photoreceptorsPrefilter.getNBrows();++i) + { + for (j=0;j<(int)_photoreceptorsPrefilter.getNBcolumns();++j) + { + double distanceToCenter=sqrt(((double)(i-halfRows)*(i-halfRows)+(j-halfColumns)*(j-halfColumns))); + if (distanceToCentersetV0CompressionParameter(0.6, maxInputValue, meanValue); // keeps log compression sensitivity parameter (usefull for the tone mapping function) + _ParvoRetinaFilter.setOPLandParvoFiltersParameters(0,OPLtemporalresponse1, OPLspatialResponse1, OPLassymetryGain, OPLtemporalresponse2, OPLspatialResponse2); + _ParvoRetinaFilter.setV0CompressionParameter(0.9, maxInputValue, meanValue); + _MagnoRetinaFilter.setCoefficientsTable(LPfilterGain, LPfilterTemporalresponse, LPfilterSpatialResponse, MovingContoursExtractorCoefficient, 0, 2.0*LPfilterSpatialResponse); + _MagnoRetinaFilter.setV0CompressionParameter(0.7, maxInputValue, meanValue); + + // stability controls value init + _setInitPeriodCount(); +} + +const bool RetinaFilter::checkInput(const std::valarray &input, const bool) +{ + + BasicRetinaFilter *inputTarget=&_photoreceptorsPrefilter; + if (_photoreceptorsLogSampling) + inputTarget=_photoreceptorsLogSampling; + + bool test=input.size()==inputTarget->getNBpixels() || input.size()==(inputTarget->getNBpixels()*3) ; + if (!test) + { + std::cerr<<"RetinaFilter::checkInput: input buffer does not match retina buffer size, conversion aborted"< &bufferInput=checkInput(LMSimageInput, true); + if (!bufferInput) + return NULL; + + if (!_useColorMode) + std::cerr<<"RetinaFilter::Can not call tone mapping oeration if the retina filter was created for gray scale images"< lmsTempBuffer(LMSimageInput); + std::cout<<"RetinaFilter::--->min LMS value="<L + _spatiotemporalLPfilter(LMSimageInput, _filterOutput, 1); + setV0CompressionParameterToneMapping(PhotoreceptorsCompression, _maxInputValue, this->sum()/_NBpixels); + _localLuminanceAdaptation(LMSimageInput, _filterOutput, lmsTempBuffer.Buffer()); + // ->M + _spatiotemporalLPfilter(LMSimageInput+_NBpixels, _filterOutput, 1); + setV0CompressionParameterToneMapping(PhotoreceptorsCompression, _maxInputValue, this->sum()/_NBpixels); + _localLuminanceAdaptation(LMSimageInput+_NBpixels, _filterOutput, lmsTempBuffer.Buffer()+_NBpixels); + // ->S + _spatiotemporalLPfilter(LMSimageInput+_NBpixels*2, _filterOutput, 1); + setV0CompressionParameterToneMapping(PhotoreceptorsCompression, _maxInputValue, this->sum()/_NBpixels); + _localLuminanceAdaptation(LMSimageInput+_NBpixels*2, _filterOutput, lmsTempBuffer.Buffer()+_NBpixels*2); + + // eliminate negative values + for (unsigned int i=0;imin LMS value="< acr1cr2TempBuffer(_NBrows, _NBcolumns, 3); + memcpy(acr1cr2TempBuffer.Buffer(), lmsTempBuffer.Buffer(), sizeof(double)*_NBpixels*3); + + // compute A Cr1 Cr2 to LMS color space conversion + _applyImageColorSpaceConversion(acr1cr2TempBuffer.Buffer(), lmsTempBuffer.Buffer(), _ACr1Cr2toLMS); + + // eliminate negative values + for (unsigned int i=0;isetDemultiplexedColorFrame(lmsTempBuffer.Buffer()); + */ +} + +// return image with center Parvo and peripheral Magno channels +void RetinaFilter::_processRetinaParvoMagnoMapping() +{ + register double *hybridParvoMagnoPTR= &_retinaParvoMagnoMappedFrame[0]; + register const double *parvoOutputPTR= get_data(_ParvoRetinaFilter.getOutput()); + register const double *magnoXOutputPTR= get_data(_MagnoRetinaFilter.getOutput()); + register double *hybridParvoMagnoCoefTablePTR= &_retinaParvoMagnoMapCoefTable[0]; + + for (unsigned int i=0 ; i<_photoreceptorsPrefilter.getNBpixels() ; ++i, hybridParvoMagnoCoefTablePTR+=2) + { + double hybridValue=*(parvoOutputPTR++)**(hybridParvoMagnoCoefTablePTR)+*(magnoXOutputPTR++)**(hybridParvoMagnoCoefTablePTR+1); + *(hybridParvoMagnoPTR++)=hybridValue; + } + + TemplateBuffer::normalizeGrayOutput_0_maxOutputValue(&_retinaParvoMagnoMappedFrame[0], _photoreceptorsPrefilter.getNBpixels()); + +} + +const bool RetinaFilter::getParvoFoveaResponse(std::valarray &parvoFovealResponse) +{ + if (!_useParvoOutput) + return false; + if (parvoFovealResponse.size() != _ParvoRetinaFilter.getNBpixels()) + return false; + + register const double *parvoOutputPTR= get_data(_ParvoRetinaFilter.getOutput()); + register double *fovealParvoResponsePTR= &parvoFovealResponse[0]; + register double *hybridParvoMagnoCoefTablePTR= &_retinaParvoMagnoMapCoefTable[0]; + + for (unsigned int i=0 ; i<_photoreceptorsPrefilter.getNBpixels() ; ++i, hybridParvoMagnoCoefTablePTR+=2) + { + *(fovealParvoResponsePTR++)=*(parvoOutputPTR++)**(hybridParvoMagnoCoefTablePTR); + } + + return true; +} + +// method to retrieve the parafoveal magnocellular pathway response (no energy motion in fovea) +const bool RetinaFilter::getMagnoParaFoveaResponse(std::valarray &magnoParafovealResponse) +{ + if (!_useMagnoOutput) + return false; + if (magnoParafovealResponse.size() != _MagnoRetinaFilter.getNBpixels()) + return false; + + register const double *magnoXOutputPTR= get_data(_MagnoRetinaFilter.getOutput()); + register double *parafovealMagnoResponsePTR=&magnoParafovealResponse[0]; + register double *hybridParvoMagnoCoefTablePTR=&_retinaParvoMagnoMapCoefTable[0]+1; + + for (unsigned int i=0 ; i<_photoreceptorsPrefilter.getNBpixels() ; ++i, hybridParvoMagnoCoefTablePTR+=2) + { + *(parafovealMagnoResponsePTR++)=*(magnoXOutputPTR++)**(hybridParvoMagnoCoefTablePTR); + } + + return true; +} + + +} diff --git a/modules/contrib/src/retinafilter.hpp b/modules/contrib/src/retinafilter.hpp new file mode 100644 index 0000000000..d378870d90 --- /dev/null +++ b/modules/contrib/src/retinafilter.hpp @@ -0,0 +1,540 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +/** +* @class RetinaFilter +* @brief class which describes the retina model developped at the LIS/GIPSA-LAB www.gipsa-lab.inpg.fr: +* -> performs a contours and moving contours extraction with powerfull local data enhancement as at the retina level +* Based on Alexandre BENOIT thesis: "Le systeme visuel humain au secours de la vision par ordinateur" +* +* => various optimisations and enhancements added after 2007 such as tone mapping capabilities, see reference paper cited in the licence and : +* Benoit A.,Alleysson D., Herault J., Le Callet P. (2009), "Spatio-Temporal Tone Mapping Operator based on a Retina model", Computational Color Imaging Workshop (CCIW09),pp 12-22, Saint Etienne, France +* +* TYPICAL USE: +* +* // create object at a specified picture size +* Retina *retina; +* retina =new Retina(frameSizeRows, frameSizeColumns, RGBmode); +* +* // init gain, spatial and temporal parameters: +* retina->setParameters(0.7, 1, 0, 7, 1, 5, 0, 0, 3 , true); +* +* // during program execution, call the filter for local luminance correction, contours extraction, moving contours extraction from an input picture called "FrameBuffer": +* retina->runfilter(FrameBuffer); +* +* // get the different output frames, check in the class description below for more outputs: +* const std::valarray correctedLuminance=retina->getLocalAdaptation(); +* const std::valarray contours=retina->getContours(); +* const std::valarray movingContours=retina->getMovingContours(); +* +* // at the end of the program, destroy object: +* delete retina; +* +* @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC / Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ +* Creation date 2007 +*/ + +#ifndef RETINACLASSES_H_ +#define RETINACLASSES_H_ + +#include "basicretinafilter.hpp" +#include "parvoretinafilter.hpp" +#include "magnoretinafilter.hpp" + +// optional includes (depending on the related publications) +#include "imagelogpolprojection.hpp" + +#include "retinacolor.hpp" + +//#define __RETINADEBUG // define RETINADEBUG to display debug data +namespace cv +{ + +// retina class that process the 3 outputs of the retina filtering stages +class RetinaFilter//: public BasicRetinaFilter +{ +public: + + /** + * constructor of the retina filter model with log sampling of the input frame (models the photoreceptors log sampling (central high resolution fovea and lower precision borders)) + * @param sizeRows: number of rows of the input image + * @param sizeColumns: number of columns of the input image + * @param colorMode: specifies if the retina works with color (true) of stays in grayscale processing (false), can be adjusted online by the use of setColorMode method + * @param samplingMethod: specifies which kind of color sampling will be used + * @param useRetinaLogSampling: activate retina log sampling, if true, the 2 following parameters can be used + * @param reductionFactor: only usefull if param useRetinaLogSampling=true, specifies the reduction factor of the output frame (as the center (fovea) is high resolution and corners can be underscaled, then a reduction of the output is allowed without precision leak + * @param samplingStrenght: only usefull if param useRetinaLogSampling=true, specifies the strenght of the log scale that is applied + */ + RetinaFilter(const unsigned int sizeRows, const unsigned int sizeColumns, const bool colorMode=false, const RETINA_COLORSAMPLINGMETHOD samplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); + + /** + * standard destructor + */ + ~RetinaFilter(); + + /** + * function that clears all buffers of the object + */ + void clearAllBuffers(); + + /** + * resize retina parvo filter object (resize all allocated buffers) + * @param NBrows: the new height size + * @param NBcolumns: the new width size + */ + void resize(const unsigned int NBrows, const unsigned int NBcolumns); + + /** + * Input buffer checker: allows to check if the passed image buffer corresponds to retina filter expectations + * @param input: the input image buffer + * @param colorMode: specifiy if the input should be considered by the retina as colored of not + * @return false if not compatible or it returns true if OK + */ + const bool checkInput(const std::valarray &input, const bool colorMode); + + /** + * run the initilized retina filter, after this call all retina outputs are updated + * @param imageInput: image input buffer, can be grayscale or RGB image respecting the size specified at the constructor level + * @param useAdaptiveFiltering: set true if you want to use adaptive color demultilexing (solve some color artefact problems), see RetinaColor for citation references + * @param processRetinaParvoMagnoMapping: tels if the main outputs takes into account the mapping of the Parvo and Magno channels on the retina (centred parvo (fovea) and magno outside (parafovea)) + * @param useColorMode: color information is used if true, warning, if input is only gray level, a buffer overflow error will occur + -> note that if color mode is activated and processRetinaParvoMagnoMapping==true, then the demultiplexed color frame (accessible throw getColorOutput() will be a color contours frame in the fovea and gray level moving contours outside + @param inputIsColorMultiplexed: set trus if the input data is a multiplexed color image (using Bayer sampling for example), the color sampling method must correspond to the RETINA_COLORSAMPLINGMETHOD passed at constructor! + * @return true if process ran well, false in case of failure + */ + const bool runFilter(const std::valarray &imageInput, const bool useAdaptiveFiltering=true, const bool processRetinaParvoMagnoMapping=false, const bool useColorMode=false, const bool inputIsColorMultiplexed=false); + + /** + * run the initilized retina filter in order to perform color tone mapping applied on an RGB image, after this call the color output of the retina is updated (use function getColorOutput() to grab it) + * the algorithm is based on David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + * -> Meylan L., Alleysson D., and S�sstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N� 9, September, 1st, 2007, pp. 2807-2816 + * get the resulting gray frame by calling function getParvoColor() + * @param grayImageInput: RGB image input buffer respecting the size specified at the constructor level + * @param PhotoreceptorsCompression: sets the log compression parameters applied at the photoreceptors level (enhance luminance in dark areas) + * @param ganglionCellsCompression: sets the log compression applied at the gnaglion cells output (enhance contrast) + */ + void runGrayToneMapping(const std::valarray &grayImageInput, std::valarray &grayImageOutput, const double PhotoreceptorsCompression=0.6, const double ganglionCellsCompression=0.6); + + /** + * run the initilized retina filter in order to perform color tone mapping applied on an RGB image, after this call the color output of the retina is updated (use function getColorOutput() to grab it) + * the algorithm is based on David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + * -> Meylan L., Alleysson D., and S�sstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N� 9, September, 1st, 2007, pp. 2807-2816 + * get the resulting RGB frame by calling function getParvoColor() + * @param RGBimageInput: RGB image input buffer respecting the size specified at the constructor level + * @param useAdaptiveFiltering: set true if you want to use adaptive color demultilexing (solve some color artefact problems), see RetinaColor for citation references + * @param PhotoreceptorsCompression: sets the log compression parameters applied at the photoreceptors level (enhance luminance in dark areas) + * @param ganglionCellsCompression: sets the log compression applied at the ganglion cells output (enhance contrast) + */ + void runRGBToneMapping(const std::valarray &RGBimageInput, std::valarray &imageOutput, const bool useAdaptiveFiltering, const double PhotoreceptorsCompression=0.6, const double ganglionCellsCompression=0.6); + + /** + * run the initilized retina filter in order to perform color tone mapping applied on an RGB image, after this call the color output of the retina is updated (use function getColorOutput() to grab it) + * get the resulting RGB frame by calling function getParvoColor() + * @param LMSimageInput: RGB image input buffer respecting the size specified at the constructor level + * @param useAdaptiveFiltering: set true if you want to use adaptive color demultilexing (solve some color artefact problems), see RetinaColor for citation references + * @param PhotoreceptorsCompression: sets the log compression parameters applied at the photoreceptors level (enhance luminance in dark areas) + * @param ganglionCellsCompression: sets the log compression applied at the gnaglion cells output (enhance contrast) + */ + void runLMSToneMapping(const std::valarray &LMSimageInput, std::valarray &imageOutput, const bool useAdaptiveFiltering, const double PhotoreceptorsCompression=0.6, const double ganglionCellsCompression=0.6); + + /** + * set up function of the retina filter: all the retina is initialized at this step, some specific parameters are set by default, use setOPLandParvoCoefficientsTable() and setMagnoCoefficientsTable in order to setup the retina with more options + * @param OPLspatialResponse1: (equal to k1 in setOPLandParvoCoefficientsTable() function) the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel + * @param OPLtemporalresponse1: (equal to tau1 in setOPLandParvoCoefficientsTable() function) the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame + * @param OPLassymetryGain: (equal to beta2 in setOPLandParvoCoefficientsTable() function) gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 + * @param OPLspatialResponse2: (equal to k2 in setOPLandParvoCoefficientsTable() function) the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel + * @param OPLtemporalresponse2: (equal to tau2 in setOPLandParvoCoefficientsTable() function) the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors + * @param LPfilterSpatialResponse: (equal to parasolCells_k in setMagnoCoefficientsTable() function) the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 + * @param LPfilterGain: (equal to parasolCells_beta in setMagnoCoefficientsTable() function) the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 + * @param LPfilterTemporalresponse: (equal to parasolCells_tau in setMagnoCoefficientsTable() function) the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) + * @param MovingContoursExtractorCoefficient: (equal to amacrinCellsTemporalCutFrequency in setMagnoCoefficientsTable() function)the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, tipicall value is 5 + * @param normalizeParvoOutput_0_maxOutputValue: specifies if the Parvo cellular output should be normalized between 0 and maxOutputValue (true) or not (false) in order to remain at a null mean value, true value is recommended for visualisation + * @param normalizeMagnoOutput_0_maxOutputValue: specifies if the Magno cellular output should be normalized between 0 and maxOutputValue (true) or not (false), setting true may be hazardous because it can enhace the noise response when nothing is moving + * @param maxOutputValue: the maximum amplitude value of the normalized outputs (generally 255 for 8bit per channel pictures) + * @param maxInputValue: the maximum pixel value of the input picture (generally 255 for 8bit per channel pictures), specify it in other case (for example High Dynamic Range Images) + * @param meanValue: the global mean value of the input data usefull for local adaptation setup + */ + void setGlobalParameters(const double OPLspatialResponse1=0.7, const double OPLtemporalresponse1=1, const double OPLassymetryGain=0, const double OPLspatialResponse2=5, const double OPLtemporalresponse2=1, const double LPfilterSpatialResponse=5, const double LPfilterGain=0, const double LPfilterTemporalresponse=0, const double MovingContoursExtractorCoefficient=5, const bool normalizeParvoOutput_0_maxOutputValue=false, const bool normalizeMagnoOutput_0_maxOutputValue=false, const double maxOutputValue=255.0, const double maxInputValue=255.0, const double meanValue=128.0); + + /** + * setup the local luminance adaptation capability + * @param V0CompressionParameter: the compression strengh of the photoreceptors local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 160 + */ + inline void setPhotoreceptorsLocalAdaptationSensitivity(const double V0CompressionParameter){_photoreceptorsPrefilter.setV0CompressionParameter(V0CompressionParameter);_setInitPeriodCount();}; + + /** + * setup the local luminance adaptation capability + * @param V0CompressionParameter: the compression strengh of the parvocellular pathway (details) local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 160 + */ + inline void setParvoGanglionCellsLocalAdaptationSensitivity(const double V0CompressionParameter){_ParvoRetinaFilter.setV0CompressionParameter(V0CompressionParameter);_setInitPeriodCount();}; + + /** + * setup the local luminance adaptation area of integration + * @param spatialResponse: the spatial constant of the low pass filter applied on the bipolar cells output in order to compute local contrast mean values + * @param temporalResponse: the spatial constant of the low pass filter applied on the bipolar cells output in order to compute local contrast mean values (generally set to zero: immediate response) + */ + inline void setGanglionCellsLocalAdaptationLPfilterParameters(const double spatialResponse, const double temporalResponse){_ParvoRetinaFilter.setGanglionCellsLocalAdaptationLPfilterParameters(temporalResponse, spatialResponse);_setInitPeriodCount();}; + + /** + * setup the local luminance adaptation capability + * @param V0CompressionParameter: the compression strengh of the magnocellular pathway (motion) local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 160 + */ + inline void setMagnoGanglionCellsLocalAdaptationSensitivity(const double V0CompressionParameter){_MagnoRetinaFilter.setV0CompressionParameter(V0CompressionParameter);_setInitPeriodCount();}; + + /** + * setup the OPL and IPL parvo channels + * @param beta1: gain of the horizontal cells network, if 0, then the mean value of the output is zero (default value), if the parameter is near 1, the amplitude is boosted but it should only be used for values rescaling... if needed + * @param tau1: the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame + * @param k1: the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel + * @param beta2: gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 + * @param tau2: the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors + * @param k2: the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) + * @param V0CompressionParameter: the compression strengh of the ganglion cells local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 230 + */ + void setOPLandParvoParameters(const double beta1, const double tau1, const double k1, const double beta2, const double tau2, const double k2, const double V0CompressionParameter){_ParvoRetinaFilter.setOPLandParvoFiltersParameters(beta1, tau1, k1, beta2, tau2, k2);_ParvoRetinaFilter.setV0CompressionParameter(V0CompressionParameter);_setInitPeriodCount();}; + + /** + * set parameters values for the Inner Plexiform Layer (IPL) magnocellular channel + * @param parasolCells_beta: the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 + * @param parasolCells_tau: the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) + * @param parasolCells_k: the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 + * @param amacrinCellsTemporalCutFrequency: the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, tipicall value is 5 + * @param V0CompressionParameter: the compression strengh of the ganglion cells local adaptation output, set a value between 160 and 250 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 200 + * @param localAdaptintegration_tau: specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + * @param localAdaptintegration_k: specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + */ + void setMagnoCoefficientsTable(const double parasolCells_beta, const double parasolCells_tau, const double parasolCells_k, const double amacrinCellsTemporalCutFrequency, const double V0CompressionParameter, const double localAdaptintegration_tau, const double localAdaptintegration_k){_MagnoRetinaFilter.setCoefficientsTable(parasolCells_beta, parasolCells_tau, parasolCells_k, amacrinCellsTemporalCutFrequency, localAdaptintegration_tau, localAdaptintegration_k);_MagnoRetinaFilter.setV0CompressionParameter(V0CompressionParameter);_setInitPeriodCount();}; + + /** + * set if the parvo output should be or not normalized between 0 and 255 (for display purpose generally) + * @param normalizeParvoOutput_0_maxOutputValue: true if normalization should be done + */ + inline void activateNormalizeParvoOutput_0_maxOutputValue(const bool normalizeParvoOutput_0_maxOutputValue){_normalizeParvoOutput_0_maxOutputValue=normalizeParvoOutput_0_maxOutputValue;}; + + /** + * set if the magno output should be or not normalized between 0 and 255 (for display purpose generally), take care, if nothing is moving, then, the noise will be enanced !!! + * @param normalizeMagnoOutput_0_maxOutputValue: true if normalization should be done + */ + inline void activateNormalizeMagnoOutput_0_maxOutputValue(const bool normalizeMagnoOutput_0_maxOutputValue){_normalizeMagnoOutput_0_maxOutputValue=normalizeMagnoOutput_0_maxOutputValue;}; + + /** + * setup the maximum amplitude value of the normalized outputs (generally 255 for 8bit per channel pictures) + * @param maxOutputValue: maximum amplitude value of the normalized outputs (generally 255 for 8bit per channel pictures) + */ + inline void setMaxOutputValue(const double maxOutputValue){_maxOutputValue=maxOutputValue;}; + + /** + * sets the color mode of the frame grabber + * @param desiredColorMode: true if the user needs color information, false for graylevels + */ + void setColorMode(const bool desiredColorMode){_useColorMode=desiredColorMode;}; + + /** + * activate color saturation as the final step of the color demultiplexing process + * -> this saturation is a sigmoide function applied to each channel of the demultiplexed image. + * @param saturateColors: boolean that activates color saturation (if true) or desactivate (if false) + * @param colorSaturationValue: the saturation factor + * */ + inline void setColorSaturation(const bool saturateColors=true, const double colorSaturationValue=4.0){_colorEngine.setColorSaturation(saturateColors, colorSaturationValue);}; + + ///////////////////////////////////////////////////////////////// + // function that retrieve the main retina outputs, one by one, or all in a structure + + /** + * @return the input image sampled by the photoreceptors spatial sampling + */ + inline const std::valarray &getPhotoreceptorsSampledFrame() const {if (_photoreceptorsLogSampling)return _photoreceptorsLogSampling->getSampledFrame();}; + + /** + * @return photoreceptors output, locally adapted luminance only, no high frequency spatio-temporal noise reduction at the next retina processing stages, use getPhotoreceptors method to get complete photoreceptors output + */ + inline const std::valarray &getLocalAdaptation() const {return _photoreceptorsPrefilter.getOutput();}; + + /** + * @return photoreceptors output: locally adapted luminance and high frequency spatio-temporal noise reduction, high luminance is a little saturated at this stage, but this is corrected naturally at the next retina processing stages + */ + inline const std::valarray &getPhotoreceptors() const {return _ParvoRetinaFilter.getPhotoreceptorsLPfilteringOutput();}; + + /** + * @return the local luminance of the processed frame (it is the horizontal cells output) + */ + inline const std::valarray &getHorizontalCells() const {return _ParvoRetinaFilter.getHorizontalCellsOutput();}; + + ///////// CONTOURS part, PARVOCELLULAR RETINA PATHWAY + /** + * @return true if Parvocellular output is activated, false if not + */ + inline const bool areContoursProcessed(){return _useParvoOutput;}; + + /** + * method to retrieve the foveal parvocellular pathway response (no details energy in parafovea) + * @param parvoParafovealResponse: buffer that will be filled with the response of the magnocellular pathway in the parafoveal area + * @return true if process succeeded (if buffer exists, is its size matches retina size, if magno channel is activated and if mapping is initialized + */ + const bool getParvoFoveaResponse(std::valarray &parvoFovealResponse); + + /** + * @param useParvoOutput: true if Parvocellular output should be activated, false if not + */ + inline void activateContoursProcessing(const bool useParvoOutput){_useParvoOutput=useParvoOutput;}; + + /** + * @return the parvocellular contours information (details), should be used at the fovea level + */ + const std::valarray &getContours(); // Parvocellular output + + /** + * @return the parvocellular contours ON information (details), should be used at the fovea level + */ + inline const std::valarray &getContoursON() const {return _ParvoRetinaFilter.getParvoON();};// Parvocellular ON output + + /** + * @return the parvocellular contours OFF information (details), should be used at the fovea level + */ + inline const std::valarray &getContoursOFF() const {return _ParvoRetinaFilter.getParvoOFF();};// Parvocellular OFF output + + ///////// MOVING CONTOURS part, MAGNOCELLULAR RETINA PATHWAY + /** + * @return true if Magnocellular output is activated, false if not + */ + inline const bool areMovingContoursProcessed(){return _useMagnoOutput;}; + + /** + * method to retrieve the parafoveal magnocellular pathway response (no motion energy in fovea) + * @param magnoParafovealResponse: buffer that will be filled with the response of the magnocellular pathway in the parafoveal area + * @return true if process succeeded (if buffer exists, is its size matches retina size, if magno channel is activated and if mapping is initialized + */ + const bool getMagnoParaFoveaResponse(std::valarray &magnoParafovealResponse); + + /** + * @param useMagnoOutput: true if Magnoocellular output should be activated, false if not + */ + inline void activateMovingContoursProcessing(const bool useMagnoOutput){_useMagnoOutput=useMagnoOutput;}; + + /** + * @return the magnocellular moving contours information (motion), should be used at the parafovea level without post-processing + */ + inline const std::valarray &getMovingContours() const {return _MagnoRetinaFilter.getOutput();};// Magnocellular output + + /** + * @return the magnocellular moving contours information (motion), should be used at the parafovea level with assymetric sigmoide post-processing which saturates motion information + */ + inline const std::valarray &getMovingContoursSaturated() const {return _MagnoRetinaFilter.getMagnoYsaturated();};// Saturated Magnocellular output + + /** + * @return the magnocellular moving contours ON information (motion), should be used at the parafovea level without post-processing + */ + inline const std::valarray &getMovingContoursON() const {return _MagnoRetinaFilter.getMagnoON();};// Magnocellular ON output + + /** + * @return the magnocellular moving contours OFF information (motion), should be used at the parafovea level without post-processing + */ + inline const std::valarray &getMovingContoursOFF() const {return _MagnoRetinaFilter.getMagnoOFF();};// Magnocellular OFF output + + /** + * @return a gray level image with center Parvo and peripheral Magno X channels, WARNING, the result will be ok if you called previously fucntion runFilter(imageInput, processRetinaParvoMagnoMapping=true); + * -> will be accessible even if color mode is activated (but the image is color sampled so quality is poor), but get the same thing but in color by the use of function getParvoColor() + */ + inline const std::valarray &getRetinaParvoMagnoMappedOutput() const {return _retinaParvoMagnoMappedFrame;};// return image with center Parvo and peripheral Magno channels + + /** + * color processing dedicated functions + * @return the parvo channel (contours, details) of the processed frame, grayscale output + */ + inline const std::valarray &getParvoContoursChannel() const {return _colorEngine.getLuminance();}; + + /** + * color processing dedicated functions + * @return the chrominance of the processed frame (same colorspace as the input output, usually RGB) + */ + inline const std::valarray &getParvoChrominance() const {return _colorEngine.getChrominance();}; // only retreive chrominance + + /** + * color processing dedicated functions + * @return the parvo + chrominance channels of the processed frame (same colorspace as the input output, usually RGB) + */ + inline const std::valarray &getColorOutput() const {return _colorEngine.getDemultiplexedColorFrame();};// retrieve luminance+chrominance + + /** + * apply to the retina color output the Krauskopf transformation which leads to an opponent color system: output colorspace if Acr1cr2 if input of the retina was LMS color space + * @param result: the input buffer to fill with the transformed colorspace retina output + * @return true if process ended successfully + */ + inline const bool applyKrauskopfLMS2Acr1cr2Transform(std::valarray &result){return _colorEngine.applyKrauskopfLMS2Acr1cr2Transform(result);}; + + /** + * apply to the retina color output the Krauskopf transformation which leads to an opponent color system: output colorspace if Acr1cr2 if input of the retina was LMS color space + * @param result: the input buffer to fill with the transformed colorspace retina output + * @return true if process ended successfully + */ + inline const bool applyLMS2LabTransform(std::valarray &result){return _colorEngine.applyLMS2LabTransform(result);}; + + /** + * color processing dedicated functions + * @return the retina initialized mode, true if color mode (RGB), false if grayscale + */ + inline const bool isColorMode(){return _useColorMode;}; // return true if RGB mode, false if gray level mode + + /** + * @return the irregular low pass filter ouput at the photoreceptors level + */ + inline const std::valarray &getIrregularLPfilteredInputFrame() const {return _photoreceptorsLogSampling->getIrregularLPfilteredInputFrame();}; + + /** + * @return true if color mode is activated, false if gray levels processing + */ + const bool getColorMode(){return _useColorMode;}; + + /** + * + * @return true if a sufficient number of processed frames has been done since the last parameters update in order to get the stable state (r�gime permanent) + */ + inline const bool isInitTransitionDone(){if (_ellapsedFramesSinceLastReset<_globalTemporalConstant)return false; return true;}; + + /** + * find a distance in the image input space when the distance is known in the retina log sampled space...read again if it is not clear enough....sorry, i should sleep + * @param projectedRadiusLength: the distance to image center in the retina log sampled space + * @return the distance to image center in the input image space + */ + inline const double getRetinaSamplingBackProjection(const double projectedRadiusLength){if (_photoreceptorsLogSampling)return _photoreceptorsLogSampling->getOriginalRadiusLength(projectedRadiusLength);else return projectedRadiusLength;}; + + /////////////////: + // retina dimensions getters + + /** + * @return number of rows of the filter + */ + inline const unsigned int getInputNBrows(){if (_photoreceptorsLogSampling) return _photoreceptorsLogSampling->getNBrows();else return _photoreceptorsPrefilter.getNBrows();}; + + /** + * @return number of columns of the filter + */ + inline const unsigned int getInputNBcolumns(){if (_photoreceptorsLogSampling) return _photoreceptorsLogSampling->getNBcolumns();else return _photoreceptorsPrefilter.getNBcolumns();}; + + /** + * @return number of pixels of the filter + */ + inline const unsigned int getInputNBpixels(){if (_photoreceptorsLogSampling) return _photoreceptorsLogSampling->getNBpixels();else return _photoreceptorsPrefilter.getNBpixels();}; + + /** + * @return the height of the frame output + */ + inline const unsigned int getOutputNBrows(){return _photoreceptorsPrefilter.getNBrows();}; + + /** + * @return the width of the frame output + */ + inline const unsigned int getOutputNBcolumns(){return _photoreceptorsPrefilter.getNBcolumns();}; + + /** + * @return the numbers of output pixels (width*height) of the images used by the object + */ + inline const unsigned int getOutputNBpixels(){return _photoreceptorsPrefilter.getNBpixels();}; + + +private: + + // processing activation flags + bool _useParvoOutput; + bool _useMagnoOutput; + + + // filter stability controls + unsigned int _ellapsedFramesSinceLastReset; + unsigned int _globalTemporalConstant; + + // private template buffers and related access pointers + std::valarray _retinaParvoMagnoMappedFrame; + std::valarray _retinaParvoMagnoMapCoefTable; + // private objects of the class + BasicRetinaFilter _photoreceptorsPrefilter; + ParvoRetinaFilter _ParvoRetinaFilter; + MagnoRetinaFilter _MagnoRetinaFilter; + RetinaColor _colorEngine; + ImageLogPolProjection *_photoreceptorsLogSampling; + + bool _useMinimalMemoryForToneMappingONLY; + + bool _normalizeParvoOutput_0_maxOutputValue; + bool _normalizeMagnoOutput_0_maxOutputValue; + double _maxOutputValue; + bool _useColorMode; + + + + // private functions + void _setInitPeriodCount(); + void _createHybridTable(); + void _processRetinaParvoMagnoMapping(); + void _runGrayToneMapping(const std::valarray &grayImageInput, std::valarray &grayImageOutput ,const double PhotoreceptorsCompression=0.6, const double ganglionCellsCompression=0.6); + + +}; + +} +#endif /*RETINACLASSES_H_*/ + + + + diff --git a/modules/contrib/src/spinimages.cpp b/modules/contrib/src/spinimages.cpp index 727b0bb80b..63396845d3 100644 --- a/modules/contrib/src/spinimages.cpp +++ b/modules/contrib/src/spinimages.cpp @@ -442,11 +442,11 @@ void cv::Mesh3D::clearOctree(){ octree = Octree(); } float cv::Mesh3D::estimateResolution(float tryRatio) { - const size_t neighbors = 3; - const size_t minReasonable = 10; + const int neighbors = 3; + const int minReasonable = 10; - size_t tryNum = static_cast(tryRatio * vtx.size()); - tryNum = min(max(tryNum, minReasonable), vtx.size()); + int tryNum = static_cast(tryRatio * vtx.size()); + tryNum = min(max(tryNum, minReasonable), (int)vtx.size()); CvMat desc = cvMat((int)vtx.size(), 3, CV_32F, &vtx[0]); CvFeatureTree* tr = cvCreateKDTree(&desc); @@ -456,7 +456,7 @@ float cv::Mesh3D::estimateResolution(float tryRatio) vector query; RNG& rng = theRNG(); - for(size_t i = 0; i < tryNum; ++i) + for(int i = 0; i < tryNum; ++i) query.push_back(vtx[rng.next() % vtx.size()]); CvMat cvinds = cvMat( (int)tryNum, neighbors, CV_32S, &inds[0] ); @@ -466,7 +466,7 @@ float cv::Mesh3D::estimateResolution(float tryRatio) cvReleaseFeatureTree(tr); const int invalid_dist = -2; - for(size_t i = 0; i < tryNum; ++i) + for(int i = 0; i < tryNum; ++i) if (inds[i] == -1) dist[i] = invalid_dist; @@ -713,8 +713,8 @@ void cv::SpinImageModel::defaultParams() Mat cv::SpinImageModel::packRandomScaledSpins(bool separateScale, size_t xCount, size_t yCount) const { - size_t spinNum = getSpinCount(); - size_t num = min(spinNum, xCount * yCount); + int spinNum = (int)getSpinCount(); + int num = min(spinNum, (int)(xCount * yCount)); if (num == 0) return Mat(); @@ -722,11 +722,11 @@ Mat cv::SpinImageModel::packRandomScaledSpins(bool separateScale, size_t xCount, RNG& rng = theRNG(); vector spins; - for(size_t i = 0; i < num; ++i) + for(int i = 0; i < num; ++i) spins.push_back(getSpinImage( rng.next() % spinNum ).reshape(1, imageWidth)); if (separateScale) - for(size_t i = 0; i < num; ++i) + for(int i = 0; i < num; ++i) { double max; Mat spin8u; @@ -737,14 +737,14 @@ Mat cv::SpinImageModel::packRandomScaledSpins(bool separateScale, size_t xCount, else { double totalMax = 0; - for(size_t i = 0; i < num; ++i) + for(int i = 0; i < num; ++i) { double m; minMaxLoc(spins[i], 0, &m); totalMax = max(m, totalMax); } - for(size_t i = 0; i < num; ++i) + for(int i = 0; i < num; ++i) { Mat spin8u; spins[i].convertTo(spin8u, CV_8U, -255.0/totalMax, 255.0); @@ -757,16 +757,16 @@ Mat cv::SpinImageModel::packRandomScaledSpins(bool separateScale, size_t xCount, Mat result((int)(yCount * sz + (yCount - 1)), (int)(xCount * sz + (xCount - 1)), CV_8UC3); result = colors[(static_cast(cvGetTickCount()/cvGetTickFrequency())/1000) % colors_mum]; - size_t pos = 0; - for(size_t y = 0; y < yCount; ++y) - for(size_t x = 0; x < xCount; ++x) + int pos = 0; + for(int y = 0; y < (int)yCount; ++y) + for(int x = 0; x < (int)xCount; ++x) if (pos < num) { - int starty = (int)((y + 0) * sz + y); - int endy = (int)((y + 1) * sz + y); + int starty = (y + 0) * sz + y; + int endy = (y + 1) * sz + y; - int startx = (int)((x + 0) * sz + x); - int endx = (int)((x + 1) * sz + x); + int startx = (x + 0) * sz + x; + int endx = (x + 1) * sz + x; Mat color; cvtColor(spins[pos++], color, CV_GRAY2BGR); diff --git a/modules/contrib/src/stereovar.cpp b/modules/contrib/src/stereovar.cpp index cc6c53b60d..1197acc434 100755 --- a/modules/contrib/src/stereovar.cpp +++ b/modules/contrib/src/stereovar.cpp @@ -53,7 +53,7 @@ namespace cv { -StereoVar::StereoVar() : levels(3), pyrScale(0.5), nIt(3), minDisp(0), maxDisp(16), poly_n(5), poly_sigma(1.2), fi(1000.0f), lambda(0.0f), penalization(PENALIZATION_TICHONOV), cycle(CYCLE_V), flags(USE_SMART_ID) +StereoVar::StereoVar() : levels(3), pyrScale(0.5), nIt(5), minDisp(0), maxDisp(16), poly_n(3), poly_sigma(0), fi(25.0f), lambda(0.03f), penalization(PENALIZATION_TICHONOV), cycle(CYCLE_V), flags(USE_SMART_ID | USE_AUTO_PARAMS) { } @@ -65,111 +65,174 @@ StereoVar::~StereoVar() { } -static Mat diffX(Mat &img) +static Mat diffX(Mat &src) +{ + register int x, y, cols = src.cols - 1; + Mat dst(src.size(), src.type()); + for(y = 0; y < src.rows; y++){ + const float* pSrc = src.ptr(y); + float* pDst = dst.ptr(y); +#if CV_SSE2 + for (x = 0; x <= cols - 8; x += 8) { + __m128 a0 = _mm_loadu_ps(pSrc + x); + __m128 b0 = _mm_loadu_ps(pSrc + x + 1); + __m128 a1 = _mm_loadu_ps(pSrc + x + 4); + __m128 b1 = _mm_loadu_ps(pSrc + x + 5); + b0 = _mm_sub_ps(b0, a0); + b1 = _mm_sub_ps(b1, a1); + _mm_storeu_ps(pDst + x, b0); + _mm_storeu_ps(pDst + x + 4, b1); + } +#endif + for( ; x < cols; x++) pDst[x] = pSrc[x+1] - pSrc[x]; + pDst[cols] = 0.f; + } + return dst; +} + +static Mat getGradient(Mat &src) { - // TODO try pointers or assm register int x, y; - Mat dst(img.size(), img.type()); + Mat dst(src.size(), src.type()); dst.setTo(0); - for (x = 0; x < img.cols - 1; x++) - for (y = 0; y < img.rows; y++) - dst.at(y, x) = img.at(y, x + 1) - img.at(y ,x); + for (y = 0; y < src.rows - 1; y++) { + float *pSrc = src.ptr(y); + float *pSrcF = src.ptr(y + 1); + float *pDst = dst.ptr(y); + for (x = 0; x < src.cols - 1; x++) + pDst[x] = fabs(pSrc[x + 1] - pSrc[x]) + fabs(pSrcF[x] - pSrc[x]); + } return dst; } -static Mat Gradient(Mat &img) +static Mat getG_c(Mat &src, float l) { - Mat sobel, sobelX, sobelY; - img.copyTo(sobelX); - img.copyTo(sobelY); - Sobel(img, sobelX, sobelX.type(), 1, 0, 1); - Sobel(img, sobelY, sobelY.type(), 0, 1, 1); - sobelX = abs(sobelX); - sobelY = abs(sobelY); - add(sobelX, sobelY, sobel); - sobelX.release(); - sobelY.release(); - return sobel; + Mat dst(src.size(), src.type()); + for (register int y = 0; y < src.rows; y++) { + float *pSrc = src.ptr(y); + float *pDst = dst.ptr(y); + for (register int x = 0; x < src.cols; x++) + pDst[x] = 0.5f*l / sqrtf(l*l + pSrc[x]*pSrc[x]); + } + return dst; } -static float g_c(Mat z, int x, int y, float l) +static Mat getG_p(Mat &src, float l) { - return 0.5f*l / sqrtf(l*l + z.at(y,x)*z.at(y,x)); -} - -static float g_p(Mat z, int x, int y, float l) -{ - return 0.5f*l*l / (l*l + z.at(y,x)*z.at(y,x)) ; + Mat dst(src.size(), src.type()); + for (register int y = 0; y < src.rows; y++) { + float *pSrc = src.ptr(y); + float *pDst = dst.ptr(y); + for (register int x = 0; x < src.cols; x++) + pDst[x] = 0.5f*l*l / (l*l + pSrc[x]*pSrc[x]); + } + return dst; } void StereoVar::VariationalSolver(Mat &I1, Mat &I2, Mat &I2x, Mat &u, int level) { register int n, x, y; float gl = 1, gr = 1, gu = 1, gd = 1, gc = 4; + Mat g_c, g_p; Mat U; - Mat Sobel; u.copyTo(U); int N = nIt; float l = lambda; float Fi = fi; - double scale = pow(pyrScale, (double) level); - if (flags & USE_SMART_ID) { + + if (flags & USE_SMART_ID) { + double scale = pow(pyrScale, (double) level) * (1 + pyrScale); N = (int) (N / scale); - Fi /= (float) scale; - l *= (float) scale; } + + double scale = pow(pyrScale, (double) level); + Fi /= (float) scale; + l *= (float) scale; + + int width = u.cols - 1; + int height = u.rows - 1; for (n = 0; n < N; n++) { - if (penalization != PENALIZATION_TICHONOV) {if(!Sobel.empty()) Sobel.release(); Sobel = Gradient(U);} - for (x = 1; x < u.cols - 1; x++) { - for (y = 1 ; y < u.rows - 1; y++) { + if (penalization != PENALIZATION_TICHONOV) { + Mat gradient = getGradient(U); + switch (penalization) { + case PENALIZATION_CHARBONNIER: g_c = getG_c(gradient, l); break; + case PENALIZATION_PERONA_MALIK: g_p = getG_p(gradient, l); break; + } + gradient.release(); + } + for (y = 1 ; y < height; y++) { + float *pU = U.ptr(y); + float *pUu = U.ptr(y + 1); + float *pUd = U.ptr(y - 1); + float *pu = u.ptr(y); + float *pI1 = I1.ptr(y); + float *pI2 = I2.ptr(y); + float *pI2x = I2x.ptr(y); + float *pG_c = NULL, *pG_cu = NULL, *pG_cd = NULL; + float *pG_p = NULL, *pG_pu = NULL, *pG_pd = NULL; + switch (penalization) { + case PENALIZATION_CHARBONNIER: + pG_c = g_c.ptr(y); + pG_cu = g_c.ptr(y + 1); + pG_cd = g_c.ptr(y - 1); + break; + case PENALIZATION_PERONA_MALIK: + pG_p = g_p.ptr(y); + pG_pu = g_p.ptr(y + 1); + pG_pd = g_p.ptr(y - 1); + break; + } + for (x = 1; x < width; x++) { switch (penalization) { case PENALIZATION_CHARBONNIER: - gc = g_c(Sobel, x, y, l); - gl = gc + g_c(Sobel, x - 1, y, l); - gr = gc + g_c(Sobel, x + 1, y, l); - gu = gc + g_c(Sobel, x, y + 1, l); - gd = gc + g_c(Sobel, x, y - 1, l); - gc = gl + gr + gu + gd; + gc = pG_c[x]; + gl = gc + pG_c[x - 1]; + gr = gc + pG_c[x + 1]; + gu = gc + pG_cu[x]; + gd = gc + pG_cd[x]; + gc = gl + gr + gu + gd; break; case PENALIZATION_PERONA_MALIK: - gc = g_p(Sobel, x, y, l); - gl = gc + g_p(Sobel, x - 1, y, l); - gr = gc + g_p(Sobel, x + 1, y, l); - gu = gc + g_p(Sobel, x, y + 1, l); - gd = gc + g_p(Sobel, x, y - 1, l); + gc = pG_p[x]; + gl = gc + pG_p[x - 1]; + gr = gc + pG_p[x + 1]; + gu = gc + pG_pu[x]; + gd = gc + pG_pd[x]; gc = gl + gr + gu + gd; break; } float fi = Fi; if (maxDisp > minDisp) { - if (U.at(y,x) > maxDisp * scale) {fi*=1000; U.at(y,x) = static_cast(maxDisp * scale);} - if (U.at(y,x) < minDisp * scale) {fi*=1000; U.at(y,x) = static_cast(minDisp * scale);} + if (pU[x] > maxDisp * scale) {fi *= 1000; pU[x] = static_cast(maxDisp * scale);} + if (pU[x] < minDisp * scale) {fi *= 1000; pU[x] = static_cast(minDisp * scale);} } - int A = (int) (U.at(y,x)); - int neg = 0; if (U.at(y,x) <= 0) neg = -1; + int A = static_cast(pU[x]); + int neg = 0; if (pU[x] <= 0) neg = -1; - if (x + A >= u.cols) - u.at(y, x) = U.at(y, u.cols - A - 1); + if (x + A > width) + pu[x] = pU[width - A]; else if (x + A + neg < 0) - u.at(y, x) = U.at(y, - A + 2); + pu[x] = pU[- A + 2]; else { - u.at(y, x) = A + (I2x.at(y, x + A + neg) * (I1.at(y, x) - I2.at(y, x + A)) - + fi * (gr * U.at(y, x + 1) + gl * U.at(y, x - 1) + gu * U.at(y + 1, x) + gd * U.at(y - 1, x) - gc * A)) - / (I2x.at(y, x + A + neg) * I2x.at(y, x + A + neg) + gc * fi) ; + pu[x] = A + (pI2x[x + A + neg] * (pI1[x] - pI2[x + A]) + + fi * (gr * pU[x + 1] + gl * pU[x - 1] + gu * pUu[x] + gd * pUd[x] - gc * A)) + / (pI2x[x + A + neg] * pI2x[x + A + neg] + gc * fi) ; } - }//y + }// x + pu[0] = pu[1]; + pu[width] = pu[width - 1]; + }// y + for (x = 0; x <= width; x++) { u.at(0, x) = u.at(1, x); - u.at(u.rows - 1, x) = u.at(u.rows - 2, x); - }//x - for (y = 0; y < u.rows; y++) { - u.at(y, 0) = u.at(y, 1); - u.at(y, u.cols - 1) = u.at(y, u.cols - 2); + u.at(height, x) = u.at(height - 1, x); } u.copyTo(U); + if (!g_c.empty()) g_c.release(); + if (!g_p.empty()) g_p.release(); }//n } @@ -251,15 +314,43 @@ void StereoVar::FMG(Mat &I1, Mat &I2, Mat &I2x, Mat &u, int level) u_h.release(); level--; + if ((flags & USE_AUTO_PARAMS) && (level < levels / 3)) { + penalization = PENALIZATION_PERONA_MALIK; + fi *= 100; + flags -= USE_AUTO_PARAMS; + autoParams(); + } if (flags & USE_MEDIAN_FILTERING) medianBlur(u, u, 3); if (level >= 0) FMG(I1, I2, I2x, u, level); } +void StereoVar::autoParams() +{ + int maxD = MAX(labs(maxDisp), labs(minDisp)); + + if (!maxD) pyrScale = 0.85; + else if (maxD < 8) pyrScale = 0.5; + else if (maxD < 64) pyrScale = 0.5 + static_cast(maxD - 8) * 0.00625; + else pyrScale = 0.85; + + if (maxD) { + levels = 0; + while ( pow(pyrScale, levels) * maxD > 1.5) levels ++; + levels++; + } + + switch(penalization) { + case PENALIZATION_TICHONOV: cycle = CYCLE_V; break; + case PENALIZATION_CHARBONNIER: cycle = CYCLE_O; break; + case PENALIZATION_PERONA_MALIK: cycle = CYCLE_O; break; + } +} + void StereoVar::operator ()( const Mat& left, const Mat& right, Mat& disp ) { CV_Assert(left.size() == right.size() && left.type() == right.type()); CvSize imgSize = left.size(); - int MaxD = MAX(std::abs(minDisp), std::abs(maxDisp)); + int MaxD = MAX(labs(minDisp), labs(maxDisp)); int SignD = 1; if (MIN(minDisp, maxDisp) < 0) SignD = -1; if (minDisp >= maxDisp) {MaxD = 256; SignD = 1;} @@ -290,6 +381,11 @@ void StereoVar::operator ()( const Mat& left, const Mat& right, Mat& disp ) GaussianBlur(rightgray, rightgray, cvSize(poly_n, poly_n), poly_sigma); } + if (flags & USE_AUTO_PARAMS) { + penalization = PENALIZATION_TICHONOV; + autoParams(); + } + Mat I1, I2; leftgray.convertTo(I1, CV_32FC1); rightgray.convertTo(I2, CV_32FC1); diff --git a/modules/contrib/src/templatebuffer.hpp b/modules/contrib/src/templatebuffer.hpp new file mode 100644 index 0000000000..14bcea9052 --- /dev/null +++ b/modules/contrib/src/templatebuffer.hpp @@ -0,0 +1,520 @@ +/*#****************************************************************************** +** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +** +** By downloading, copying, installing or using the software you agree to this license. +** If you do not agree to this license, do not download, install, +** copy or use the software. +** +** +** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. +** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. +** +** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) +** +** Creation - enhancement process 2007-2011 +** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France +** +** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). +** Refer to the following research paper for more information: +** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 +** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: +** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. +** +** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : +** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: +** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 +** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. +** ====> more informations in the above cited Jeanny Heraults's book. +** +** License Agreement +** For Open Source Computer Vision Library +** +** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. +** +** For Human Visual System tools (hvstools) +** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. +** +** Third party copyrights are property of their respective owners. +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * The name of the copyright holders may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** This software is provided by the copyright holders and contributors "as is" and +** any express or implied warranties, including, but not limited to, the implied +** warranties of merchantability and fitness for a particular purpose are disclaimed. +** In no event shall the Intel Corporation or contributors be liable for any direct, +** indirect, incidental, special, exemplary, or consequential damages +** (including, but not limited to, procurement of substitute goods or services; +** loss of use, data, or profits; or business interruption) however caused +** and on any theory of liability, whether in contract, strict liability, +** or tort (including negligence or otherwise) arising in any way out of +** the use of this software, even if advised of the possibility of such damage. +*******************************************************************************/ + +#ifndef __TEMPLATEBUFFER_HPP__ +#define __TEMPLATEBUFFER_HPP__ + +#include +#include +#include +#include + +//#define __TEMPLATEBUFFERDEBUG //define TEMPLATEBUFFERDEBUG in order to display debug information + +namespace cv +{ +/** +* @class TemplateBuffer +* @brief this class is a simple template memory buffer which contains basic functions to get information on or normalize the buffer content +* note that thanks to the parent STL template class "valarray", it is possible to perform easily operations on the full array such as addition, product etc. +* @author Alexandre BENOIT (benoit.alexandre.vision@gmail.com), helped by Gelu IONESCU (gelu.ionescu@lis.inpg.fr) +* creation date: september 2007 +*/ +template class TemplateBuffer : public std::valarray +{ +public: + + /** + * constructor for monodimensional array + * @param dim: the size of the vector + */ + TemplateBuffer(const size_t dim=0) + : std::valarray((type)0, dim) + { + _NBrows=1; + _NBcolumns=dim; + _NBdepths=1; + _NBpixels=dim; + _doubleNBpixels=2*dim; + } + + /** + * constructor by copy for monodimensional array + * @param pVal: the pointer to a buffer to copy + * @param dim: the size of the vector + */ + TemplateBuffer(const type* pVal, const size_t dim) + : std::valarray(pVal, dim) + { + _NBrows=1; + _NBcolumns=dim; + _NBdepths=1; + _NBpixels=dim; + _doubleNBpixels=2*dim; + } + + /** + * constructor for bidimensional array + * @param dimRows: the size of the vector + * @param dimColumns: the size of the vector + * @param depth: the number of layers of the buffer in its third dimension (3 of color images, 1 for gray images. + */ + TemplateBuffer(const size_t dimRows, const size_t dimColumns, const size_t depth=1) + : std::valarray((type)0, dimRows*dimColumns*depth) + { +#ifdef TEMPLATEBUFFERDEBUG + std::cout<<"TemplateBuffer::TemplateBuffer: new buffer, size="<(toCopy) + { + memcpy(Buffer(), toCopy.Buffer(), this->size()); + }*/ + /** + * destructor + */ + virtual ~TemplateBuffer() + { +#ifdef TEMPLATEBUFFERDEBUG + std::cout<<"~TemplateBuffer"<::operator=(0);};//memset(Buffer(), 0, sizeof(type)*_NBpixels);}; + + /** + * @return the numbers of rows (height) of the images used by the object + */ + inline unsigned int getNBrows(){return (unsigned int)_NBrows;}; + + /** + * @return the numbers of columns (width) of the images used by the object + */ + inline unsigned int getNBcolumns(){return (unsigned int)_NBcolumns;}; + + /** + * @return the numbers of pixels (width*height) of the images used by the object + */ + inline unsigned int getNBpixels(){return (unsigned int)_NBpixels;}; + + /** + * @return the numbers of pixels (width*height) of the images used by the object + */ + inline unsigned int getDoubleNBpixels(){return (unsigned int)_doubleNBpixels;}; + + /** + * @return the numbers of depths (3rd dimension: 1 for gray images, 3 for rgb images) of the images used by the object + */ + inline unsigned int getDepthSize(){return (unsigned int)_NBdepths;}; + + /** + * resize the buffer and recompute table index etc. + */ + void resizeBuffer(const size_t dimRows, const size_t dimColumns, const size_t depth=1) + { + this->resize(dimRows*dimColumns*depth); + _NBrows=dimRows; + _NBcolumns=dimColumns; + _NBdepths=depth; + _NBpixels=dimRows*dimColumns; + _doubleNBpixels=2*dimRows*dimColumns; + } + + inline TemplateBuffer & operator=(const std::valarray &b) + { + //std::cout<<"TemplateBuffer & operator= affect vector: "<::operator=(b); + return *this; + } + + inline TemplateBuffer & operator=(const type &b) + { + //std::cout<<"TemplateBuffer & operator= affect value: "<::operator=(b); + return *this; + } + + /* inline const type &operator[](const unsigned int &b) + { + return (*this)[b]; + } + */ + /** + * @return the buffer adress in non const mode + */ + inline type* Buffer() { return &(*this)[0]; } + + /////////////////////////////////////////////////////// + // Standard Image manipulation functions + + /** + * standard 0 to 255 image normalization function + * @param inputOutputBuffer: the image to be normalized (rewrites the input), if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param nbPixels: specifies the number of pixel on which the normalization should be performed, if 0, then all pixels specified in the constructor are processed + * @param maxOutputValue: the maximum output value + */ + static void normalizeGrayOutput_0_maxOutputValue(type *inputOutputBuffer, const size_t nbPixels, const type maxOutputValue=(type)255.0); + + /** + * standard 0 to 255 image normalization function + * @param inputOutputBuffer: the image to be normalized (rewrites the input), if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param nbPixels: specifies the number of pixel on which the normalization should be performed, if 0, then all pixels specified in the constructor are processed + * @param maxOutputValue: the maximum output value + */ + void normalizeGrayOutput_0_maxOutputValue(const type maxOutputValue=(type)255.0){normalizeGrayOutput_0_maxOutputValue(this->Buffer(), this->size(), maxOutputValue);}; + + /** + * sigmoide image normalization function (saturates min and max values) + * @param meanValue: specifies the mean value of th pixels to be processed + * @param sensitivity: strenght of the sigmoide + * @param inputPicture: the image to be normalized if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param outputBuffer: the ouput buffer on which the result is writed, if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param maxOutputValue: the maximum output value + */ + static void normalizeGrayOutputCentredSigmoide(const type meanValue, const type sensitivity, const type maxOutputValue, type *inputPicture, type *outputBuffer, const unsigned int nbPixels); + + /** + * sigmoide image normalization function on the current buffer (saturates min and max values) + * @param meanValue: specifies the mean value of th pixels to be processed + * @param sensitivity: strenght of the sigmoide + * @param maxOutputValue: the maximum output value + */ + inline void normalizeGrayOutputCentredSigmoide(const type meanValue=(type)0.0, const type sensitivity=(type)2.0, const type maxOutputValue=(type)255.0){normalizeGrayOutputCentredSigmoide(meanValue, sensitivity, 255.0, this->Buffer(), this->Buffer(), this->getNBpixels()), maxOutputValue;}; + + /** + * sigmoide image normalization function (saturates min and max values), in this function, the sigmoide is centered on low values (high saturation of the medium and high values + * @param inputPicture: the image to be normalized if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param outputBuffer: the ouput buffer on which the result is writed, if no parameter, then, the built in buffer reachable by getOutput() function is normalized + * @param sensitivity: strenght of the sigmoide + * @param maxOutputValue: the maximum output value + */ + void normalizeGrayOutputNearZeroCentreredSigmoide(type *inputPicture=(type*)NULL, type *outputBuffer=(type*)NULL, const type sensitivity=(type)40, const type maxOutputValue=(type)255.0); + + /** + * center and reduct the image (image-mean)/std + * @param inputOutputBuffer: the image to be normalized if no parameter, the result is rewrited on it + */ + void centerReductImageLuminance(type *inputOutputBuffer=(type*)NULL); + + /** + * @return standard deviation of the buffer + */ + const double getStandardDeviation() + { + double standardDeviation=0; + double meanValue=getMean(); + + type *bufferPTR=Buffer(); + for (unsigned int i=0;isize();++i) + { + double diff=(*(bufferPTR++)-meanValue); + standardDeviation+=diff*diff; + } + return sqrt(standardDeviation/this->size()); + }; + + /** + * Clip buffer histogram + * @param minRatio: the minimum ratio of the lower pixel values, range=[0,1] and lower than maxRatio + * @param maxRatio: the aximum ratio of the higher pixel values, range=[0,1] and higher than minRatio + */ + void clipHistogram(double minRatio, double maxRatio, double maxOutputValue) + { + + if (minRatio>=maxRatio) + { + std::cerr<<"TemplateBuffer::clipHistogram: minRatio must be inferior to maxRatio, buffer unchanged"<max()*maxRatio; + const double minThreshold=(this->max()-this->min())*minRatio+this->min(); + + type *bufferPTR=this->Buffer(); + + double deltaH=maxThreshold; + double deltaL=maxThreshold; + + double updatedHighValue=maxThreshold; + double updatedLowValue=maxThreshold; + + for (unsigned int i=0;isize();++i) + { + double curentValue=(double)*(bufferPTR++); + + // updating "closest to the high threshold" pixel value + double highValueTest=maxThreshold-curentValue; + if (highValueTest>0) + { + if (deltaH>highValueTest) + { + deltaH=highValueTest; + updatedHighValue=curentValue; + } + } + + // updating "closest to the low threshold" pixel value + double lowValueTest=curentValue-minThreshold; + if (lowValueTest>0) + { + if (deltaL>lowValueTest) + { + deltaL=lowValueTest; + updatedLowValue=curentValue; + } + } + } + + std::cout<<"Tdebug"<max()"<max()<<"maxThreshold="<min()"<min()<<"minThreshold="<Buffer(); + for (unsigned int i=0;isize();++i, ++bufferPTR) + { + if (*bufferPTRupdatedHighValue) + *bufferPTR=updatedHighValue; + } + + normalizeGrayOutput_0_maxOutputValue(this->Buffer(), this->size(), maxOutputValue); + + } + + /** + * @return the mean value of the vector + */ + inline const double getMean(){return this->sum()/this->size();}; + +protected: + size_t _NBrows; + size_t _NBcolumns; + size_t _NBdepths; + size_t _NBpixels; + size_t _doubleNBpixels; + // utilities + static type _abs(const type x); + +}; + +/////////////////////////////////////////////////////////////////////// +/// normalize output between 0 and 255, can be applied on images of different size that the declared size if nbPixels parameters is setted up; +template +void TemplateBuffer::normalizeGrayOutput_0_maxOutputValue(type *inputOutputBuffer, const size_t processedPixels, const type maxOutputValue) +{ + type maxValue=inputOutputBuffer[0], minValue=inputOutputBuffer[0]; + + // get the min and max value + register type *inputOutputBufferPTR=inputOutputBuffer; + for (register size_t j = 0; j pixValue) + minValue = pixValue; + } + // change the range of the data to 0->255 + + type factor = maxOutputValue/(maxValue-minValue); + type offset = -1.0*minValue*factor; + + inputOutputBufferPTR=inputOutputBuffer; + for (register size_t j = 0; j < processedPixels; ++j, ++inputOutputBufferPTR) + *inputOutputBufferPTR=*(inputOutputBufferPTR)*factor+offset; + +} +// normalize data with a sigmoide close to 0 (saturates values for those superior to 0) +template +void TemplateBuffer::normalizeGrayOutputNearZeroCentreredSigmoide(type *inputBuffer, type *outputBuffer, const type sensitivity, const type maxOutputValue) +{ + if (inputBuffer==NULL) + inputBuffer=Buffer(); + if (outputBuffer==NULL) + outputBuffer=Buffer(); + + type X0cube=sensitivity*sensitivity*sensitivity; + + register type *inputBufferPTR=inputBuffer; + register type *outputBufferPTR=outputBuffer; + + for (register size_t j = 0; j < _NBpixels; ++j, ++inputBufferPTR) + { + + type currentCubeLuminance=*inputBufferPTR**inputBufferPTR**inputBufferPTR; + *(outputBufferPTR++)=maxOutputValue*currentCubeLuminance/(currentCubeLuminance+X0cube); + } +} + +// normalize and adjust luminance with a centered to 128 sigmode +template +void TemplateBuffer::normalizeGrayOutputCentredSigmoide(const type meanValue, const type sensitivity, const type maxOutputValue, type *inputBuffer, type *outputBuffer, const unsigned int nbPixels) +{ + + if (sensitivity==1.0) + { + std::cerr<<"TemplateBuffer::TemplateBuffer::normalizeGrayOutputCentredSigmoide error: 2nd parameter (sensitivity) must not equal 0, copying original data..."< +void TemplateBuffer::centerReductImageLuminance(type *inputOutputBuffer) +{ + // if outputBuffer unsassigned, the rewrite the buffer + if (inputOutputBuffer==NULL) + inputOutputBuffer=Buffer(); + type meanValue=0, stdValue=0; + + // compute mean value + for (register size_t j = 0; j < _NBpixels; ++j) + meanValue+=inputOutputBuffer[j]; + meanValue/=((type)_NBpixels); + + // compute std value + register type *inputOutputBufferPTR=inputOutputBuffer; + for (size_t index=0;index<_NBpixels;++index) + { + type inputMinusMean=*(inputOutputBufferPTR++)-meanValue; + stdValue+=inputMinusMean*inputMinusMean; + } + + stdValue=sqrt(stdValue/((type)_NBpixels)); + // adjust luminance in regard of mean and std value; + inputOutputBufferPTR=inputOutputBuffer; + for (size_t index=0;index<_NBpixels;++index, ++inputOutputBufferPTR) + *inputOutputBufferPTR=(*(inputOutputBufferPTR)-meanValue)/stdValue; +} + + +template +type TemplateBuffer::_abs(const type x) +{ + + if (x>0) + return x; + else + return -x; +} + +template < > +inline int TemplateBuffer::_abs(const int x) +{ + return std::abs(x); +} +template < > +inline double TemplateBuffer::_abs(const double x) +{ + return std::fabs(x); +} + +template < > +inline float TemplateBuffer::_abs(const float x) +{ + return std::fabs(x); +} + +} +#endif + + + diff --git a/modules/core/doc/basic_structures.rst b/modules/core/doc/basic_structures.rst index 24c9646120..208554c0d5 100644 --- a/modules/core/doc/basic_structures.rst +++ b/modules/core/doc/basic_structures.rst @@ -113,7 +113,7 @@ Rect\_ ------ .. ocv:class:: Rect_ -Template class for 2D rectangles, described by the following parameters:: +Template class for 2D rectangles, described by the following parameters: * Coordinates of the top-left corner. This is a default interpretation of ``Rect_::x`` and ``Rect_::y`` in OpenCV. Though, in your algorithms you may count ``x`` and ``y`` from the bottom-left corner. * Rectangle width and height. @@ -215,7 +215,7 @@ If you need a more flexible type, use :ocv:class:`Mat` . The elements of the mat 7, 8, 9); cout << sum(Mat(m*m.t())) << endl; - + Vec --- .. ocv:class:: Vec @@ -303,6 +303,8 @@ The static method ``Range::all()`` returns a special variable that means "the wh } +.. _Ptr: + Ptr --- .. ocv:class:: Ptr @@ -652,50 +654,86 @@ Matrix Expressions ------------------ This is a list of implemented matrix operations that can be combined in arbitrary complex expressions -(here -*A*,*B* -stand for matrices ( ``Mat`` ), -*s* -for a scalar ( ``Scalar`` ), -:math:`\alpha` for a real-valued scalar ( ``double`` )): +(here ``A``, ``B`` stand for matrices ( ``Mat`` ), ``s`` for a scalar ( ``Scalar`` ), +``alpha`` for a real-valued scalar ( ``double`` )): * Addition, subtraction, negation: - :math:`A \pm B,\;A \pm s,\;s \pm A,\;-A` * - scaling: - :math:`A*\alpha`, :math:`A*\alpha` * - per-element multiplication and division: - :math:`A.mul(B), A/B, \alpha/A` * - matrix multiplication: - :math:`A*B` * - transposition: - :math:`A.t() \sim A^t` * - matrix inversion and pseudo-inversion, solving linear systems and least-squares problems: + ``A+B, A-B, A+s, A-s, s+A, s-A, -A`` + +* + Scaling: + ``A*alpha`` + +* + Per-element multiplication and division: + ``A.mul(B), A/B, alpha/A`` + +* + Matrix multiplication: + ``A*B`` + +* + Transposition: + ``A.t()`` (means ``A``\ :sup:`T`) + +* + Matrix inversion and pseudo-inversion, solving linear systems and least-squares problems: - :math:`A.inv([method]) \sim A^{-1}, A.inv([method])*B \sim X:\,AX=B` + ``A.inv([method])`` (~ ``A``\ :sup:`-1`) ``, A.inv([method])*B`` (~ ``X: AX=B``) * Comparison: - :math:`A\gtreqqless B,\;A \ne B,\;A \gtreqqless \alpha,\;A \ne \alpha`. The result of comparison is an 8-bit single channel mask whose elements are set to 255 (if the particular element or pair of elements satisfy the condition) or 0. + ``A cmpop B, A cmpop alpha, alpha cmpop A``, where ``cmpop`` is one of ``: >, >=, ==, !=, <=, <``. The result of comparison is an 8-bit single channel mask whose elements are set to 255 (if the particular element or pair of elements satisfy the condition) or 0. * - Bitwise logical operations: ``A & B, A & s, A | B, A | s, A textasciicircum B, A textasciicircum s, ~ A`` * - element-wise minimum and maximum: - :math:`min(A, B), min(A, \alpha), max(A, B), max(A, \alpha)` * - element-wise absolute value: - :math:`abs(A)` * - cross-product, dot-product: - :math:`A.cross(B), A.dot(B)` * - any function of matrix or matrices and scalars that returns a matrix or a scalar, such as ``norm``, ``mean``, ``sum``, ``countNonZero``, ``trace``, ``determinant``, ``repeat``, and others. + Bitwise logical operations: ``A logicop B, A logicop s, s logicop A, ~A``, where ``logicop`` is one of ``: &, |, ^``. + +* + Element-wise minimum and maximum: + ``min(A, B), min(A, alpha), max(A, B), max(A, alpha)`` + +* + Element-wise absolute value: + ``abs(A)`` + +* + Cross-product, dot-product: + ``A.cross(B)`` + ``A.dot(B)`` + +* + Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as ``norm``, ``mean``, ``sum``, ``countNonZero``, ``trace``, ``determinant``, ``repeat``, and others. * - Matrix initializers ( ``eye(), zeros(), ones()`` ), matrix comma-separated initializers, matrix constructors and operators that extract sub-matrices (see :ocv:class:`Mat` description). + Matrix initializers ( ``Mat::eye(), Mat::zeros(), Mat::ones()`` ), matrix comma-separated initializers, matrix constructors and operators that extract sub-matrices (see :ocv:class:`Mat` description). * ``Mat_()`` constructors to cast the result to the proper type. .. note:: Comma-separated initializers and probably some other operations may require additional explicit ``Mat()`` or ``Mat_()`` constuctor calls to resolve a possible ambiguity. +Here are examples of matrix expressions: + +:: + + // compute pseudo-inverse of A, equivalent to A.inv(DECOMP_SVD) + SVD svd(A); + Mat pinvA = svd.vt.t()*Mat::diag(1./svd.w)*svd.u.t(); + + // compute the new vector of parameters in the Levenberg-Marquardt algorithm + x -= (A.t()*A + lambda*Mat::eye(A.cols,A.cols,A.type())).inv(DECOMP_CHOLESKY)*(A.t()*err); + + // sharpen image using "unsharp mask" algorithm + Mat blurred; double sigma = 1, threshold = 5, amount = 1; + GaussianBlur(img, blurred, Size(), sigma, sigma); + Mat lowConstrastMask = abs(img - blurred) < threshold; + Mat sharpened = img*(1+amount) + blurred*(-amount); + img.copyTo(sharpened, lowContrastMask); + +.. + + Below is the formal description of the ``Mat`` methods. Mat::Mat @@ -800,7 +838,7 @@ Provides matrix assignment operators. .. ocv:function:: Mat& Mat::operator = (const MatExpr_Base& expr) -.. ocv:function:: Mat& operator = (const Scalar& s) +.. ocv:function:: Mat& Mat::operator = (const Scalar& s) :param m: Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that no data is copied but the data is shared and the reference counter, if any, is incremented. Before assigning new data, the old data is de-referenced via :ocv:func:`Mat::release` . @@ -853,7 +891,7 @@ The method makes a new header for the specified matrix row and returns it. This A.row(i) = A.row(j) + 0; // this is a bit longe, but the recommended method. - Mat Ai = A.row(i); M.row(j).copyTo(Ai); + A.row(j).copyTo(A.row(i)); Mat::col ------------ @@ -875,9 +913,9 @@ Creates a matrix header for the specified row span. .. ocv:function:: Mat Mat::rowRange(const Range& r) const - :param startrow: A 0-based start index of the row span. + :param startrow: An inclusive 0-based start index of the row span. - :param endrow: A 0-based ending index of the row span. + :param endrow: An exclusive 0-based ending index of the row span. :param r: :ocv:class:`Range` structure containing both the start and the end indices. @@ -893,9 +931,9 @@ Creates a matrix header for the specified row span. .. ocv:function:: Mat Mat::colRange(const Range& r) const - :param startcol: A 0-based start index of the column span. + :param startcol: An inclusive 0-based start index of the column span. - :param endcol: A 0-based ending index of the column span. + :param endcol: An exclusive 0-based ending index of the column span. :param r: :ocv:class:`Range` structure containing both the start and the end indices. @@ -954,6 +992,8 @@ so that the destination matrix is reallocated if needed. While ``m.copyTo(m);`` When the operation mask is specified, and the ``Mat::create`` call shown above reallocated the matrix, the newly allocated matrix is initialized with all zeros before copying the data. +.. _Mat::convertTo: + Mat::convertTo ------------------ Converts an array to another datatype with optional scaling. @@ -1115,7 +1155,7 @@ Returns a zero array of the specified size and type. :param cols: Number of columns. :param size: Alternative to the matrix size specification ``Size(cols, rows)`` . - + :param sizes: Array of integers specifying the array shape. :param type: Created matrix type. @@ -1144,8 +1184,8 @@ Returns an array of all 1's of the specified size and type. :param cols: Number of columns. :param size: Alternative to the matrix size specification ``Size(cols, rows)`` . - - :param sizes: Array of integers specifying the array shape. + + :param sizes: Array of integers specifying the array shape. :param type: Created matrix type. @@ -1170,7 +1210,7 @@ Returns an identity matrix of the specified size and type. :param cols: Number of columns. :param size: Alternative matrix size specification as ``Size(cols, rows)`` . - + :param type: Created matrix type. The method returns a Matlab-style identity matrix initializer, similarly to @@ -1196,7 +1236,7 @@ Allocates new array data if needed. :param cols: New number of columns. :param size: Alternative new matrix size specification: ``Size(cols, rows)`` - + :param sizes: Array of integers specifying a new array shape. :param type: New matrix type. @@ -1206,7 +1246,7 @@ This is one of the key ``Mat`` methods. Most new-style OpenCV functions and meth #. If the current array shape and the type match the new ones, return immediately. Otherwise, de-reference the previous data by calling :ocv:func:`Mat::release`. - + #. Initialize the new header. @@ -1360,9 +1400,9 @@ Extracts a rectangular submatrix. :param rowRange: Start and end row of the extracted submatrix. The upper boundary is not included. To select all the rows, use ``Range::all()``. - + :param colRange: Start and end column of the extracted submatrix. The upper boundary is not included. To select all the columns, use ``Range::all()``. - + :param roi: Extracted submatrix specified as a rectangle. :param ranges: Array of selected ranges along each array dimension. @@ -1484,7 +1524,7 @@ Mat::elemSize ----------------- Returns the matrix element size in bytes. -.. ocv:function:: size_t Mat::elemSize(void) const +.. ocv:function:: size_t Mat::elemSize() const The method returns the matrix element size in bytes. For example, if the matrix type is ``CV_16SC3`` , the method returns ``3*sizeof(short)`` or 6. @@ -1493,7 +1533,7 @@ Mat::elemSize1 ------------------ Returns the size of each matrix element channel in bytes. -.. ocv:function:: size_t Mat::elemSize() const +.. ocv:function:: size_t Mat::elemSize1() const The method returns the matrix element channel size in bytes, that is, it ignores the number of channels. For example, if the matrix type is ``CV_16SC3`` , the method returns ``sizeof(short)`` or 2. @@ -1675,9 +1715,9 @@ Mat::end ------------ Returns the matrix iterator and sets it to the after-last matrix element. -.. ocv:function:: MatIterator_<_Tp> Mat::end() +.. ocv:function:: template MatIterator_<_Tp> Mat::end() -.. ocv:function:: MatConstIterator_<_Tp> Mat::end() const +.. ocv:function:: template MatConstIterator_<_Tp> Mat::end() const The methods return the matrix read-only or read-write iterators, set to the point following the last matrix element. diff --git a/modules/core/doc/clustering.rst b/modules/core/doc/clustering.rst index e37036aae3..81bfb7abb6 100644 --- a/modules/core/doc/clustering.rst +++ b/modules/core/doc/clustering.rst @@ -58,14 +58,12 @@ partition ------------- Splits an element set into equivalency classes. -.. ocv:function:: template int - -.. ocv:function:: partition( const vector<_Tp>& vec, vector& labels, _EqPredicate predicate=_EqPredicate()) +.. ocv:function:: template int partition( const vector<_Tp>& vec, vector& labels, _EqPredicate predicate=_EqPredicate()) :param vec: Set of elements stored as a vector. :param labels: Output vector of labels. It contains as many elements as ``vec``. Each label ``labels[i]`` is a 0-based cluster index of ``vec[i]`` . - + :param predicate: Equivalence predicate (pointer to a boolean function of two arguments or an instance of the class that has the method ``bool operator()(const _Tp& a, const _Tp& b)`` ). The predicate returns ``true`` when the elements are certainly in the same class, and returns ``false`` if they may or may not be in the same class. The generic function ``partition`` implements an @@ -76,4 +74,4 @@ http://en.wikipedia.org/wiki/Disjoint-set_data_structure . The function returns the number of equivalency classes. -.. [Arthur2007] Arthur and S. Vassilvitskii “k-means++: the advantages of careful seeding”, Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms, 2007 +.. [Arthur2007] Arthur and S. Vassilvitskii. k-means++: the advantages of careful seeding, Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms, 2007 diff --git a/modules/core/doc/drawing_functions.rst b/modules/core/doc/drawing_functions.rst index 9985c0073a..26edd8cfe5 100644 --- a/modules/core/doc/drawing_functions.rst +++ b/modules/core/doc/drawing_functions.rst @@ -68,7 +68,7 @@ Clips the line against the image rectangle. :param imgSize: Image size. The image rectangle is ``Rect(0, 0, imgSize.width, imgSize.height)`` . - :param imgSize: Image rectangle.?? why do you list the same para twice?? + :param imgRect: Image rectangle. :param pt1: First line point. @@ -137,9 +137,9 @@ Approximates an elliptic arc with a polyline. :param center: Center of the arc. :param axes: Half-sizes of the arc. See the :ocv:func:`ellipse` for details. - + :param angle: Rotation angle of the ellipse in degrees. See the :ocv:func:`ellipse` for details. - + :param startAngle: Starting angle of the elliptic arc in degrees. :param endAngle: Ending angle of the elliptic arc in degrees. @@ -315,6 +315,7 @@ The function initializes the font structure that can be passed to text rendering .. seealso:: :ocv:cfunc:`PutText` +.. _Line: line -------- diff --git a/modules/core/doc/dynamic_structures.rst b/modules/core/doc/dynamic_structures.rst index a92f95e2a3..de4f19bab9 100644 --- a/modules/core/doc/dynamic_structures.rst +++ b/modules/core/doc/dynamic_structures.rst @@ -176,6 +176,8 @@ The structure ``CvGraphScanner`` is used for depth-first graph traversal. See di CvTreeNodeIterator ------------------ +.. ocv:struct:: CvTreeNodeIterator + The structure ``CvTreeNodeIterator`` is used to traverse trees of sequences. ClearGraph diff --git a/modules/core/doc/old_basic_structures.rst b/modules/core/doc/old_basic_structures.rst index 4e0c189752..d0bc05fc79 100644 --- a/modules/core/doc/old_basic_structures.rst +++ b/modules/core/doc/old_basic_structures.rst @@ -544,13 +544,13 @@ Converts one array to another with optional linear transformation. .. ocv:pyoldfunction:: cv.ConvertScale(src, dst, scale=1.0, shift=0.0)-> None .. ocv:pyoldfunction:: cv.Convert(src, dst)-> None -:: + :: - #define cvCvtScale cvConvertScale - #define cvScale cvConvertScale - #define cvConvert(src, dst ) cvConvertScale((src), (dst), 1, 0 ) + #define cvCvtScale cvConvertScale + #define cvScale cvConvertScale + #define cvConvert(src, dst ) cvConvertScale((src), (dst), 1, 0 ) -.. + .. :param src: Source array @@ -1729,7 +1729,7 @@ For example, `NumPy `_ arrays support the array interfa .. code-block::python - >>> import cv, numpy + >>> import cv2.cv as cv, numpy >>> a = numpy.ones((480, 640)) >>> mat = cv.fromarray(a) >>> print cv.GetDims(mat), cv.CV_MAT_CN(cv.GetElemType(mat)) diff --git a/modules/core/doc/operations_on_arrays.rst b/modules/core/doc/operations_on_arrays.rst index b29ae60115..227ee810ca 100644 --- a/modules/core/doc/operations_on_arrays.rst +++ b/modules/core/doc/operations_on_arrays.rst @@ -1814,24 +1814,26 @@ mixChannels ----------- Copies specified channels from input arrays to the specified channels of output arrays. -.. ocv:function:: void mixChannels(const Mat* srcv, int nsrc, Mat* dstv, int ndst, const int* fromTo, size_t npairs) +.. ocv:function:: void mixChannels(const Mat* src, int nsrc, Mat* dst, int ndst, const int* fromTo, size_t npairs) -.. ocv:function:: void mixChannels(const vector& srcv, vector& dstv, const int* fromTo, int npairs) +.. ocv:function:: void mixChannels(const vector& src, vector& dst, const int* fromTo, int npairs) .. ocv:pyfunction:: cv2.mixChannels(src, dst, fromTo) -> None .. ocv:cfunction:: void cvMixChannels(const CvArr** src, int srcCount, CvArr** dst, int dstCount, const int* fromTo, int pairCount) .. ocv:pyoldfunction:: cv.MixChannels(src, dst, fromTo) -> None - :param srcv: Input array or vector of matrices. All the matrices must have the same size and the same depth. + :param src: Input array or vector of matrices. All the matrices must have the same size and the same depth. - :param nsrc: Number of elements in ``srcv`` . + :param nsrc: Number of matrices in ``src`` . - :param dstv: Output array or vector of matrices. All the matrices *must be allocated* . Their size and depth must be the same as in ``srcv[0]`` . + :param dst: Output array or vector of matrices. All the matrices *must be allocated* . Their size and depth must be the same as in ``src[0]`` . - :param ndst: Number of elements in ``dstv`` . + :param ndst: Number of matrices in ``dst`` . - :param fromTo: Array of index pairs specifying which channels are copied and where. ``fromTo[k*2]`` is a 0-based index of the input channel in ``srcv`` . ``fromTo[k*2+1]`` is an index of the output channel in ``dstv`` . The continuous channel numbering is used: the first input image channels are indexed from ``0`` to ``srcv[0].channels()-1`` , the second input image channels are indexed from ``srcv[0].channels()`` to ``srcv[0].channels() + srcv[1].channels()-1``, and so on. The same scheme is used for the output image channels. As a special case, when ``fromTo[k*2]`` is negative, the corresponding output channel is filled with zero ``npairs`` . + :param fromTo: Array of index pairs specifying which channels are copied and where. ``fromTo[k*2]`` is a 0-based index of the input channel in ``src`` . ``fromTo[k*2+1]`` is an index of the output channel in ``dst`` . The continuous channel numbering is used: the first input image channels are indexed from ``0`` to ``src[0].channels()-1`` , the second input image channels are indexed from ``src[0].channels()`` to ``src[0].channels() + src[1].channels()-1``, and so on. The same scheme is used for the output image channels. As a special case, when ``fromTo[k*2]`` is negative, the corresponding output channel is filled with zero . + + :param npairs: Number of index pairs in ``fromTo``. The functions ``mixChannels`` provide an advanced mechanism for shuffling image channels. @@ -2161,13 +2163,13 @@ PCA constructors :param data: Input samples stored as matrix rows or matrix columns. - :param mean: Optional mean value. If the matrix is empty ( ``Mat()`` ), the mean is computed from the data. + :param mean: Optional mean value. If the matrix is empty ( ``noArray()`` ), the mean is computed from the data. :param flags: Operation flags. Currently the parameter is only used to specify the data layout. - * **CV_PCA_DATA_AS_ROWS** indicates that the input samples are stored as matrix rows. + * **CV_PCA_DATA_AS_ROW** indicates that the input samples are stored as matrix rows. - * **CV_PCA_DATA_AS_COLS** indicates that the input samples are stored as matrix columns. + * **CV_PCA_DATA_AS_COL** indicates that the input samples are stored as matrix columns. :param maxComponents: Maximum number of components that PCA should retain. By default, all the components are retained. @@ -2186,13 +2188,13 @@ Performs Principal Component Analysis of the supplied dataset. :param data: Input samples stored as the matrix rows or as the matrix columns. - :param mean: Optional mean value. If the matrix is empty ( ``Mat()`` ), the mean is computed from the data. + :param mean: Optional mean value. If the matrix is empty ( ``noArray()`` ), the mean is computed from the data. :param flags: Operation flags. Currently the parameter is only used to specify the data layout. - * **CV_PCA_DATA_AS_ROWS** indicates that the input samples are stored as matrix rows. + * **CV_PCA_DATA_AS_ROW** indicates that the input samples are stored as matrix rows. - * **CV_PCA_DATA_AS_COLS** indicates that the input samples are stored as matrix columns. + * **CV_PCA_DATA_AS_COL** indicates that the input samples are stored as matrix columns. :param maxComponents: Maximum number of components that PCA should retain. By default, all the components are retained. @@ -2212,9 +2214,9 @@ Projects vector(s) to the principal component subspace. .. ocv:pyfunction:: cv2.PCAProject(vec, mean, eigenvectors[, result]) -> result - :param vec: Input vector(s). They must have the same dimensionality and the same layout as the input data used at PCA phase. That is, if ``CV_PCA_DATA_AS_ROWS`` are specified, then ``vec.cols==data.cols`` (vector dimensionality) and ``vec.rows`` is the number of vectors to project. The same is true for the ``CV_PCA_DATA_AS_COLS`` case. + :param vec: Input vector(s). They must have the same dimensionality and the same layout as the input data used at PCA phase. That is, if ``CV_PCA_DATA_AS_ROW`` are specified, then ``vec.cols==data.cols`` (vector dimensionality) and ``vec.rows`` is the number of vectors to project. The same is true for the ``CV_PCA_DATA_AS_COL`` case. - :param result: Output vectors. In case of ``CV_PCA_DATA_AS_COLS`` , the output matrix has as many columns as the number of input vectors. This means that ``result.cols==vec.cols`` and the number of rows match the number of principal components (for example, ``maxComponents`` parameter passed to the constructor). + :param result: Output vectors. In case of ``CV_PCA_DATA_AS_COL`` , the output matrix has as many columns as the number of input vectors. This means that ``result.cols==vec.cols`` and the number of rows match the number of principal components (for example, ``maxComponents`` parameter passed to the constructor). The methods project one or more vectors to the principal component subspace, where each vector projection is represented by coefficients in the principal component basis. The first form of the method returns the matrix that the second form writes to the result. So the first form can be used as a part of expression while the second form can be more efficient in a processing loop. @@ -2398,7 +2400,7 @@ For some values of ``p`` , such as integer values, 0.5 and -0.5, specialized fas RNG --- -.. ocv:class: RNG +.. ocv:class:: RNG Random number generator. It encapsulates the state (currently, a 64-bit integer) and has methods to return scalar random values and to fill arrays with random values. Currently it supports uniform and Gaussian (normal) distributions. The generator uses Multiply-With-Carry algorithm, introduced by G. Marsaglia ( http://en.wikipedia.org/wiki/Multiply-with-carry diff --git a/modules/core/doc/utility_and_system_functions_and_macros.rst b/modules/core/doc/utility_and_system_functions_and_macros.rst index 0612a14efe..1a19daef74 100644 --- a/modules/core/doc/utility_and_system_functions_and_macros.rst +++ b/modules/core/doc/utility_and_system_functions_and_macros.rst @@ -187,7 +187,7 @@ Signals an error and raises an exception. :param exc: Exception to throw. :param code: Error code. Normally, it is a negative value. The list of pre-defined error codes can be found in ``cxerror.h`` . - + :param msg: Text of the error message. :param args: ``printf`` -like formatted error message in parentheses. @@ -268,8 +268,8 @@ The function deallocates the buffer allocated with :ocv:func:`fastMalloc` . If N format ----------- -Returns a text string formatted using the ``printf`` -like expression. +------ +Returns a text string formatted using the ``printf``\ -like expression. .. ocv:function:: string format( const char* fmt, ... ) @@ -280,6 +280,28 @@ The function acts like ``sprintf`` but forms and returns an STL string. It can +checkHardwareSupport +-------------------- +Returns true if the specified feature is supported by the host hardware. + +.. ocv:function:: bool checkHardwareSupport(int feature) +.. ocv:cfunction:: int cvCheckHardwareSupport(int feature) +.. ocv:pyfunction:: checkHardwareSupport(feature) -> Bool + + :param feature: The feature of interest, one of: + + * ``CV_CPU_MMX`` - MMX + * ``CV_CPU_SSE`` - SSE + * ``CV_CPU_SSE2`` - SSE 2 + * ``CV_CPU_SSE3`` - SSE 3 + * ``CV_CPU_SSSE3`` - SSSE 3 + * ``CV_CPU_SSE4_1`` - SSE 4.1 + * ``CV_CPU_SSE4_2`` - SSE 4.2 + * ``CV_CPU_POPCNT`` - POPCOUNT + * ``CV_CPU_AVX`` - AVX + +The function returns true if the host hardware supports the specified feature. When user calls ``setUseOptimized(false)``, the subsequent calls to ``checkHardwareSupport()`` will return false until ``setUseOptimized(true)`` is called. This way user can dynamically switch on and off the optimized code in OpenCV. + getNumThreads ----------------- Returns the number of threads used by OpenCV. @@ -289,8 +311,8 @@ Returns the number of threads used by OpenCV. The function returns the number of threads that is used by OpenCV. .. seealso:: -:ocv:func:`setNumThreads`, -:ocv:func:`getThreadNum` + :ocv:func:`setNumThreads`, + :ocv:func:`getThreadNum` @@ -303,8 +325,8 @@ Returns the index of the currently executed thread. The function returns a 0-based index of the currently executed thread. The function is only valid inside a parallel OpenMP region. When OpenCV is built without OpenMP support, the function always returns 0. .. seealso:: -:ocv:func:`setNumThreads`, -:ocv:func:`getNumThreads` . + :ocv:func:`setNumThreads`, + :ocv:func:`getNumThreads` . @@ -388,8 +410,8 @@ Sets the number of threads used by OpenCV. The function sets the number of threads used by OpenCV in parallel OpenMP regions. If ``nthreads=0`` , the function uses the default number of threads that is usually equal to the number of the processing cores. .. seealso:: -:ocv:func:`getNumThreads`, -:ocv:func:`getThreadNum` + :ocv:func:`getNumThreads`, + :ocv:func:`getThreadNum` diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index dc75f4d514..9e1d8556dd 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -216,7 +216,7 @@ CV_EXPORTS int getThreadNum(); before and after the function call. The granularity of ticks depends on the hardware and OS used. Use cv::getTickFrequency() to convert ticks to seconds. */ -CV_EXPORTS int64 getTickCount(); +CV_EXPORTS_W int64 getTickCount(); /*! Returns the number of ticks per seconds. @@ -240,7 +240,7 @@ CV_EXPORTS_W double getTickFrequency(); one can accurately measure the execution time of very small code fragments, for which cv::getTickCount() granularity is not enough. */ -CV_EXPORTS int64 getCPUTickCount(); +CV_EXPORTS_W int64 getCPUTickCount(); /*! Returns SSE etc. support status @@ -263,6 +263,9 @@ CV_EXPORTS int64 getCPUTickCount(); */ CV_EXPORTS_W bool checkHardwareSupport(int feature); +//! returns the number of CPUs (including hyper-threading) +CV_EXPORTS_W int getNumberOfCPUs(); + /*! Allocates memory buffer @@ -589,6 +592,8 @@ public: explicit Vec(const _Tp* values); Vec(const Vec<_Tp, cn>& v); + Vec<_Tp, cn>& operator =(const Matx<_Tp, cn, 1>& m); + static Vec all(_Tp alpha); //! per-element multiplication @@ -610,6 +615,10 @@ public: _Tp& operator[](int i); const _Tp& operator ()(int i) const; _Tp& operator ()(int i); + + Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp); + Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp); + template Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp); }; @@ -1267,6 +1276,7 @@ public: template _InputArray(const vector >& vec); _InputArray(const vector& vec); template _InputArray(const Matx<_Tp, m, n>& matx); + _InputArray(const Scalar& s); _InputArray(const double& val); virtual Mat getMat(int i=-1) const; virtual void getMatVector(vector& mv) const; @@ -1327,6 +1337,7 @@ typedef InputArray InputArrayOfArrays; typedef const _OutputArray& OutputArray; typedef OutputArray OutputArrayOfArrays; typedef OutputArray InputOutputArray; +typedef OutputArray InputOutputArrayOfArrays; CV_EXPORTS OutputArray noArray(); @@ -2031,13 +2042,15 @@ CV_EXPORTS_W void merge(const vector& mv, OutputArray dst); //! copies each plane of a multi-channel array to a dedicated array CV_EXPORTS void split(const Mat& src, Mat* mvbegin); //! copies each plane of a multi-channel array to a dedicated array -CV_EXPORTS_W void split(const Mat& m, vector& mv); +CV_EXPORTS_W void split(const Mat& m, CV_OUT vector& mv); //! copies selected channels from the input arrays to the selected channels of the output arrays CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs); CV_EXPORTS void mixChannels(const vector& src, vector& dst, const int* fromTo, size_t npairs); +CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputArrayOfArrays dst, + const vector& fromTo); //! extracts a single channel from src (coi is 0-based index) CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi); @@ -2147,6 +2160,15 @@ CV_EXPORTS_W double invert(InputArray src, OutputArray dst, int flags=DECOMP_LU) //! solves linear system or a least-square problem CV_EXPORTS_W bool solve(InputArray src1, InputArray src2, OutputArray dst, int flags=DECOMP_LU); + +enum +{ + SORT_EVERY_ROW=0, + SORT_EVERY_COLUMN=1, + SORT_ASCENDING=0, + SORT_DESCENDING=16 +}; + //! sorts independently each matrix row or each matrix column CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags); //! sorts independently each matrix row or each matrix column @@ -2162,6 +2184,19 @@ CV_EXPORTS bool eigen(InputArray src, OutputArray eigenvalues, int lowindex=-1, CV_EXPORTS bool eigen(InputArray src, OutputArray eigenvalues, OutputArray eigenvectors, int lowindex=-1, int highindex=-1); +CV_EXPORTS_W bool eigen(InputArray src, bool computeEigenvectors, + OutputArray eigenvalues, OutputArray eigenvectors); + +enum +{ + COVAR_SCRAMBLED=0, + COVAR_NORMAL=1, + COVAR_USE_AVG=2, + COVAR_SCALE=4, + COVAR_ROWS=8, + COVAR_COLS=16 +}; + //! computes covariation matrix of a set of samples CV_EXPORTS void calcCovarMatrix( const Mat* samples, int nsamples, Mat& covar, Mat& mean, int flags, int ctype=CV_64F); @@ -2246,6 +2281,16 @@ public: Mat mean; //!< mean value subtracted before the projection and added after the back projection }; +CV_EXPORTS_W void PCACompute(InputArray data, CV_OUT InputOutputArray mean, + OutputArray eigenvectors, int maxComponents=0); + +CV_EXPORTS_W void PCAProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + +CV_EXPORTS_W void PCABackProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + + /*! Singular Value Decomposition class @@ -2295,6 +2340,14 @@ public: Mat u, w, vt; }; +//! computes SVD of src +CV_EXPORTS_W void SVDecomp( InputArray src, CV_OUT OutputArray w, + CV_OUT OutputArray u, CV_OUT OutputArray vt, int flags=0 ); + +//! performs back substitution for the previously computed SVD +CV_EXPORTS_W void SVBackSubst( InputArray w, InputArray u, InputArray vt, + InputArray rhs, CV_OUT OutputArray dst ); + //! computes Mahalanobis distance between two vectors: sqrt((v1-v2)'*icovar*(v1-v2)), where icovar is the inverse covariation matrix CV_EXPORTS_W double Mahalanobis(InputArray v1, InputArray v2, InputArray icovar); //! a synonym for Mahalanobis @@ -2342,6 +2395,7 @@ CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev //! shuffles the input array elements CV_EXPORTS void randShuffle(InputOutputArray dst, double iterFactor=1., RNG* rng=0); +CV_EXPORTS_AS(randShuffle) void randShuffle_(InputOutputArray dst, double iterFactor=1.); //! draws the line segment (pt1, pt2) in the image CV_EXPORTS_W void line(Mat& img, Point pt1, Point pt2, const Scalar& color, @@ -2376,6 +2430,9 @@ CV_EXPORTS_W void ellipse(Mat& img, const RotatedRect& box, const Scalar& color, CV_EXPORTS void fillConvexPoly(Mat& img, const Point* pts, int npts, const Scalar& color, int lineType=8, int shift=0); +CV_EXPORTS_W void fillConvexPoly(InputOutputArray img, InputArray points, + const Scalar& color, int lineType=8, + int shift=0); //! fills an area bounded by one or more polygons CV_EXPORTS void fillPoly(Mat& img, const Point** pts, @@ -2383,16 +2440,24 @@ CV_EXPORTS void fillPoly(Mat& img, const Point** pts, const Scalar& color, int lineType=8, int shift=0, Point offset=Point() ); +CV_EXPORTS_W void fillPoly(InputOutputArray img, InputArrayOfArrays pts, + const Scalar& color, int lineType=8, int shift=0, + Point offset=Point() ); + //! draws one or more polygonal curves CV_EXPORTS void polylines(Mat& img, const Point** pts, const int* npts, int ncontours, bool isClosed, const Scalar& color, int thickness=1, int lineType=8, int shift=0 ); +CV_EXPORTS_W void polylines(InputOutputArray img, InputArrayOfArrays pts, + bool isClosed, const Scalar& color, + int thickness=1, int lineType=8, int shift=0 ); + //! clips the line segment by the rectangle Rect(0, 0, imgSize.width, imgSize.height) CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2); //! clips the line segment by the rectangle imgRect -CV_EXPORTS_W bool clipLine(Rect imgRect, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2); +CV_EXPORTS_W bool clipLine(Rect imgRect, CV_OUT CV_IN_OUT Point& pt1, CV_OUT CV_IN_OUT Point& pt2); /*! Line iterator class @@ -4167,78 +4232,108 @@ protected: #endif /*! - Command Line Parser - - The class is used for reading command arguments. - Supports the following syntax: - //-k=10 --key --db=-10.11 -key1 argument --inputFile=lena.jpg - CommandLineParser parser(argc, argv); - int k = parser.get("k", -1); //these methods also work - double db = parser.get("db"); //with and type - bool key = parser.get("key"); - bool key1 = parser.get("key1"); The method return 'true', if 'key' was defined in command line - " and it will return 'false' otherwise.> - string argument = parser.get("0"); - It also works with 'int', 'unsigned int', 'double' and 'float' types. - string inputFile = parser.get("inputFile"); +"\nThe CommandLineParser class is designed for command line arguments parsing\n" + "Keys map: \n" + "Before you start to work with CommandLineParser you have to create a map for keys.\n" + " It will look like this\n" + " const char* keys =\n" + " {\n" + " { s| string| 123asd |string parameter}\n" + " { d| digit | 100 |digit parameter }\n" + " { c|noCamera|false |without camera }\n" + " { 1| |some text|help }\n" + " { 2| |333 |another help }\n" + " };\n" + "Usage syntax: \n" + " \"{\" - start of parameter string.\n" + " \"}\" - end of parameter string\n" + " \"|\" - separator between short name, full name, default value and help\n" + "Supported syntax: \n" + " --key1=arg1 \n" + " -key2=arg2 \n" + "Usage: \n" + " Imagine that the input parameters are next:\n" + " -s=string_value --digit=250 --noCamera lena.jpg 10000\n" + " CommandLineParser parser(argc, argv, keys) - create a parser object\n" + " parser.get(\"s\" or \"string\") will return you first parameter value\n" + " parser.get(\"s\", false or \"string\", false) will return you first parameter value\n" + " without spaces in end and begin\n" + " parser.get(\"d\" or \"digit\") will return you second parameter value.\n" + " It also works with 'unsigned int', 'double', and 'float' types>\n" + " parser.get(\"c\" or \"noCamera\") will return you true .\n" + " If you enter this key in commandline>\n" + " It return you false otherwise.\n" + " parser.get(\"1\") will return you the first argument without parameter (lena.jpg) \n" + " parser.get(\"2\") will return you the second argument without parameter (10000)\n" + " It also works with 'unsigned int', 'double', and 'float' types \n" */ class CV_EXPORTS CommandLineParser { public: - //! the default constructor - CommandLineParser(int argc, const char* argv[]); + //! the default constructor + CommandLineParser(int argc, const char* argv[], const char* key_map); - //! get parameter, if parameter is not given get default parameter - template - _Tp get(const std::string& name, const _Tp& default_value = _Tp()) + //! get parameter, you can choose: delete spaces in end and begin or not + template + _Tp get(const std::string& name, bool space_delete=true) + { + if (!has(name)) { - std::string str = getString(name); - if (!has(name)) - return default_value; - return analyzeValue<_Tp>(str); + return _Tp(); } + std::string str = getString(name); + return analizeValue<_Tp>(str, space_delete); + } + + //! print short name, full name, current value and help for all params + void printParams(); protected: - std::map data; - std::string getString(const std::string& name) const; + std::map > data; + std::string getString(const std::string& name); - bool has(const std::string& keys) const; + bool has(const std::string& keys); - template - static _Tp getData(const std::string& str) - { - _Tp res; - std::stringstream s1(str); - s1 >> res; - return res; - } + template + _Tp analizeValue(const std::string& str, bool space_delete=false); - template - _Tp fromStringNumber(const std::string& str);//the default conversion function for numbers + template + static _Tp getData(const std::string& str) + { + _Tp res; + std::stringstream s1(str); + s1 >> res; + return res; + } + + template + _Tp fromStringNumber(const std::string& str);//the default conversion function for numbers - template - _Tp analyzeValue(const std::string& str); }; - template<> CV_EXPORTS - bool CommandLineParser::get(const std::string& name, const bool& default_value); - template<> CV_EXPORTS - std::string CommandLineParser::analyzeValue(const std::string& str); +template<> CV_EXPORTS +bool CommandLineParser::get(const std::string& name, bool space_delete); - template<> CV_EXPORTS - int CommandLineParser::analyzeValue(const std::string& str); +template<> CV_EXPORTS +std::string CommandLineParser::analizeValue(const std::string& str, bool space_delete); - template<> CV_EXPORTS - unsigned CommandLineParser::analyzeValue(const std::string& str); +template<> CV_EXPORTS +int CommandLineParser::analizeValue(const std::string& str, bool space_delete); - template<> CV_EXPORTS - float CommandLineParser::analyzeValue(const std::string& str); +template<> CV_EXPORTS +unsigned CommandLineParser::analizeValue(const std::string& str, bool space_delete); - template<> CV_EXPORTS - double CommandLineParser::analyzeValue(const std::string& str); +template<> CV_EXPORTS +float CommandLineParser::analizeValue(const std::string& str, bool space_delete); + +template<> CV_EXPORTS +double CommandLineParser::analizeValue(const std::string& str, bool space_delete); } diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index a69673820f..6f444e4ed2 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -338,6 +338,7 @@ inline Mat Mat::colRange(const Range& r) const inline Mat Mat::diag(const Mat& d) { + CV_Assert( d.cols == 1 ); Mat m(d.rows, d.rows, d.type(), Scalar(0)), md = m.diag(); d.copyTo(md); return m; @@ -675,7 +676,12 @@ template inline Mat::operator Matx<_Tp, m, n>() cons template inline void Mat::push_back(const _Tp& elem) { - CV_Assert(DataType<_Tp>::type == type() && cols == 1 + if( !data ) + { + *this = Mat(1, 1, DataType<_Tp>::type, (void*)&elem).clone(); + return; + } + CV_Assert(DataType<_Tp>::type == type() && cols == 1 /* && dims == 2 (cols == 1 implies dims == 2) */); uchar* tmp = dataend + step[0]; if( !isSubmatrix() && isContinuous() && tmp <= datalimit ) @@ -1098,18 +1104,21 @@ process( const Mat_& m1, const Mat_& m2, Mat_& m3, Op op ) /////////////////////////////// Input/Output Arrays ///////////////////////////////// -template _InputArray::_InputArray(const vector<_Tp>& vec) +template inline _InputArray::_InputArray(const vector<_Tp>& vec) : flags(STD_VECTOR + DataType<_Tp>::type), obj((void*)&vec) {} -template _InputArray::_InputArray(const vector >& vec) +template inline _InputArray::_InputArray(const vector >& vec) : flags(STD_VECTOR_VECTOR + DataType<_Tp>::type), obj((void*)&vec) {} -template _InputArray::_InputArray(const Matx<_Tp, m, n>& mtx) +template inline _InputArray::_InputArray(const Matx<_Tp, m, n>& mtx) : flags(MATX + DataType<_Tp>::type), obj((void*)&mtx), sz(n, m) {} -template _OutputArray::_OutputArray(vector<_Tp>& vec) : _InputArray(vec) {} -template _OutputArray::_OutputArray(vector >& vec) : _InputArray(vec) {} -template _OutputArray::_OutputArray(Matx<_Tp, m, n>& mtx) : _InputArray(mtx) {} +inline _InputArray::_InputArray(const Scalar& s) + : flags(MATX + CV_64F), obj((void*)&s), sz(1, 4) {} + +template inline _OutputArray::_OutputArray(vector<_Tp>& vec) : _InputArray(vec) {} +template inline _OutputArray::_OutputArray(vector >& vec) : _InputArray(vec) {} +template inline _OutputArray::_OutputArray(Matx<_Tp, m, n>& mtx) : _InputArray(mtx) {} //////////////////////////////////// Matrix Expressions ///////////////////////////////////////// @@ -1303,6 +1312,37 @@ template static inline MatExpr max(double s, const Mat_<_Tp>& a) { return cv::max((const Mat&)a, s); } + +template static inline void min(const Mat_<_Tp>& a, const Mat_<_Tp>& b, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, (const Mat&)b, (Mat&)c); +} + +template static inline void min(const Mat_<_Tp>& a, double s, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, s, (Mat&)c); +} + +template static inline void min(double s, const Mat_<_Tp>& a, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, s, (Mat&)c); +} + +template static inline void max(const Mat_<_Tp>& a, const Mat_<_Tp>& b, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, (const Mat&)b, (Mat&)c); +} + +template static inline void max(const Mat_<_Tp>& a, double s, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, s, (Mat&)c); +} + +template static inline void max(double s, const Mat_<_Tp>& a, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, s, (Mat&)c); +} + CV_EXPORTS MatExpr operator & (const Mat& a, const Mat& b); CV_EXPORTS MatExpr operator & (const Mat& a, const Scalar& s); diff --git a/modules/core/include/opencv2/core/operations.hpp b/modules/core/include/opencv2/core/operations.hpp index 60b4926c48..ee37b706da 100644 --- a/modules/core/include/opencv2/core/operations.hpp +++ b/modules/core/include/opencv2/core/operations.hpp @@ -625,14 +625,14 @@ Matx<_Tp, m, n> operator * (const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b) template static inline Point_<_Tp> operator * (const Matx<_Tp, 2, 2>& a, const Point_<_Tp>& b) { - return Point_<_Tp>(a*Vec<_Tp,2>(b)); + return Point_<_Tp>(a*Vec<_Tp,2>(b.x,b.y)); } template static inline Point3_<_Tp> operator * (const Matx<_Tp, 3, 3>& a, const Point3_<_Tp>& b) { - return Point3_<_Tp>(a*Vec<_Tp,3>(b)); + return Point3_<_Tp>(a*Vec<_Tp,3>(b.x,b.y,b.z)); } @@ -653,7 +653,7 @@ Matx<_Tp, 4, 1> operator * (const Matx<_Tp, 4, 4>& a, const Point3_<_Tp>& b) template static inline Scalar operator * (const Matx<_Tp, 4, 4>& a, const Scalar& b) { - return Scalar(a*Matx<_Tp, 4, 1>(b)); + return Scalar(a*Matx<_Tp, 4, 1>(b[0],b[1],b[2],b[3])); } @@ -1017,10 +1017,33 @@ template inline Vec<_Tp, cn>::Vec(const _Tp* values) {} -template inline Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& v) - : Matx<_Tp, cn, 1>(v.val) +template inline Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m) + : Matx<_Tp, cn, 1>(m.val) {} +template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp op) +: Matx<_Tp, cn, 1>(a, b, op) +{} + +template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp op) +: Matx<_Tp, cn, 1>(a, b, op) +{} + +template template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp op) +: Matx<_Tp, cn, 1>(a, alpha, op) +{} + +template inline +Vec<_Tp, cn>& Vec<_Tp, cn>::operator = (const Matx<_Tp, cn, 1>& m) +{ + for( int i = 0; i < cn; i++ ) + this->val[i] = m.val[i]; + return *this; +} + template inline Vec<_Tp, cn> Vec<_Tp, cn>::all(_Tp alpha) { Vec v; @@ -1101,100 +1124,75 @@ operator -= (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b) template static inline Vec<_Tp, cn> operator + (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b) { - Vec<_Tp, cn> c = a; - return c += b; + return Vec<_Tp, cn>(a, b, Matx_AddOp()); } template static inline Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b) { - Vec<_Tp, cn> c = a; - return c -= b; + return Vec<_Tp, cn>(a, b, Matx_SubOp()); } template static inline -Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, _Tp alpha) +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, int alpha) { for( int i = 0; i < cn; i++ ) - a[i] *= alpha; + a[i] = saturate_cast<_Tp>(a[i]*alpha); return a; } -template static inline -Vec& operator *= (Vec& a, double alpha) +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, float alpha) { for( int i = 0; i < cn; i++ ) - a[i] *= (float)alpha; - return a; -} - -template static inline -Vec& operator *= (Vec& a, int alpha) -{ - for( int i = 0; i < cn; i++ ) - a[i] *= (float)alpha; + a[i] = saturate_cast<_Tp>(a[i]*alpha); return a; } -template static inline Vec<_Tp, cn> -operator * (const Vec<_Tp, cn>& a, _Tp alpha) +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, double alpha) { - Vec<_Tp, cn> c = a; - return c *= alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + + +template static inline Vec<_Tp, cn> +operator * (const Vec<_Tp, cn>& a, int alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); } template static inline Vec<_Tp, cn> -operator * (_Tp alpha, const Vec<_Tp, cn>& a) +operator * (int alpha, const Vec<_Tp, cn>& a) { - Vec<_Tp, cn> c = a; - return c *= alpha; + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); } -template static inline Vec -operator * (double alpha, const Vec& a) +template static inline Vec<_Tp, cn> +operator * (const Vec<_Tp, cn>& a, float alpha) { - Vec c = a; - return c *= (float)alpha; + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); } -template static inline Vec -operator * (const Vec& a, double alpha) +template static inline Vec<_Tp, cn> +operator * (float alpha, const Vec<_Tp, cn>& a) { - Vec c = a; - return c *= (float)alpha; + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); } -template static inline Vec -operator * (int alpha, const Vec& a) +template static inline Vec<_Tp, cn> +operator * (const Vec<_Tp, cn>& a, double alpha) { - Vec c = a; - return c *= (float)alpha; + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); } -template static inline Vec -operator * (const Vec& a, int alpha) +template static inline Vec<_Tp, cn> +operator * (double alpha, const Vec<_Tp, cn>& a) { - Vec c = a; - return c *= (float)alpha; -} - -template static inline Vec<_Tp, 4> -operator * (const Vec<_Tp, 4>& a, const Vec<_Tp, 4>& b) -{ - return Vec<_Tp, 4>(saturate_cast<_Tp>(a[0]*b[0] - a[1]*b[1] - a[2]*b[2] - a[3]*b[3]), - saturate_cast<_Tp>(a[0]*b[1] + a[1]*b[0] + a[2]*b[3] - a[3]*b[2]), - saturate_cast<_Tp>(a[0]*b[2] - a[1]*b[3] + a[2]*b[0] - a[3]*b[1]), - saturate_cast<_Tp>(a[0]*b[3] + a[1]*b[2] - a[2]*b[1] - a[3]*b[0])); -} - - -template static inline Vec<_Tp, 4>& -operator *= (Vec<_Tp, 4>& a, const Vec<_Tp, 4>& b) -{ - a = a*b; - return a; -} - + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} template static inline Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a) @@ -1203,7 +1201,7 @@ operator - (const Vec<_Tp, cn>& a) for( int i = 0; i < cn; i++ ) t.val[i] = saturate_cast<_Tp>(-a.val[i]); return t; } - + template<> inline Vec Vec::cross(const Vec& v) const { return Vec(val[1]*v.val[2] - val[2]*v.val[1], @@ -2000,7 +1998,7 @@ static inline bool operator !(const Range& r) static inline Range operator & (const Range& r1, const Range& r2) { - Range r(std::max(r1.start, r2.start), std::min(r2.start, r2.end)); + Range r(std::max(r1.start, r2.start), std::min(r1.end, r2.end)); r.end = std::max(r.end, r.start); return r; } @@ -2780,7 +2778,8 @@ public: size_t remaining = it->remaining, cn = DataType<_Tp>::channels; int _fmt = DataType<_Tp>::fmt; char fmt[] = { (char)((_fmt>>8)+'1'), (char)_fmt, '\0' }; - count = std::min(count, remaining/cn); + size_t remaining1 = remaining/cn; + count = count < remaining1 ? count : remaining1; vec.resize(count); it->readRaw( string(fmt), (uchar*)&vec[0], count*sizeof(_Tp) ); } diff --git a/modules/core/include/opencv2/core/version.hpp b/modules/core/include/opencv2/core/version.hpp index b29c445cb2..0cd25ca8b3 100644 --- a/modules/core/include/opencv2/core/version.hpp +++ b/modules/core/include/opencv2/core/version.hpp @@ -49,7 +49,7 @@ #define CV_MAJOR_VERSION 2 #define CV_MINOR_VERSION 3 -#define CV_SUBMINOR_VERSION 0 +#define CV_SUBMINOR_VERSION 1 #define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR(__A) CVAUX_STR_EXP(__A) diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index fc9f6685d3..5f6c04f1a8 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -68,7 +68,9 @@ struct NOP {}; template void vBinOp8(const T* src1, size_t step1, const T* src2, size_t step2, T* dst, size_t step, Size sz) { +#if CV_SSE2 Op8 op8; +#endif Op op; for( ; sz.height--; src1 += step1/sizeof(src1[0]), @@ -117,7 +119,9 @@ template void vBinOp16(const T* src1, size_t step1, const T* src2, size_t step2, T* dst, size_t step, Size sz) { +#if CV_SSE2 Op16 op16; +#endif Op op; for( ; sz.height--; src1 += step1/sizeof(src1[0]), @@ -168,7 +172,9 @@ template void vBinOp32s(const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, Size sz) { +#if CV_SSE2 Op32 op32; +#endif Op op; for( ; sz.height--; src1 += step1/sizeof(src1[0]), @@ -223,7 +229,9 @@ template void vBinOp32f(const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, Size sz) { +#if CV_SSE2 Op32 op32; +#endif Op op; for( ; sz.height--; src1 += step1/sizeof(src1[0]), @@ -276,7 +284,9 @@ template void vBinOp64f(const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, Size sz) { +#if CV_SSE2 Op64 op64; +#endif Op op; for( ; sz.height--; src1 += step1/sizeof(src1[0]), @@ -1064,7 +1074,7 @@ void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst, { for( size_t j = 0; j < total; j += blocksize ) { - int bsz = (int)std::min(total - j, blocksize); + int bsz = (int)MIN(total - j, blocksize); func( ptrs[0], 0, ptrs[1], 0, haveMask ? maskbuf : ptrs[2], 0, Size(bsz*c, 1), 0 ); if( haveMask ) @@ -1096,7 +1106,7 @@ void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst, { for( size_t j = 0; j < total; j += blocksize ) { - int bsz = (int)std::min(total - j, blocksize); + int bsz = (int)MIN(total - j, blocksize); func( ptrs[0], 0, scbuf, 0, haveMask ? maskbuf : ptrs[1], 0, Size(bsz*c, 1), 0 ); if( haveMask ) @@ -1128,25 +1138,41 @@ static BinaryFunc minTab[] = void cv::bitwise_and(InputArray a, InputArray b, OutputArray c, InputArray mask) { - BinaryFunc f = and8u; + BinaryFunc f = +#ifdef HAVE_TEGRA_OPTIMIZATION + (BinaryFunc)tegra:: +#endif + and8u; binary_op(a, b, c, mask, &f, true); } void cv::bitwise_or(InputArray a, InputArray b, OutputArray c, InputArray mask) { - BinaryFunc f = or8u; + BinaryFunc f = +#ifdef HAVE_TEGRA_OPTIMIZATION + (BinaryFunc)tegra:: +#endif + or8u; binary_op(a, b, c, mask, &f, true); } void cv::bitwise_xor(InputArray a, InputArray b, OutputArray c, InputArray mask) { - BinaryFunc f = xor8u; + BinaryFunc f = +#ifdef HAVE_TEGRA_OPTIMIZATION + (BinaryFunc)tegra:: +#endif + xor8u; binary_op(a, b, c, mask, &f, true); } void cv::bitwise_not(InputArray a, OutputArray c, InputArray mask) { - BinaryFunc f = not8u; + BinaryFunc f = +#ifdef HAVE_TEGRA_OPTIMIZATION + (BinaryFunc)tegra:: +#endif + not8u; binary_op(a, a, c, mask, &f, true); } @@ -1291,7 +1317,7 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, uchar *buf, *maskbuf = 0, *buf1 = 0, *buf2 = 0, *wbuf = 0; size_t bufesz = (cvtsrc1 ? wsz : 0) + (cvtsrc2 || haveScalar ? wsz : 0) + (cvtdst ? wsz : 0) + (haveMask ? dsz : 0); - _dst.create(src1.dims, src1.size, src1.type()); + _dst.create(src1.dims, src1.size, dtype); Mat dst = _dst.getMat(); BinaryFunc func = tab[CV_MAT_DEPTH(wtype)]; @@ -1322,7 +1348,7 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, { for( size_t j = 0; j < total; j += blocksize ) { - int bsz = (int)std::min(total - j, blocksize); + int bsz = (int)MIN(total - j, blocksize); Size bszn(bsz*cn, 1); const uchar *sptr1 = ptrs[0], *sptr2 = ptrs[1]; uchar* dptr = ptrs[2]; @@ -1387,7 +1413,7 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, { for( size_t j = 0; j < total; j += blocksize ) { - int bsz = (int)std::min(total - j, blocksize); + int bsz = (int)MIN(total - j, blocksize); Size bszn(bsz*cn, 1); const uchar *sptr1 = ptrs[0]; const uchar* sptr2 = buf2; @@ -1427,6 +1453,20 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, } } +#ifdef HAVE_TEGRA_OPTIMIZATION +static BinaryFunc addTab[] = +{ + (BinaryFunc)tegra::add8u, (BinaryFunc)add8s, (BinaryFunc)add16u, (BinaryFunc)add16s, + (BinaryFunc)add32s, (BinaryFunc)add32f, (BinaryFunc)add64f, 0 +}; + +static BinaryFunc subTab[] = +{ + (BinaryFunc)tegra::sub8u, (BinaryFunc)sub8s, (BinaryFunc)sub16u, (BinaryFunc)sub16s, + (BinaryFunc)sub32s, (BinaryFunc)sub32f, (BinaryFunc)sub64f, 0 +}; + +#else static BinaryFunc addTab[] = { (BinaryFunc)add8u, (BinaryFunc)add8s, (BinaryFunc)add16u, (BinaryFunc)add16s, @@ -1438,6 +1478,7 @@ static BinaryFunc subTab[] = (BinaryFunc)sub8u, (BinaryFunc)sub8s, (BinaryFunc)sub16u, (BinaryFunc)sub16s, (BinaryFunc)sub32s, (BinaryFunc)sub32f, (BinaryFunc)sub64f, 0 }; +#endif static BinaryFunc absdiffTab[] = { @@ -2083,8 +2124,8 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op) if( kind1 == kind2 && src1.dims <= 2 && src2.dims <= 2 && src1.size() == src2.size() && src1.type() == src2.type() ) { - CV_Assert(src1.channels() == 1); - _dst.create(src1.size(), CV_8UC1); + int cn = src1.channels(); + _dst.create(src1.size(), CV_8UC(cn)); Mat dst = _dst.getMat(); Size sz = getContinuousSize(src1, src2, dst, src1.channels()); cmpTab[src1.depth()](src1.data, src1.step, src2.data, src2.step, dst.data, dst.step, sz, &op); @@ -2110,15 +2151,15 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op) haveScalar = true; } + int cn = src1.channels(), depth1 = src1.depth(), depth2 = src2.depth(); - if( cn != 1 ) - CV_Error( CV_StsUnsupportedFormat, "compare() can only process single-channel arrays" ); + _dst.create(src1.dims, src1.size, CV_8UC(cn)); + src1 = src1.reshape(1); src2 = src2.reshape(1); + Mat dst = _dst.getMat().reshape(1); + size_t esz = src1.elemSize(); size_t blocksize0 = (size_t)(BLOCK_SIZE + esz-1)/esz; - - _dst.create(src1.dims, src1.size, CV_8U); - Mat dst = _dst.getMat(); BinaryFunc func = cmpTab[depth1]; if( !haveScalar ) @@ -2181,7 +2222,7 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op) { for( size_t j = 0; j < total; j += blocksize ) { - int bsz = (int)std::min(total - j, blocksize); + int bsz = (int)MIN(total - j, blocksize); func( ptrs[0], 0, buf, 0, ptrs[1], 0, Size(bsz, 1), &op); ptrs[0] += bsz*esz; ptrs[1] += bsz; @@ -2387,7 +2428,7 @@ void cv::inRange(InputArray _src, InputArray _lowerb, { for( size_t j = 0; j < total; j += blocksize ) { - int bsz = (int)std::min(total - j, blocksize); + int bsz = (int)MIN(total - j, blocksize); size_t delta = bsz*esz; uchar *lptr = lbuf, *uptr = ubuf; if( !lbScalar ) diff --git a/modules/core/src/cmdparser.cpp b/modules/core/src/cmdparser.cpp index 012041ceea..f67f624ea3 100644 --- a/modules/core/src/cmdparser.cpp +++ b/modules/core/src/cmdparser.cpp @@ -1,4 +1,5 @@ #include "precomp.hpp" +#include "iostream" using namespace std; using namespace cv; @@ -6,27 +7,44 @@ using namespace cv; void helpParser() { printf("\nThe CommandLineParser class is designed for command line arguments parsing\n" + "Keys map: \n" + "Before you start to work with CommandLineParser you have to create a map for keys.\n" + " It will look like this\n" + " const char* keys =\n" + " {\n" + " { s| string| 123asd |string parameter}\n" + " { d| digit | 100 |digit parameter }\n" + " { c|noCamera|false |without camera }\n" + " { 1| |some text|help }\n" + " { 2| |333 |another help }\n" + " };\n" + "Usage syntax: \n" + " \"{\" - start of parameter string.\n" + " \"}\" - end of parameter string\n" + " \"|\" - separator between short name, full name, default value and help\n" "Supported syntax: \n" - " --key1=arg1 or --key3 \n" + " -key2=arg2 \n" "Usage: \n" " Imagine that the input parameters are next:\n" - " -k=10 --key --db=-10.11 -key1 argument --inputFile=lena.jpg\n" - "parser.get(\"k\")\n" - "parser.get(\"db\", 99.99)\n" - " It also works with 'int', 'unsigned int', 'float' and 'string' types\n" - "parser.get(\"key\")\n" - "parser.get(\"key1\")\n" - "parser.get(\"0\")\n" - " It also works with 'int', 'unsigned int', 'double' and 'float' types\n\n" + " -s=string_value --digit=250 --noCamera lena.jpg 10000\n" + " CommandLineParser parser(argc, argv, keys) - create a parser object\n" + " parser.get(\"s\" or \"string\") will return you first parameter value\n" + " parser.get(\"s\", false or \"string\", false) will return you first parameter value\n" + " without spaces in end and begin\n" + " parser.get(\"d\" or \"digit\") will return you second parameter value.\n" + " It also works with 'unsigned int', 'double', and 'float' types>\n" + " parser.get(\"c\" or \"noCamera\") will return you true .\n" + " If you enter this key in commandline>\n" + " It return you false otherwise.\n" + " parser.get(\"1\") will return you the first argument without parameter (lena.jpg) \n" + " parser.get(\"2\") will return you the second argument without parameter (10000)\n" + " It also works with 'unsigned int', 'double', and 'float' types \n" ); } @@ -37,166 +55,179 @@ vector split_string(const string& str, const string& delimiters) string::size_type pos = str.find_first_of(delimiters, lastPos); while (string::npos != pos || string::npos != lastPos) { + res.push_back(str.substr(lastPos, pos - lastPos)); lastPos = str.find_first_not_of(delimiters, pos); + if (str[pos + 1] == '|' && str[pos] == '|') + { + res.push_back(""); + if(str[pos + 2] == '|') + res.push_back(""); + } + if (str[pos + 1] == '\0') + res.push_back(""); pos = str.find_first_of(delimiters, lastPos); } return res; } -CommandLineParser::CommandLineParser(int argc, const char* argv[]) +CommandLineParser::CommandLineParser(int argc, const char* argv[], const char* keys) { - std::string cur_name; + + std::string keys_buffer; + std::string values_buffer; std::string buffer; - std::stringstream str_buff(std::stringstream::in | std::stringstream::out); - std::map::iterator it; - int find_symbol; - int index = 0; + std::string curName; + std::vector keysVector; + std::vector paramVector; + std::map >::iterator it; + size_t flagPosition; + int currentIndex = 1; + bool isFound = false; + bool withNoKey = false; + bool hasValueThroughEq = false; - - for(int i = 1; i < argc; i++) + keys_buffer = keys; + while (!keys_buffer.empty()) { - if(!argv[i]) - break; - cur_name = argv[i]; - if((cur_name.find('-') == 0) && ((int)cur_name.find('=') != -1) && - (cur_name.find('=') != (cur_name.length() - 1))) - { - while (cur_name.find('-') == 0) - cur_name.erase(0,1); + flagPosition = keys_buffer.find_first_of('}'); + flagPosition++; + buffer = keys_buffer.substr(0, flagPosition); + keys_buffer.erase(0, flagPosition); - buffer = cur_name; - find_symbol = (int)cur_name.find('='); - cur_name.erase(find_symbol); - buffer.erase(0, find_symbol + 1); - if (data.find(cur_name) != data.end()) + flagPosition = buffer.find('{'); + if (flagPosition != buffer.npos) + buffer.erase(flagPosition, (flagPosition + 1)); + + flagPosition = buffer.find('}'); + if (flagPosition != buffer.npos) + buffer.erase(flagPosition); + + paramVector = split_string(buffer, "|"); + buffer = paramVector[0]; + if (atoi(buffer.c_str()) == 0) + buffer = buffer + '|' + paramVector[1]; + + paramVector.erase(paramVector.begin(), paramVector.begin() + 2); + data[buffer] = paramVector; + } + + buffer.clear(); + keys_buffer.clear(); + paramVector.clear(); + for (int i = 1; i < argc; i++) + { + if (!argv[i]) + break; + curName = argv[i]; + if (curName.find('-') == 0 && ((curName[1] < '0') || (curName[1] > '9'))) + { + while (curName.find('-') == 0) + curName.erase(curName.begin(), (curName.begin() + 1)); + } + else + withNoKey = true; + if (curName.find('=') != curName.npos) + { + hasValueThroughEq = true; + buffer = curName; + curName.erase(curName.find('=')); + buffer.erase(0, (buffer.find('=') + 1)); + } + + for(it = data.begin(); it != data.end(); it++) + { + keys_buffer = it->first; + keysVector = split_string(keys_buffer, "| "); + if (keysVector.size() == 1) + keysVector.push_back(""); + values_buffer = it->second[0]; + if (((curName == keysVector[0]) || (curName == keysVector[1])) && hasValueThroughEq) { - printf("CommandLineParser constructor found dublicating parameters for name=%s\n" - , cur_name.c_str()); - printf("Constructor will not continue its work since this moment.\n" - "Please enter parameters without dublicates\n"); - helpParser(); - data.clear(); + it->second[0] = buffer; + isFound = true; break; } - else - data[cur_name] = buffer; + + if (!hasValueThroughEq && (values_buffer.find("false") == values_buffer.npos) && + ((curName == keysVector[0]) || (curName == keysVector[1]))) + + { + it->second[0] = argv[++i]; + isFound = true; + break; + } + + if (!hasValueThroughEq && (values_buffer.find("false") != values_buffer.npos) + && ((curName == keysVector[0]) || (curName == keysVector[1]))) + + { + it->second[0] = "true"; + isFound = true; + break; + } + + if (withNoKey) + { + std::string noKeyStr = it->first; + if(atoi(noKeyStr.c_str()) == currentIndex) + { + it->second[0] = curName; + currentIndex++; + isFound = true; + break; + } + } } - else if (cur_name.find('=') == 0) - { - printf("The next key is wrong: key= %s\n", cur_name.c_str()); - printf("Constructor will not continue its work since this moment.\n" - "Please enter parameters without any mistakes\n"); - helpParser(); - data.clear(); - break; - } - else if(((int)cur_name.find('-') == -1) && ((int)cur_name.find('=') != -1)) - { - printf("The next key must be defined with '--' or '-' increment: key= %s\n", cur_name.c_str()); - printf("Constructor will not continue its work since this moment.\n" - "Please enter parameters without any mistakes\n"); - helpParser(); - data.clear(); - break; - } - else if (cur_name.find('=') == (cur_name.length() - 1)) - { - printf("The next key must have argument after '=': key= %s\n", cur_name.c_str()); - printf("Constructor will not continue its work since this moment.\n" - "Please enter parameters without any mistakes\n"); - helpParser(); - data.clear(); - break; - } - else if ((cur_name.find('-') == 0) && ((cur_name[1] < '0') || (cur_name[1] > '9')) ) - { - while (cur_name.find('-') == 0) - cur_name.erase(0,1); - - for(it = data.begin(); it != data.end(); it++) - { - if (it->first == cur_name) - { - printf("CommandLineParser constructor found dublicating parameters for name=%s\n" - , cur_name.c_str()); - printf("Constructor will not continue its work since this moment.\n" - "Please enter parameters without dublicates\n"); - helpParser(); - data.clear(); - break; - } - } - data[cur_name] = "true"; - } - else - { - str_buff << index; - for(it = data.begin(); it != data.end(); it++) - { - if (it->second == cur_name) - { - printf("CommandLineParser constructor found dublicating parameters for name=%s\n" - , cur_name.c_str()); - printf("Constructor will not continue its work since this moment.\n" - "Please enter parameters without dublicates\n"); - helpParser(); - data.clear(); - break; - } - } - data[str_buff.str()] = cur_name; - str_buff.seekp(0); - index++; - } + withNoKey = false; + hasValueThroughEq = false; + if(!isFound) + printf("The current parameter is not defined: %s\n", curName.c_str()); + isFound = false; } + + } -bool CommandLineParser::has(const std::string& keys) const +bool CommandLineParser::has(const std::string& keys) { - vector names=split_string(keys, " |"); - for(size_t j=0; j < names.size(); j++) { - if (data.find(names[j])!=data.end()) + std::map >::iterator it; + std::vector keysVector; + for(it = data.begin(); it != data.end(); it++) + { + keysVector = split_string(it->first, "| "); + if (keysVector.size() == 1) + keysVector.push_back(""); + if ((keys == keysVector[0]) || (keys == keysVector[1])) return true; } return false; } -std::string CommandLineParser::getString(const std::string& keys) const +std::string CommandLineParser::getString(const std::string& keys) { - vector names=split_string(keys, " |"); + std::map >::iterator it; + std::vector valueVector; - int found_index=-1; - for(size_t j=0; j < names.size(); j++) { - const string& cur_name=names[j]; - bool is_cur_found=has(cur_name); - - if (is_cur_found && (found_index >= 0)) { - string str_exception="dublicating parameters for " - "name='" + names[found_index] + "' and name='"+cur_name+"'"; - CV_Error(CV_StsParseError, str_exception); - } - - if (is_cur_found) - found_index=j; + for(it = data.begin(); it != data.end(); it++) + { + valueVector = split_string(it->first, "| "); + if (valueVector.size() == 1) + valueVector.push_back(""); + if ((keys == valueVector[0]) || (keys == valueVector[1])) + return it->second[0]; } - - if (found_index<0) - return string(); - return data.find(names[found_index])->second; + return string(); } template - _Tp CommandLineParser::fromStringNumber(const std::string& str) //the default conversion function for numbers + _Tp CommandLineParser::fromStringNumber(const std::string& str)//the default conversion function for numbers { - if (str.empty()) - CV_Error(CV_StsParseError, "Empty string cannot be converted to a number"); - const char* c_str=str.c_str(); - if((!isdigit(c_str[0])) + if ((!isdigit(c_str[0])) && ( (c_str[0]!='-') || (strlen(c_str) <= 1) || ( !isdigit(c_str[1]) ) @@ -204,71 +235,77 @@ template ) { - CV_Error(CV_StsParseError, "The string '"+ str +"' cannot be converted to a number"); + printf("This string cannot be converted to a number. Zero will be returned %s\n ", str.c_str()); + return _Tp(); } return getData<_Tp>(str); } -template -static _Tp getData(const std::string& str) -{ - _Tp res; - std::stringstream s1(str); - s1 >> res; - return res; -} - -template -static _Tp fromStringNumber(const std::string& str)//the default conversion function for numbers -{ - - if (str.empty()) - CV_Error(CV_StsParseError, "Empty string cannot be converted to a number"); - - const char* c_str=str.c_str(); - if( !isdigit(c_str[0]) && - (c_str[0] != '-' || strlen(c_str) <= 1 || !isdigit(c_str[1]) )) - CV_Error(CV_StsParseError, "The string '"+ str +"' cannot be converted to a number"); - - return getData<_Tp>(str); -} + void CommandLineParser::printParams() + { + std::map >::iterator it; + std::vector keysVector; + for(it = data.begin(); it != data.end(); it++) + { + keysVector = split_string(it->first, "| "); + if (keysVector.size() == 1) + keysVector.push_back(""); + printf("\t%s [%8s] (%12s - by default) - %s\n", keysVector[0].c_str(), + keysVector[1].c_str(), it->second[0].c_str(), it->second[1].c_str()); + } + } template<> -bool CommandLineParser::get(const std::string& name, const bool& /*default_value*/) +bool CommandLineParser::get(const std::string& name, bool space_delete) { - if (!has(name)) + std::string str_buf = getString(name); + if (space_delete) + { + while (str_buf.find_first_of(' ') == 0) + str_buf.erase(0, 1); + while (str_buf.find_last_of(' ') == (str_buf.length() - 1)) + str_buf.erase(str_buf.end() - 1, str_buf.end()); + } + if (str_buf == "false") return false; return true; } - template<> -std::string CommandLineParser::analyzeValue(const std::string& str) +std::string CommandLineParser::analizeValue(const std::string& str, bool space_delete) { + if (space_delete) + { + std::string str_buf = str; + while (str_buf.find_first_of(' ') == 0) + str_buf.erase(0, 1); + while (str_buf.find_last_of('-') == (str.length() - 1)) + str_buf.erase(str_buf.end() - 1, str_buf.end()); + return str_buf; + } return str; } template<> -int CommandLineParser::analyzeValue(const std::string& str) +int CommandLineParser::analizeValue(const std::string& str, bool space_delete) { return fromStringNumber(str); } template<> -unsigned int CommandLineParser::analyzeValue(const std::string& str) +unsigned int CommandLineParser::analizeValue(const std::string& str, bool space_delete) { return fromStringNumber(str); } template<> -float CommandLineParser::analyzeValue(const std::string& str) +float CommandLineParser::analizeValue(const std::string& str, bool space_delete) { return fromStringNumber(str); } template<> -double CommandLineParser::analyzeValue(const std::string& str) +double CommandLineParser::analizeValue(const std::string& str, bool space_delete) { return fromStringNumber(str); } - diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp index 73b13ad717..c0a7c4930d 100644 --- a/modules/core/src/convert.cpp +++ b/modules/core/src/convert.cpp @@ -220,7 +220,7 @@ void cv::split(const Mat& src, Mat* mv) SplitFunc func = splitTab[depth]; CV_Assert( func != 0 ); - int esz = src.elemSize(), esz1 = src.elemSize1(); + int esz = (int)src.elemSize(), esz1 = (int)src.elemSize1(); int blocksize0 = (BLOCK_SIZE + esz-1)/esz; AutoBuffer _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16); const Mat** arrays = (const Mat**)(uchar*)_buf; @@ -305,7 +305,7 @@ void cv::merge(const Mat* mv, size_t n, OutputArray _dst) } size_t esz = dst.elemSize(), esz1 = dst.elemSize1(); - int blocksize0 = (BLOCK_SIZE + esz-1)/esz; + int blocksize0 = (int)((BLOCK_SIZE + esz-1)/esz); AutoBuffer _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16); const Mat** arrays = (const Mat**)(uchar*)_buf; uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16); @@ -451,12 +451,12 @@ void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, cons if( i0 < src[j].channels() ) break; CV_Assert(j < nsrcs && src[j].depth() == depth); - tab[i*4] = j; tab[i*4+1] = i0*esz1; + tab[i*4] = (int)j; tab[i*4+1] = (int)(i0*esz1); sdelta[i] = src[j].channels(); } else { - tab[i*4] = nsrcs + ndsts; tab[i*4+1] = 0; + tab[i*4] = (int)(nsrcs + ndsts); tab[i*4+1] = 0; sdelta[i] = 0; } @@ -464,11 +464,11 @@ void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, cons if( i1 < dst[j].channels() ) break; CV_Assert(i1 >= 0 && j < ndsts && dst[j].depth() == depth); - tab[i*4+2] = j + nsrcs; tab[i*4+3] = i1*esz1; + tab[i*4+2] = (int)(j + nsrcs); tab[i*4+3] = (int)(i1*esz1); ddelta[i] = dst[j].channels(); } - NAryMatIterator it(arrays, ptrs, nsrcs + ndsts); + NAryMatIterator it(arrays, ptrs, (int)(nsrcs + ndsts)); int total = (int)it.size, blocksize = std::min(total, (int)((BLOCK_SIZE + esz1-1)/esz1)); MixChannelsFunc func = mixchTab[depth]; @@ -503,6 +503,22 @@ void cv::mixChannels(const vector& src, vector& dst, !dst.empty() ? &dst[0] : 0, dst.size(), fromTo, npairs); } +void cv::mixChannels(InputArrayOfArrays src, InputArrayOfArrays dst, + const vector& fromTo) +{ + if(fromTo.empty()) + return; + int i, nsrc = (int)src.total(), ndst = (int)dst.total(); + CV_Assert(fromTo.size()%2 == 0 && nsrc > 0 && ndst > 0); + cv::AutoBuffer _buf(nsrc + ndst); + Mat* buf = _buf; + for( i = 0; i < nsrc; i++ ) + buf[i] = src.getMat(i); + for( i = 0; i < ndst; i++ ) + buf[nsrc + i] = dst.getMat(i); + mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, &fromTo[0], fromTo.size()/2); +} + void cv::extractChannel(InputArray _src, OutputArray _dst, int coi) { Mat src = _src.getMat(); diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 620154f733..43f601c367 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -207,9 +207,11 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const return; } - CV_Assert( mask.type() == CV_8U ); + int cn = channels(), mcn = mask.channels(); + CV_Assert( mask.depth() == CV_8U && (mcn == 1 || mcn == cn) ); + bool colorMask = mcn > 1; - size_t esz = elemSize(); + size_t esz = colorMask ? elemSize1() : elemSize(); BinaryFunc copymask = getCopyMaskFunc(esz); uchar* data0 = _dst.getMat().data; @@ -221,7 +223,7 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const if( dims <= 2 ) { - Size sz = getContinuousSize(*this, dst, mask); + Size sz = getContinuousSize(*this, dst, mask, mcn); copymask(data, step, mask.data, mask.step, dst.data, dst.step, sz, &esz); return; } @@ -229,7 +231,7 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const const Mat* arrays[] = { this, &dst, &mask, 0 }; uchar* ptrs[3]; NAryMatIterator it(arrays, ptrs); - Size sz((int)it.size, 1); + Size sz((int)(it.size*mcn), 1); for( size_t i = 0; i < it.nplanes; i++, ++it ) copymask(ptrs[0], 0, ptrs[2], 0, ptrs[1], 0, sz, &esz); @@ -257,7 +259,7 @@ Mat& Mat::operator = (const Scalar& s) for( size_t j = 0; j < size; j += blockSize ) { - size_t sz = std::min(blockSize, size - j); + size_t sz = MIN(blockSize, size - j); memcpy( ptr + j, scalar, sz ); } } @@ -316,13 +318,13 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask) static void flipHoriz( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size size, size_t esz ) { - int i, j, limit = ((size.width + 1)/2)*esz; + int i, j, limit = (int)(((size.width + 1)/2)*esz); AutoBuffer _tab(size.width*esz); int* tab = _tab; for( i = 0; i < size.width; i++ ) for( size_t k = 0; k < esz; k++ ) - tab[i*esz + k] = (size.width - i - 1)*esz + k; + tab[i*esz + k] = (int)((size.width - i - 1)*esz + k); for( ; size.height--; src += sstep, dst += dstep ) { diff --git a/modules/core/src/datastructs.cpp b/modules/core/src/datastructs.cpp index 917c6ea7f1..59a482962d 100644 --- a/modules/core/src/datastructs.cpp +++ b/modules/core/src/datastructs.cpp @@ -3945,7 +3945,7 @@ void KDTree::findOrthoRange(InputArray _lowerBound, if( _neighborsIdx.needed() ) { - _neighborsIdx.create(idx.size(), 1, CV_32S, -1, true); + _neighborsIdx.create((int)idx.size(), 1, CV_32S, -1, true); Mat nidx = _neighborsIdx.getMat(); Mat(nidx.size(), CV_32S, &idx[0]).copyTo(nidx); } diff --git a/modules/core/src/drawing.cpp b/modules/core/src/drawing.cpp index d8101fd8d0..f8e8a513bf 100644 --- a/modules/core/src/drawing.cpp +++ b/modules/core/src/drawing.cpp @@ -2012,6 +2012,63 @@ Size getTextSize( const string& text, int fontFace, double fontScale, int thickn } + +void cv::fillConvexPoly(InputOutputArray _img, InputArray _points, + const Scalar& color, int lineType, int shift) +{ + Mat img = _img.getMat(), points = _points.getMat(); + CV_Assert(points.checkVector(2, CV_32S) >= 0); + fillConvexPoly(img, (const Point*)points.data, points.rows*points.cols*points.channels()/2, color, lineType, shift); +} + + +void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts, + const Scalar& color, int lineType, int shift, Point offset) +{ + Mat img = _img.getMat(); + int i, ncontours = (int)pts.total(); + if( ncontours == 0 ) + return; + AutoBuffer _ptsptr(ncontours); + AutoBuffer _npts(ncontours); + Point** ptsptr = _ptsptr; + int* npts = _npts; + + for( i = 0; i < ncontours; i++ ) + { + Mat p = pts.getMat(i); + CV_Assert(p.checkVector(2, CV_32S) >= 0); + ptsptr[i] = (Point*)p.data; + npts[i] = p.rows*p.cols*p.channels()/2; + } + fillPoly(img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset); +} + + +void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts, + bool isClosed, const Scalar& color, + int thickness, int lineType, int shift ) +{ + Mat img = _img.getMat(); + int i, ncontours = (int)pts.total(); + if( ncontours == 0 ) + return; + AutoBuffer _ptsptr(ncontours); + AutoBuffer _npts(ncontours); + Point** ptsptr = _ptsptr; + int* npts = _npts; + + for( i = 0; i < ncontours; i++ ) + { + Mat p = pts.getMat(i); + CV_Assert(p.checkVector(2, CV_32S) >= 0); + ptsptr[i] = (Point*)p.data; + npts[i] = p.rows*p.cols*p.channels()/2; + } + polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift); +} + + static const int CodeDeltas[8][2] = { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; diff --git a/modules/core/src/lapack.cpp b/modules/core/src/lapack.cpp index 03785f9ec6..c88125e4fb 100644 --- a/modules/core/src/lapack.cpp +++ b/modules/core/src/lapack.cpp @@ -1398,10 +1398,7 @@ bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int meth /////////////////// finding eigenvalues and eigenvectors of a symmetric matrix /////////////// -namespace cv -{ - -static bool eigen( InputArray _src, OutputArray _evals, OutputArray _evects, bool computeEvects, int, int ) +bool cv::eigen( InputArray _src, bool computeEvects, OutputArray _evals, OutputArray _evects ) { Mat src = _src.getMat(); int type = src.type(); @@ -1431,17 +1428,14 @@ static bool eigen( InputArray _src, OutputArray _evals, OutputArray _evects, boo return ok; } -} - -bool cv::eigen( InputArray src, OutputArray evals, int lowindex, int highindex ) +bool cv::eigen( InputArray src, OutputArray evals, int, int ) { - return eigen(src, evals, noArray(), false, lowindex, highindex); + return eigen(src, false, evals, noArray()); } -bool cv::eigen( InputArray src, OutputArray evals, OutputArray evects, - int lowindex, int highindex ) +bool cv::eigen( InputArray src, OutputArray evals, OutputArray evects, int, int) { - return eigen(src, evals, evects, true, lowindex, highindex); + return eigen(src, true, evals, evects); } namespace cv @@ -1568,6 +1562,17 @@ void SVD::backSubst( InputArray rhs, OutputArray dst ) const } +void cv::SVDecomp(InputArray src, OutputArray w, OutputArray u, OutputArray vt, int flags) +{ + SVD::compute(src, w, u, vt, flags); +} + +void cv::SVBackSubst(InputArray w, InputArray u, InputArray vt, InputArray rhs, OutputArray dst) +{ + SVD::backSubst(w, u, vt, rhs, dst); +} + + CV_IMPL double cvDet( const CvArr* arr ) { @@ -1632,14 +1637,31 @@ CV_IMPL void cvEigenVV( CvArr* srcarr, CvArr* evectsarr, CvArr* evalsarr, double, int lowindex, int highindex) { - cv::Mat src = cv::cvarrToMat(srcarr), evals = cv::cvarrToMat(evalsarr); + cv::Mat src = cv::cvarrToMat(srcarr), evals0 = cv::cvarrToMat(evalsarr), evals = evals0; if( evectsarr ) { - cv::Mat evects = cv::cvarrToMat(evectsarr); + cv::Mat evects0 = cv::cvarrToMat(evectsarr), evects = evects0; eigen(src, evals, evects, lowindex, highindex); + if( evects0.data != evects.data ) + { + uchar* p = evects0.data; + evects.convertTo(evects0, evects0.type()); + CV_Assert( p == evects0.data ); + } } else eigen(src, evals, lowindex, highindex); + if( evals0.data != evals.data ) + { + uchar* p = evals0.data; + if( evals0.size() == evals.size() ) + evals.convertTo(evals0, evals0.type()); + else if( evals0.type() == evals.type() ) + cv::transpose(evals, evals0); + else + cv::Mat(evals.t()).convertTo(evals0, evals0.type()); + CV_Assert( p == evals0.data ); + } } diff --git a/modules/core/src/mathfuncs.cpp b/modules/core/src/mathfuncs.cpp index 83970fa847..88056e012f 100644 --- a/modules/core/src/mathfuncs.cpp +++ b/modules/core/src/mathfuncs.cpp @@ -1990,8 +1990,8 @@ bool checkRange(InputArray _src, bool quiet, Point* pt, if( depth < CV_32F ) { - double m = 0, M = 0, badValue = 0; - Point mp, MP, badPt(-1,-1); + double m = 0, M = 0; + Point mp, MP; minMaxLoc(src.reshape(1,0), &m, &M, &mp, &MP); if( M >= maxVal ) { diff --git a/modules/core/src/matmul.cpp b/modules/core/src/matmul.cpp index 28767bfe33..45cb158220 100644 --- a/modules/core/src/matmul.cpp +++ b/modules/core/src/matmul.cpp @@ -2713,7 +2713,7 @@ double Mat::dot(InputArray _mat) const { size_t len = total()*cn; if( len == (size_t)(int)len ) - return func(data, mat.data, len); + return func(data, mat.data, (int)len); } const Mat* arrays[] = {this, &mat, 0}; @@ -2884,6 +2884,34 @@ Mat PCA::backProject(InputArray data) const } +void cv::PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, int maxComponents) +{ + PCA pca; + pca(data, mean, 0, maxComponents); + pca.mean.copyTo(mean); + pca.eigenvectors.copyTo(eigenvectors); +} + +void cv::PCAProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result) +{ + PCA pca; + pca.mean = mean.getMat(); + pca.eigenvectors = eigenvectors.getMat(); + pca.project(data, result); +} + +void cv::PCABackProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result) +{ + PCA pca; + pca.mean = mean.getMat(); + pca.eigenvectors = eigenvectors.getMat(); + pca.backProject(data, result); +} + + /****************************************************************************************\ * Earlier API * \****************************************************************************************/ diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index f0905a180b..95b0c4e36f 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -585,6 +585,11 @@ void Mat::push_back(const Mat& elems) push_back(tmp); return; } + if( !data ) + { + *this = elems.clone(); + return; + } size.p[0] = elems.size.p[0]; bool eq = size == elems.size; @@ -928,7 +933,7 @@ void _InputArray::getMatVector(vector& mv) const if( k == MAT ) { const Mat& m = *(const Mat*)obj; - size_t i, n = m.size[0]; + int i, n = (int)m.size[0]; mv.resize(n); for( i = 0; i < n; i++ ) @@ -940,7 +945,7 @@ void _InputArray::getMatVector(vector& mv) const if( k == EXPR ) { Mat m = *(const MatExpr*)obj; - size_t i, n = m.size[0]; + int i, n = m.size[0]; mv.resize(n); for( i = 0; i < n; i++ ) @@ -980,7 +985,7 @@ void _InputArray::getMatVector(vector& mv) const if( k == STD_VECTOR_VECTOR ) { const vector >& vv = *(const vector >*)obj; - size_t i, n = vv.size(); + int i, n = (int)vv.size(); int t = CV_MAT_TYPE(flags); mv.resize(n); @@ -2200,7 +2205,7 @@ static void generateCentersPP(const Mat& _data, Mat& _out_centers, { int i, j, k, dims = _data.cols, N = _data.rows; const float* data = _data.ptr(0); - int step = (int)(_data.step/sizeof(data[0])); + size_t step = _data.step/sizeof(data[0]); vector _centers(K); int* centers = &_centers[0]; vector _dist(N*3); @@ -2795,7 +2800,7 @@ NAryMatIterator& NAryMatIterator::operator ++() const Mat& A = *arrays[i]; if( !A.data ) continue; - int _idx = idx; + int _idx = (int)idx; uchar* data = A.data; for( int j = iterdepth-1; j >= 0 && _idx > 0; j-- ) { diff --git a/modules/core/src/out.cpp b/modules/core/src/out.cpp index eeca5a1fa2..366f5cf05c 100644 --- a/modules/core/src/out.cpp +++ b/modules/core/src/out.cpp @@ -127,7 +127,8 @@ static void writeMat(std::ostream& out, const Mat& m, char rowsep, char elembrac { if(orowbrace) out << orowbrace; - writeElems(out, m.ptr(i), m.cols, type, elembrace); + if( m.data ) + writeElems(out, m.ptr(i), m.cols, type, elembrace); if(orowbrace) out << crowbrace << (i+1 < m.rows ? ", " : ""); if(i+1 < m.rows) diff --git a/modules/core/src/precomp.hpp b/modules/core/src/precomp.hpp index 14a3437a7d..efd8c61e79 100644 --- a/modules/core/src/precomp.hpp +++ b/modules/core/src/precomp.hpp @@ -65,6 +65,10 @@ #include #include +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "opencv2/core/core_tegra.hpp" +#endif + namespace cv { diff --git a/modules/core/src/rand.cpp b/modules/core/src/rand.cpp index fb68d38847..e143256c88 100644 --- a/modules/core/src/rand.cpp +++ b/modules/core/src/rand.cpp @@ -812,6 +812,11 @@ void cv::randShuffle( InputOutputArray _dst, double iterFactor, RNG* _rng ) func( dst, rng, iterFactor ); } +void cv::randShuffle_( InputOutputArray _dst, double iterFactor ) +{ + randShuffle(_dst, iterFactor); +} + CV_IMPL void cvRandArr( CvRNG* _rng, CvArr* arr, int disttype, CvScalar param1, CvScalar param2 ) { diff --git a/modules/core/src/stat.cpp b/modules/core/src/stat.cpp index e1dc88e52e..307a68b250 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -590,7 +590,7 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input } double scale = nz0 ? 1./nz0 : 0.; - for( int k = 0; k < cn; k++ ) + for( k = 0; k < cn; k++ ) { s[k] *= scale; sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.)); diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index bdd44d2928..2922cdaf8f 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -85,6 +85,17 @@ #include +#if defined __linux__ || defined __APPLE__ +#include +#include +#include +#if defined ANDROID +#include +#else +#include +#endif +#endif + namespace cv { @@ -192,7 +203,7 @@ struct IPPInitializer IPPInitializer ippInitializer; #else -volatile bool useOptimizedFlag = false; +volatile bool useOptimizedFlag = true; #endif volatile bool USE_SSE2 = false; @@ -365,6 +376,41 @@ int getThreadNum(void) #endif } +int getNumberOfCPUs(void) +{ +#if defined WIN32 || defined _WIN32 + SYSTEM_INFO sysinfo; + GetSystemInfo( &sysinfo ); + + return (int)sysinfo.dwNumberOfProcessors; +#elif defined __linux__ + return (int)sysconf( _SC_NPROCESSORS_ONLN ); +#elif defined __APPLE__ + int numCPU=0; + int mib[4]; + size_t len = sizeof(numCPU); + + /* set the mib for hw.ncpu */ + mib[0] = CTL_HW; + mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; + + /* get the number of CPUs from the system */ + sysctl(mib, 2, &numCPU, &len, NULL, 0); + + if( numCPU < 1 ) + { + mib[1] = HW_NCPU; + sysctl( mib, 2, &numCPU, &len, NULL, 0 ); + + if( numCPU < 1 ) + numCPU = 1; + } + + return (int)numCPU; +#else + return 1; +#endif +} string format( const char* fmt, ... ) { diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index b20747085c..dc1215ae3f 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -559,7 +559,8 @@ static void inRange(const Mat& src, const Mat& lb, const Mat& rb, Mat& dst) NAryMatIterator it(arrays, planes); size_t total = planes[0].total(); - int i, nplanes = it.nplanes, depth = src.depth(), cn = src.channels(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(), cn = src.channels(); for( i = 0; i < nplanes; i++, ++it ) { @@ -606,7 +607,8 @@ static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& ds NAryMatIterator it(arrays, planes); size_t total = planes[0].total(); - int i, nplanes = it.nplanes, depth = src.depth(), cn = src.channels(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(), cn = src.channels(); double lbuf[4], rbuf[4]; int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn); scalarToRawData(lb, lbuf, wtype, cn); @@ -900,7 +902,8 @@ static void exp(const Mat& src, Mat& dst) NAryMatIterator it(arrays, planes); size_t j, total = planes[0].total()*src.channels(); - int i, nplanes = it.nplanes, depth = src.depth(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(); for( i = 0; i < nplanes; i++, ++it ) { @@ -928,7 +931,8 @@ static void log(const Mat& src, Mat& dst) NAryMatIterator it(arrays, planes); size_t j, total = planes[0].total()*src.channels(); - int i, nplanes = it.nplanes, depth = src.depth(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(); for( i = 0; i < nplanes; i++, ++it ) { @@ -1017,7 +1021,8 @@ static void cartToPolar(const Mat& mx, const Mat& my, Mat& mmag, Mat& mangle, bo NAryMatIterator it(arrays, planes); size_t j, total = planes[0].total(); - int i, nplanes = it.nplanes, depth = mx.depth(); + size_t i, nplanes = it.nplanes; + int depth = mx.depth(); double scale = angleInDegrees ? 180/CV_PI : 1; for( i = 0; i < nplanes; i++, ++it ) @@ -1260,8 +1265,8 @@ struct MinMaxLocOp : public BaseElemWiseOp void saveOutput(const vector& minidx, const vector& maxidx, double minval, double maxval, Mat& dst) { - size_t i, ndims = minidx.size(); - dst.create(1, (int)(ndims*2 + 2), CV_64FC1); + int i, ndims = (int)minidx.size(); + dst.create(1, ndims*2 + 2, CV_64FC1); for( i = 0; i < ndims; i++ ) { diff --git a/modules/core/test/test_dxt.cpp b/modules/core/test/test_dxt.cpp index be6826e1d9..fd3fdd6fd5 100644 --- a/modules/core/test/test_dxt.cpp +++ b/modules/core/test/test_dxt.cpp @@ -170,9 +170,9 @@ static void DCT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat( w = wave.ptr(); if( !_src.isContinuous() ) - srcstep = _src.step/_src.elemSize(); + srcstep = (int)(_src.step/_src.elemSize()); if( !_dst.isContinuous() ) - dststep = _dst.step/_dst.elemSize(); + dststep = (int)(_dst.step/_dst.elemSize()); if( _src.type() == CV_32FC1 ) { @@ -279,10 +279,10 @@ static void convertFromCCS( const Mat& _src0, const Mat& _src1, Mat& _dst, int f int srcstep = cn, dststep = 1; if( !_dst.isContinuous() ) - dststep = _dst.step/_dst.elemSize(); + dststep = (int)(_dst.step/_dst.elemSize()); if( !_src0.isContinuous() ) - srcstep = _src0.step/_src0.elemSize1(); + srcstep = (int)(_src0.step/_src0.elemSize1()); if( _dst.depth() == CV_32F ) { diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index 23e03073a1..0b9dbd5311 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -1954,7 +1954,7 @@ void Core_SVDTest::prepare_to_validation( int /*test_case_idx*/ ) } w = &test_mat[TEMP][0]; - step = w->rows == 1 ? 1 : w->step1(); + step = w->rows == 1 ? 1 : (int)w->step1(); for( i = 0; i < min_size; i++ ) { double normval = 0, aii; diff --git a/modules/features2d/doc/common_interfaces_of_descriptor_extractors.rst b/modules/features2d/doc/common_interfaces_of_descriptor_extractors.rst index 5983c463cc..a750eb5d2a 100644 --- a/modules/features2d/doc/common_interfaces_of_descriptor_extractors.rst +++ b/modules/features2d/doc/common_interfaces_of_descriptor_extractors.rst @@ -55,23 +55,15 @@ Computes the descriptors for a set of keypoints detected in an image (first vari .. ocv:function:: void DescriptorExtractor::compute( const Mat& image, vector& keypoints, Mat& descriptors ) const - :param image: Image. - - :param keypoints: Keypoints. Keypoints for which a descriptor cannot be computed are removed. Sometimes new keypoints can be added, for example: ``SIFT`` duplicates keypoint with several dominant orientations (for each orientation). - - :param descriptors: Descriptors. Row ``i`` is the descriptor for keypoint ``i``. - .. ocv:function:: void DescriptorExtractor::compute( const vector& images, vector >& keypoints, vector& descriptors ) const + :param image: Image. + :param images: Image set. - :param keypoints: Input keypoints collection. ``keypoints[i]`` are keypoints - detected in ``images[i]`` . Keypoints for which a descriptor - cannot be computed are removed. - - :param descriptors: Descriptor collection. ``descriptors[i]`` are descriptors computed for a ``keypoints[i]`` set. - + :param keypoints: Input collection of keypoints. Keypoints for which a descriptor cannot be computed are removed. Sometimes new keypoints can be added, for example: ``SIFT`` duplicates keypoint with several dominant orientations (for each orientation). + :param descriptors: Computed descriptors. In the second variant of the method ``descriptors[i]`` are descriptors computed for a ``keypoints[i]`. Row ``j`` is the ``keypoints`` (or ``keypoints[i]``) is the descriptor for keypoint ``j``-th keypoint. DescriptorExtractor::read ----------------------------- @@ -119,7 +111,7 @@ SiftDescriptorExtractor .. ocv:class:: SiftDescriptorExtractor Wrapping class for computing descriptors by using the -:ocv:class::`SIFT` class. :: +:ocv:class:`SIFT` class. :: class SiftDescriptorExtractor : public DescriptorExtractor { diff --git a/modules/features2d/doc/common_interfaces_of_descriptor_matchers.rst b/modules/features2d/doc/common_interfaces_of_descriptor_matchers.rst index 31ac5a1044..8ec9c4bc18 100644 --- a/modules/features2d/doc/common_interfaces_of_descriptor_matchers.rst +++ b/modules/features2d/doc/common_interfaces_of_descriptor_matchers.rst @@ -290,7 +290,7 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t template<> struct Accumulator { typedef int Type; }; /* - * Squared Euclidean distance functor + * Euclidean distance functor */ template struct L2 @@ -300,6 +300,20 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t ResultType operator()( const T* a, const T* b, int size ) const; }; + + /* + * Squared Euclidean distance functor + */ + template + struct SL2 + { + typedef T ValueType; + typedef typename Accumulator::Type ResultType; + + ResultType operator()( const T* a, const T* b, int size ) const; + }; + // Note: in case of SL2 distance a parameter maxDistance in the method DescriptorMatcher::radiusMatch + // is a squared maximum distance in L2. /* * Manhattan distance (city block distance) functor @@ -311,7 +325,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t typedef typename Accumulator::Type ResultType; ResultType operator()( const T* a, const T* b, int size ) const; - ... }; /* @@ -334,7 +347,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t ResultType operator()( const unsigned char* a, const unsigned char* b, int size ) const; - ... }; diff --git a/modules/features2d/doc/common_interfaces_of_feature_detectors.rst b/modules/features2d/doc/common_interfaces_of_feature_detectors.rst index bc0984a603..5be705308f 100644 --- a/modules/features2d/doc/common_interfaces_of_feature_detectors.rst +++ b/modules/features2d/doc/common_interfaces_of_feature_detectors.rst @@ -100,19 +100,17 @@ Detects keypoints in an image (first variant) or image set (second variant). .. ocv:function:: void FeatureDetector::detect( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const +.. ocv:function:: void FeatureDetector::detect( const vector& images, vector >& keypoints, const vector& masks=vector() ) const + :param image: Image. - :param keypoints: Detected keypoints. - - :param mask: Mask specifying where to look for keypoints (optional). It must be a char matrix with non-zero values in the region of interest. - -.. ocv:function:: void FeatureDetector::detect( const vector& images, vector >& keypoints, const vector& masks=vector() ) const - :param images: Image set. - :param keypoints: Collection of keypoints detected in input images. ``keypoints[i]`` is a set of keypoints detected in ``images[i]`` . + :param keypoints: The detected keypoints. In the second variant of the method ``keypoints[i]`` is a set of keypoints detected in ``images[i]`` . - :param masks: Masks for each input image specifying where to look for keypoints (optional). ``masks[i]`` is a mask for ``images[i]`` . Each element of the ``masks`` vector must be a char matrix with non-zero values in the region of interest. + :param mask: Mask specifying where to look for keypoints (optional). It must be a 8-bit integer matrix with non-zero values in the region of interest. + + :param masks: Masks for each input image specifying where to look for keypoints (optional). ``masks[i]`` is a mask for ``images[i]``. FeatureDetector::read ------------------------- diff --git a/modules/features2d/doc/object_categorization.rst b/modules/features2d/doc/object_categorization.rst index 416ad5b5d2..a5f82b5bf7 100644 --- a/modules/features2d/doc/object_categorization.rst +++ b/modules/features2d/doc/object_categorization.rst @@ -94,6 +94,7 @@ BOWKMeansTrainer BOWKMeansTrainer::BOWKMeansTrainer ---------------------------------- + The constructor. .. ocv:function:: BOWKMeansTrainer::BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(), int attempts=3, int flags=KMEANS_PP_CENTERS ) @@ -193,6 +194,7 @@ Returns an image discriptor size if the vocabulary is set. Otherwise, it returns BOWImgDescriptorExtractor::descriptorType --------------------------------------------- + Returns an image descriptor type. .. ocv:function:: int BOWImgDescriptorExtractor::descriptorType() const diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index 9da0f87a4f..b7281f8b61 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -44,7 +44,7 @@ #define __OPENCV_FEATURES_2D_HPP__ #include "opencv2/core/core.hpp" -#include "opencv2/flann/flann.hpp" +#include "opencv2/flann/miniflann.hpp" #ifdef __cplusplus #include @@ -1583,10 +1583,16 @@ public: bool filterByConvexity; float minConvexity, maxConvexity; + + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; }; SimpleBlobDetector(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params()); + virtual void read( const FileNode& fn ); + virtual void write( FileStorage& fs ) const; + protected: struct CV_EXPORTS Center { @@ -1618,11 +1624,15 @@ public: bool varyXyStepWithScale; bool varyImgBoundWithScale; + + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; }; DenseFeatureDetector( const DenseFeatureDetector::Params& params=DenseFeatureDetector::Params() ); - // TODO implement read/write + virtual void read( const FileNode& fn ); + virtual void write( FileStorage& fs ) const; protected: virtual void detectImpl( const Mat& image, vector& keypoints, const Mat& mask=Mat() ) const; @@ -1919,7 +1929,7 @@ protected: * - if you know the integral image, use setIntegralImage so that it is not recomputed. This calls * setStepSize automatically */ -class OrbDescriptorExtractor : public cv::DescriptorExtractor +class CV_EXPORTS OrbDescriptorExtractor : public cv::DescriptorExtractor { public: /** default constructor @@ -2052,6 +2062,9 @@ public: // bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes. BriefDescriptorExtractor( int bytes = 32 ); + virtual void read( const FileNode& ); + virtual void write( FileStorage& ) const; + virtual int descriptorSize() const; virtual int descriptorType() const; @@ -2084,6 +2097,27 @@ template<> struct Accumulator { typedef float Type; }; * Squared Euclidean distance functor */ template +struct CV_EXPORTS SL2 +{ + typedef T ValueType; + typedef typename Accumulator::Type ResultType; + + ResultType operator()( const T* a, const T* b, int size ) const + { + ResultType result = ResultType(); + for( int i = 0; i < size; i++ ) + { + ResultType diff = (ResultType)(a[i] - b[i]); + result += diff*diff; + } + return result; + } +}; + +/* + * Euclidean distance functor + */ +template struct CV_EXPORTS L2 { typedef T ValueType; @@ -2367,6 +2401,7 @@ Ptr BruteForceMatcher::clone( bool emptyTrainData ) BruteForceMatcher* matcher = new BruteForceMatcher(distance); if( !emptyTrainData ) { + matcher->trainDescCollection.resize(trainDescCollection.size()); std::transform( trainDescCollection.begin(), trainDescCollection.end(), matcher->trainDescCollection.begin(), clone_op ); } @@ -2391,77 +2426,77 @@ template inline void BruteForceMatcher::commonKnnMatchImpl( BruteForceMatcher& matcher, const Mat& queryDescriptors, vector >& matches, int knn, const vector& masks, bool compactResult ) - { - typedef typename Distance::ValueType ValueType; - typedef typename Distance::ResultType DistanceType; - CV_DbgAssert( !queryDescriptors.empty() ); - CV_Assert( DataType::type == queryDescriptors.type() ); +{ + typedef typename Distance::ValueType ValueType; + typedef typename Distance::ResultType DistanceType; + CV_DbgAssert( !queryDescriptors.empty() ); + CV_Assert( DataType::type == queryDescriptors.type() ); - int dimension = queryDescriptors.cols; - matches.reserve(queryDescriptors.rows); + int dimension = queryDescriptors.cols; + matches.reserve(queryDescriptors.rows); - size_t imgCount = matcher.trainDescCollection.size(); - vector allDists( imgCount ); // distances between one query descriptor and all train descriptors - for( size_t i = 0; i < imgCount; i++ ) + size_t imgCount = matcher.trainDescCollection.size(); + vector allDists( imgCount ); // distances between one query descriptor and all train descriptors + for( size_t i = 0; i < imgCount; i++ ) allDists[i] = Mat( 1, matcher.trainDescCollection[i].rows, DataType::type ); - for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ ) - { - if( matcher.isMaskedOut( masks, qIdx ) ) - { - if( !compactResult ) // push empty vector - matches.push_back( vector() ); - } - else - { - // 1. compute distances between i-th query descriptor and all train descriptors - for( size_t iIdx = 0; iIdx < imgCount; iIdx++ ) - { - CV_Assert( DataType::type == matcher.trainDescCollection[iIdx].type() || matcher.trainDescCollection[iIdx].empty() ); - CV_Assert( queryDescriptors.cols == matcher.trainDescCollection[iIdx].cols || - matcher.trainDescCollection[iIdx].empty() ); + for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ ) + { + if( matcher.isMaskedOut( masks, qIdx ) ) + { + if( !compactResult ) // push empty vector + matches.push_back( vector() ); + } + else + { + // 1. compute distances between i-th query descriptor and all train descriptors + for( size_t iIdx = 0; iIdx < imgCount; iIdx++ ) + { + CV_Assert( DataType::type == matcher.trainDescCollection[iIdx].type() || matcher.trainDescCollection[iIdx].empty() ); + CV_Assert( queryDescriptors.cols == matcher.trainDescCollection[iIdx].cols || + matcher.trainDescCollection[iIdx].empty() ); - const ValueType* d1 = (const ValueType*)(queryDescriptors.data + queryDescriptors.step*qIdx); - allDists[iIdx].setTo( Scalar::all(std::numeric_limits::max()) ); - for( int tIdx = 0; tIdx < matcher.trainDescCollection[iIdx].rows; tIdx++ ) - { - if( masks.empty() || matcher.isPossibleMatch(masks[iIdx], qIdx, tIdx) ) - { - const ValueType* d2 = (const ValueType*)(matcher.trainDescCollection[iIdx].data + - matcher.trainDescCollection[iIdx].step*tIdx); - allDists[iIdx].at(0, tIdx) = matcher.distance(d1, d2, dimension); - } - } - } + const ValueType* d1 = (const ValueType*)(queryDescriptors.data + queryDescriptors.step*qIdx); + allDists[iIdx].setTo( Scalar::all(std::numeric_limits::max()) ); + for( int tIdx = 0; tIdx < matcher.trainDescCollection[iIdx].rows; tIdx++ ) + { + if( masks.empty() || matcher.isPossibleMatch(masks[iIdx], qIdx, tIdx) ) + { + const ValueType* d2 = (const ValueType*)(matcher.trainDescCollection[iIdx].data + + matcher.trainDescCollection[iIdx].step*tIdx); + allDists[iIdx].at(0, tIdx) = matcher.distance(d1, d2, dimension); + } + } + } - // 2. choose k nearest matches for query[i] - matches.push_back( vector() ); - vector >::reverse_iterator curMatches = matches.rbegin(); - for( int k = 0; k < knn; k++ ) - { - DMatch bestMatch; - bestMatch.distance = std::numeric_limits::max(); - for( size_t iIdx = 0; iIdx < imgCount; iIdx++ ) - { - if( !allDists[iIdx].empty() ) - { - double minVal; - Point minLoc; - minMaxLoc( allDists[iIdx], &minVal, 0, &minLoc, 0 ); - if( minVal < bestMatch.distance ) - bestMatch = DMatch( qIdx, minLoc.x, (int)iIdx, (float)minVal ); - } - } - if( bestMatch.trainIdx == -1 ) - break; + // 2. choose k nearest matches for query[i] + matches.push_back( vector() ); + vector >::reverse_iterator curMatches = matches.rbegin(); + for( int k = 0; k < knn; k++ ) + { + DMatch bestMatch; + bestMatch.distance = std::numeric_limits::max(); + for( size_t iIdx = 0; iIdx < imgCount; iIdx++ ) + { + if( !allDists[iIdx].empty() ) + { + double minVal; + Point minLoc; + minMaxLoc( allDists[iIdx], &minVal, 0, &minLoc, 0 ); + if( minVal < bestMatch.distance ) + bestMatch = DMatch( qIdx, minLoc.x, (int)iIdx, (float)minVal ); + } + } + if( bestMatch.trainIdx == -1 ) + break; - allDists[bestMatch.imgIdx].at(0, bestMatch.trainIdx) = std::numeric_limits::max(); - curMatches->push_back( bestMatch ); - } - //TODO should already be sorted at this point? - std::sort( curMatches->begin(), curMatches->end() ); - } - } + allDists[bestMatch.imgIdx].at(0, bestMatch.trainIdx) = std::numeric_limits::max(); + curMatches->push_back( bestMatch ); + } + //TODO should already be sorted at this point? + std::sort( curMatches->begin(), curMatches->end() ); + } + } } template @@ -2536,6 +2571,11 @@ public: virtual void add( const vector& descriptors ); virtual void clear(); + // Reads matcher object from a file node + virtual void read( const FileNode& ); + // Writes matcher object to a file storage + virtual void write( FileStorage& ) const; + virtual void train(); virtual bool isMaskSupported() const; diff --git a/modules/features2d/src/blobdetector.cpp b/modules/features2d/src/blobdetector.cpp index 1242507543..4fa920787a 100644 --- a/modules/features2d/src/blobdetector.cpp +++ b/modules/features2d/src/blobdetector.cpp @@ -84,11 +84,79 @@ SimpleBlobDetector::Params::Params() maxConvexity = std::numeric_limits::max(); } +void SimpleBlobDetector::Params::read(const cv::FileNode& fn ) +{ + thresholdStep = fn["thresholdStep"]; + minThreshold = fn["minThreshold"]; + maxThreshold = fn["maxThreshold"]; + + minRepeatability = (size_t)(int)fn["minRepeatability"]; + minDistBetweenBlobs = fn["minDistBetweenBlobs"]; + + filterByColor = (int)fn["filterByColor"] != 0 ? true : false; + blobColor = (uchar)(int)fn["blobColor"]; + + filterByArea = (int)fn["filterByArea"] != 0 ? true : false; + minArea = fn["minArea"]; + maxArea = fn["maxArea"]; + + filterByCircularity = (int)fn["filterByCircularity"] != 0 ? true : false; + minCircularity = fn["minCircularity"]; + maxCircularity = fn["maxCircularity"]; + + filterByInertia = (int)fn["filterByInertia"] != 0 ? true : false; + minInertiaRatio = fn["minInertiaRatio"]; + maxInertiaRatio = fn["maxInertiaRatio"]; + + filterByConvexity = (int)fn["filterByConvexity"] != 0 ? true : false; + minConvexity = fn["minConvexity"]; + maxConvexity = fn["maxConvexity"]; +} + +void SimpleBlobDetector::Params::write(cv::FileStorage& fs) const +{ + fs << "thresholdStep" << thresholdStep; + fs << "minThreshold" << minThreshold; + fs << "maxThreshold" << maxThreshold; + + fs << "minRepeatability" << (int)minRepeatability; + fs << "minDistBetweenBlobs" << minDistBetweenBlobs; + + fs << "filterByColor" << (int)filterByColor; + fs << "blobColor" << (int)blobColor; + + fs << "filterByArea" << (int)filterByArea; + fs << "minArea" << minArea; + fs << "maxArea" << maxArea; + + fs << "filterByCircularity" << (int)filterByCircularity; + fs << "minCircularity" << minCircularity; + fs << "maxCircularity" << maxCircularity; + + fs << "filterByInertia" << (int)filterByInertia; + fs << "minInertiaRatio" << minInertiaRatio; + fs << "maxInertiaRatio" << maxInertiaRatio; + + fs << "filterByConvexity" << (int)filterByConvexity; + fs << "minConvexity" << minConvexity; + fs << "maxConvexity" << maxConvexity; +} + SimpleBlobDetector::SimpleBlobDetector(const SimpleBlobDetector::Params ¶meters) : params(parameters) { } +void SimpleBlobDetector::read( const cv::FileNode& fn ) +{ + params.read(fn); +} + +void SimpleBlobDetector::write( cv::FileStorage& fs ) const +{ + params.write(fs); +} + void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, vector
¢ers) const { (void)image; diff --git a/modules/features2d/src/brief.cpp b/modules/features2d/src/brief.cpp index bde3127590..29b5148bf6 100644 --- a/modules/features2d/src/brief.cpp +++ b/modules/features2d/src/brief.cpp @@ -188,6 +188,31 @@ int BriefDescriptorExtractor::descriptorType() const return CV_8UC1; } +void BriefDescriptorExtractor::read( const FileNode& fn) +{ + int descriptorSize = fn["descriptorSize"]; + switch (descriptorSize) + { + case 16: + test_fn_ = pixelTests16; + break; + case 32: + test_fn_ = pixelTests32; + break; + case 64: + test_fn_ = pixelTests64; + break; + default: + CV_Error(CV_StsBadArg, "descriptorSize must be 16, 32, or 64"); + } + bytes_ = descriptorSize; +} + +void BriefDescriptorExtractor::write( FileStorage& fs) const +{ + fs << "descriptorSize" << bytes_; +} + void BriefDescriptorExtractor::computeImpl(const Mat& image, std::vector& keypoints, Mat& descriptors) const { // Construct integral image for fast smoothing (box filter) diff --git a/modules/features2d/src/calonder.cpp b/modules/features2d/src/calonder.cpp index d7a74eea20..c933b20a0e 100644 --- a/modules/features2d/src/calonder.cpp +++ b/modules/features2d/src/calonder.cpp @@ -618,7 +618,7 @@ void RandomizedTree::write(std::ostream &os) const os.write((char*)(&classes_), sizeof(classes_)); os.write((char*)(&depth_), sizeof(depth_)); - os.write((char*)(&nodes_[0]), nodes_.size() * sizeof(nodes_[0])); + os.write((char*)(&nodes_[0]), (int)(nodes_.size() * sizeof(nodes_[0]))); for (int i=0; i FeatureDetector::create( const string& detectorType ) params.useHarrisDetector = true; fd = new GoodFeaturesToTrackDetector(params); } + else if( !detectorType.compare( "Dense" ) ) + { + fd = new DenseFeatureDetector(); + } + else if( !detectorType.compare( "SimpleBlob" ) ) + { + fd = new SimpleBlobDetector(); + } else if( (pos=detectorType.find("Grid")) == 0 ) { pos += string("Grid").size(); @@ -445,7 +453,7 @@ void ORB::CommonParams::read(const FileNode& fn) { scale_factor_ = fn["scaleFactor"]; n_levels_ = int(fn["nLevels"]); - first_level_ = int(fn["firsLevel"]); + first_level_ = int(fn["firstLevel"]); edge_threshold_ = fn["edgeThreshold"]; patch_size_ = fn["patchSize"]; } @@ -454,7 +462,7 @@ void ORB::CommonParams::write(FileStorage& fs) const { fs << "scaleFactor" << scale_factor_; fs << "nLevels" << int(n_levels_); - fs << "firsLevel" << int(first_level_); + fs << "firstLevel" << int(first_level_); fs << "edgeThreshold" << int(edge_threshold_); fs << "patchSize" << int(patch_size_); } @@ -499,9 +507,45 @@ DenseFeatureDetector::Params::Params( float _initFeatureScale, int _featureScale varyXyStepWithScale(_varyXyStepWithScale), varyImgBoundWithScale(_varyImgBoundWithScale) {} +void DenseFeatureDetector::Params::read( const FileNode& fn ) +{ + initFeatureScale = fn["initFeatureScale"]; + featureScaleLevels = fn["featureScaleLevels"]; + featureScaleMul = fn["featureScaleMul"]; + + initXyStep = fn["initXyStep"]; + initImgBound = fn["initImgBound"]; + + varyXyStepWithScale = (int)fn["varyXyStepWithScale"] != 0 ? true : false; + varyImgBoundWithScale = (int)fn["varyImgBoundWithScale"] != 0 ? true : false; +} + +void DenseFeatureDetector::Params::write( FileStorage& fs ) const +{ + fs << "initFeatureScale" << initFeatureScale; + fs << "featureScaleLevels" << featureScaleLevels; + fs << "featureScaleMul" << featureScaleMul; + + fs << "initXyStep" << initXyStep; + fs << "initImgBound" << initImgBound; + + fs << "varyXyStepWithScale" << (int)varyXyStepWithScale; + fs << "varyImgBoundWithScale" << (int)varyImgBoundWithScale; +} + DenseFeatureDetector::DenseFeatureDetector(const DenseFeatureDetector::Params &_params) : params(_params) {} +void DenseFeatureDetector::read( const FileNode &fn ) +{ + params.read(fn); +} + +void DenseFeatureDetector::write( FileStorage &fs ) const +{ + params.write(fs); +} + void DenseFeatureDetector::detectImpl( const Mat& image, vector& keypoints, const Mat& mask ) const { float curScale = params.initFeatureScale; @@ -575,8 +619,9 @@ void GridAdaptedFeatureDetector::detectImpl( const Mat& image, vector& vector sub_keypoints; detector->detect( sub_image, sub_keypoints, sub_mask ); keepStrongest( maxPerCell, sub_keypoints ); - for( std::vector::iterator it = sub_keypoints.begin(), end = sub_keypoints.end(); - it != end; ++it ) + std::vector::iterator it = sub_keypoints.begin(), + end = sub_keypoints.end(); + for( ; it != end; ++it ) { it->pt.x += col_range.start; it->pt.y += row_range.start; @@ -602,12 +647,25 @@ bool PyramidAdaptedFeatureDetector::empty() const void PyramidAdaptedFeatureDetector::detectImpl( const Mat& image, vector& keypoints, const Mat& mask ) const { Mat src = image; + Mat src_mask = mask; + + Mat dilated_mask; + if( !mask.empty() ) + { + dilate( mask, dilated_mask, Mat() ); + Mat mask255( mask.size(), CV_8UC1, Scalar(0) ); + mask255.setTo( Scalar(255), dilated_mask != 0 ); + dilated_mask = mask255; + } + for( int l = 0, multiplier = 1; l <= maxLevel; ++l, multiplier *= 2 ) { // Detect on current level of the pyramid vector new_pts; - detector->detect( src, new_pts, mask ); - for( vector::iterator it = new_pts.begin(), end = new_pts.end(); it != end; ++it) + detector->detect( src, new_pts, src_mask ); + vector::iterator it = new_pts.begin(), + end = new_pts.end(); + for( ; it != end; ++it) { it->pt.x *= multiplier; it->pt.y *= multiplier; @@ -620,10 +678,16 @@ void PyramidAdaptedFeatureDetector::detectImpl( const Mat& image, vector& keypoints, Mat& ou RNG& rng=theRNG(); bool isRandColor = _color == Scalar::all(-1); - for( vector::const_iterator i = keypoints.begin(), ie = keypoints.end(); i != ie; ++i ) + CV_Assert( !outImage.empty() ); + vector::const_iterator it = keypoints.begin(), + end = keypoints.end(); + for( ; it != end; ++it ) { Scalar color = isRandColor ? Scalar(rng(256), rng(256), rng(256)) : _color; - _drawKeypoint( outImage, *i, color, flags ); + _drawKeypoint( outImage, *it, color, flags ); } } diff --git a/modules/features2d/src/evaluation.cpp b/modules/features2d/src/evaluation.cpp index 0cf53a8033..ba1a76b818 100644 --- a/modules/features2d/src/evaluation.cpp +++ b/modules/features2d/src/evaluation.cpp @@ -388,7 +388,8 @@ static void calculateRepeatability( const Mat& img1, const Mat& img2, const Mat& thresholdedOverlapMask->create( (int)keypoints1.size(), (int)keypoints2t.size(), CV_8UC1 ); thresholdedOverlapMask->setTo( Scalar::all(0) ); } - size_t minCount = min( keypoints1.size(), keypoints2t.size() ); + size_t size1 = keypoints1.size(), size2 = keypoints2t.size(); + size_t minCount = MIN( size1, size2 ); // calculate overlap errors vector overlaps; diff --git a/modules/features2d/src/generated_16.i b/modules/features2d/src/generated_16.i index c6e7597cd2..b85bf06d9e 100644 --- a/modules/features2d/src/generated_16.i +++ b/modules/features2d/src/generated_16.i @@ -1,19 +1,19 @@ // Code generated with '$ scripts/generate_code.py src/test_pairs.txt 16' #define SMOOTHED(y,x) smoothedSum(sum, pt, y, x) - desc[0] = ((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0) ; - desc[1] = ((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0) ; - desc[2] = ((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0) ; - desc[3] = ((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0) ; - desc[4] = ((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0) ; - desc[5] = ((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0) ; - desc[6] = ((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0) ; - desc[7] = ((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0) ; - desc[8] = ((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0) ; - desc[9] = ((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0) ; - desc[10] = ((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0) ; - desc[11] = ((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0) ; - desc[12] = ((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0) ; - desc[13] = ((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0) ; - desc[14] = ((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0) ; - desc[15] = ((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0) ; + desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0)); + desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0)); + desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0)); + desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0)); + desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0)); + desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0)); + desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0)); + desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0)); + desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0)); + desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0)); + desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0)); + desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0)); + desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0)); + desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0)); + desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0)); + desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0)); #undef SMOOTHED diff --git a/modules/features2d/src/generated_32.i b/modules/features2d/src/generated_32.i index 0f13acfb23..19952d2f75 100644 --- a/modules/features2d/src/generated_32.i +++ b/modules/features2d/src/generated_32.i @@ -1,35 +1,35 @@ // Code generated with '$ scripts/generate_code.py src/test_pairs.txt 32' #define SMOOTHED(y,x) smoothedSum(sum, pt, y, x) - desc[0] = ((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0) ; - desc[1] = ((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0) ; - desc[2] = ((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0) ; - desc[3] = ((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0) ; - desc[4] = ((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0) ; - desc[5] = ((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0) ; - desc[6] = ((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0) ; - desc[7] = ((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0) ; - desc[8] = ((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0) ; - desc[9] = ((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0) ; - desc[10] = ((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0) ; - desc[11] = ((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0) ; - desc[12] = ((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0) ; - desc[13] = ((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0) ; - desc[14] = ((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0) ; - desc[15] = ((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0) ; - desc[16] = ((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0) ; - desc[17] = ((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0) ; - desc[18] = ((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0) ; - desc[19] = ((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0) ; - desc[20] = ((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0) ; - desc[21] = ((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0) ; - desc[22] = ((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0) ; - desc[23] = ((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0) ; - desc[24] = ((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0) ; - desc[25] = ((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0) ; - desc[26] = ((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0) ; - desc[27] = ((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0) ; - desc[28] = ((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0) ; - desc[29] = ((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0) ; - desc[30] = ((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0) ; - desc[31] = ((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0) ; + desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0)); + desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0)); + desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0)); + desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0)); + desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0)); + desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0)); + desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0)); + desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0)); + desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0)); + desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0)); + desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0)); + desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0)); + desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0)); + desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0)); + desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0)); + desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0)); + desc[16] = (uchar)(((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0)); + desc[17] = (uchar)(((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0)); + desc[18] = (uchar)(((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0)); + desc[19] = (uchar)(((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0)); + desc[20] = (uchar)(((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0)); + desc[21] = (uchar)(((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0)); + desc[22] = (uchar)(((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0)); + desc[23] = (uchar)(((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0)); + desc[24] = (uchar)(((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0)); + desc[25] = (uchar)(((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0)); + desc[26] = (uchar)(((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0)); + desc[27] = (uchar)(((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0)); + desc[28] = (uchar)(((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0)); + desc[29] = (uchar)(((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0)); + desc[30] = (uchar)(((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0)); + desc[31] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0)); #undef SMOOTHED diff --git a/modules/features2d/src/generated_64.i b/modules/features2d/src/generated_64.i index 3b47de7624..2262e2d412 100644 --- a/modules/features2d/src/generated_64.i +++ b/modules/features2d/src/generated_64.i @@ -1,67 +1,67 @@ // Code generated with '$ scripts/generate_code.py src/test_pairs.txt 64' #define SMOOTHED(y,x) smoothedSum(sum, pt, y, x) - desc[0] = ((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0) ; - desc[1] = ((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0) ; - desc[2] = ((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0) ; - desc[3] = ((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0) ; - desc[4] = ((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0) ; - desc[5] = ((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0) ; - desc[6] = ((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0) ; - desc[7] = ((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0) ; - desc[8] = ((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0) ; - desc[9] = ((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0) ; - desc[10] = ((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0) ; - desc[11] = ((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0) ; - desc[12] = ((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0) ; - desc[13] = ((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0) ; - desc[14] = ((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0) ; - desc[15] = ((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0) ; - desc[16] = ((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0) ; - desc[17] = ((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0) ; - desc[18] = ((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0) ; - desc[19] = ((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0) ; - desc[20] = ((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0) ; - desc[21] = ((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0) ; - desc[22] = ((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0) ; - desc[23] = ((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0) ; - desc[24] = ((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0) ; - desc[25] = ((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0) ; - desc[26] = ((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0) ; - desc[27] = ((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0) ; - desc[28] = ((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0) ; - desc[29] = ((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0) ; - desc[30] = ((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0) ; - desc[31] = ((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0) ; - desc[32] = ((SMOOTHED(16, 12) < SMOOTHED(0, 19)) << 7) + ((SMOOTHED(4, 3) < SMOOTHED(6, 0)) << 6) + ((SMOOTHED(-2, -1) < SMOOTHED(2, 17)) << 5) + ((SMOOTHED(8, 1) < SMOOTHED(3, 1)) << 4) + ((SMOOTHED(-12, -1) < SMOOTHED(-11, 0)) << 3) + ((SMOOTHED(-11, 2) < SMOOTHED(7, 9)) << 2) + ((SMOOTHED(-1, 3) < SMOOTHED(-19, 4)) << 1) + ((SMOOTHED(-1, -11) < SMOOTHED(-1, 3)) << 0) ; - desc[33] = ((SMOOTHED(1, -10) < SMOOTHED(-10, -4)) << 7) + ((SMOOTHED(-2, 3) < SMOOTHED(6, 11)) << 6) + ((SMOOTHED(3, 7) < SMOOTHED(-9, -8)) << 5) + ((SMOOTHED(24, -14) < SMOOTHED(-2, -10)) << 4) + ((SMOOTHED(-3, -3) < SMOOTHED(-18, -6)) << 3) + ((SMOOTHED(-13, -10) < SMOOTHED(-7, -1)) << 2) + ((SMOOTHED(2, -7) < SMOOTHED(9, -6)) << 1) + ((SMOOTHED(2, -4) < SMOOTHED(6, -13)) << 0) ; - desc[34] = ((SMOOTHED(4, -4) < SMOOTHED(-2, 3)) << 7) + ((SMOOTHED(-4, 2) < SMOOTHED(9, 13)) << 6) + ((SMOOTHED(-11, 5) < SMOOTHED(-6, -11)) << 5) + ((SMOOTHED(4, -2) < SMOOTHED(11, -9)) << 4) + ((SMOOTHED(-19, 0) < SMOOTHED(-23, -5)) << 3) + ((SMOOTHED(-5, -7) < SMOOTHED(-3, -6)) << 2) + ((SMOOTHED(-6, -4) < SMOOTHED(12, 14)) << 1) + ((SMOOTHED(12, -11) < SMOOTHED(-8, -16)) << 0) ; - desc[35] = ((SMOOTHED(-21, 15) < SMOOTHED(-12, 6)) << 7) + ((SMOOTHED(-2, -1) < SMOOTHED(-8, 16)) << 6) + ((SMOOTHED(6, -1) < SMOOTHED(-8, -2)) << 5) + ((SMOOTHED(1, -1) < SMOOTHED(-9, 8)) << 4) + ((SMOOTHED(3, -4) < SMOOTHED(-2, -2)) << 3) + ((SMOOTHED(-7, 0) < SMOOTHED(4, -8)) << 2) + ((SMOOTHED(11, -11) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(2, 3) < SMOOTHED(11, 7)) << 0) ; - desc[36] = ((SMOOTHED(-7, -4) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(3, -7) < SMOOTHED(-5, 0)) << 6) + ((SMOOTHED(3, -7) < SMOOTHED(-10, -5)) << 5) + ((SMOOTHED(-3, -1) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(0, 8) < SMOOTHED(5, 1)) << 3) + ((SMOOTHED(9, 0) < SMOOTHED(1, 16)) << 2) + ((SMOOTHED(8, 4) < SMOOTHED(-11, -3)) << 1) + ((SMOOTHED(-15, 9) < SMOOTHED(8, 17)) << 0) ; - desc[37] = ((SMOOTHED(0, 2) < SMOOTHED(-9, 17)) << 7) + ((SMOOTHED(-6, -11) < SMOOTHED(-10, -3)) << 6) + ((SMOOTHED(1, 1) < SMOOTHED(15, -8)) << 5) + ((SMOOTHED(-12, -13) < SMOOTHED(-2, 4)) << 4) + ((SMOOTHED(-6, 4) < SMOOTHED(-6, -10)) << 3) + ((SMOOTHED(5, -7) < SMOOTHED(7, -5)) << 2) + ((SMOOTHED(10, 6) < SMOOTHED(8, 9)) << 1) + ((SMOOTHED(-5, 7) < SMOOTHED(-18, -3)) << 0) ; - desc[38] = ((SMOOTHED(-6, 3) < SMOOTHED(5, 4)) << 7) + ((SMOOTHED(-10, -13) < SMOOTHED(-5, -3)) << 6) + ((SMOOTHED(-11, 2) < SMOOTHED(-16, 0)) << 5) + ((SMOOTHED(7, -21) < SMOOTHED(-5, -13)) << 4) + ((SMOOTHED(-14, -14) < SMOOTHED(-4, -4)) << 3) + ((SMOOTHED(4, 9) < SMOOTHED(7, -3)) << 2) + ((SMOOTHED(4, 11) < SMOOTHED(10, -4)) << 1) + ((SMOOTHED(6, 17) < SMOOTHED(9, 17)) << 0) ; - desc[39] = ((SMOOTHED(-10, 8) < SMOOTHED(0, -11)) << 7) + ((SMOOTHED(-6, -16) < SMOOTHED(-6, 8)) << 6) + ((SMOOTHED(-13, 5) < SMOOTHED(10, -5)) << 5) + ((SMOOTHED(3, 2) < SMOOTHED(12, 16)) << 4) + ((SMOOTHED(13, -8) < SMOOTHED(0, -6)) << 3) + ((SMOOTHED(10, 0) < SMOOTHED(4, -11)) << 2) + ((SMOOTHED(8, 5) < SMOOTHED(10, -2)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(-13, 3)) << 0) ; - desc[40] = ((SMOOTHED(2, 4) < SMOOTHED(-7, -3)) << 7) + ((SMOOTHED(-14, -2) < SMOOTHED(-11, 16)) << 6) + ((SMOOTHED(11, -6) < SMOOTHED(7, 6)) << 5) + ((SMOOTHED(-3, 15) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(-3, 8) < SMOOTHED(12, -12)) << 3) + ((SMOOTHED(-13, 6) < SMOOTHED(-14, 7)) << 2) + ((SMOOTHED(-11, -5) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(7, -6) < SMOOTHED(6, 3)) << 0) ; - desc[41] = ((SMOOTHED(-4, 10) < SMOOTHED(5, 1)) << 7) + ((SMOOTHED(9, 16) < SMOOTHED(10, 13)) << 6) + ((SMOOTHED(-17, 10) < SMOOTHED(2, 8)) << 5) + ((SMOOTHED(-5, 1) < SMOOTHED(4, -4)) << 4) + ((SMOOTHED(-14, 8) < SMOOTHED(-5, 2)) << 3) + ((SMOOTHED(4, -9) < SMOOTHED(-6, -3)) << 2) + ((SMOOTHED(3, -7) < SMOOTHED(-10, 0)) << 1) + ((SMOOTHED(-2, -8) < SMOOTHED(-10, 4)) << 0) ; - desc[42] = ((SMOOTHED(-8, 5) < SMOOTHED(-9, 24)) << 7) + ((SMOOTHED(2, -8) < SMOOTHED(8, -9)) << 6) + ((SMOOTHED(-4, 17) < SMOOTHED(-5, 2)) << 5) + ((SMOOTHED(14, 0) < SMOOTHED(-9, 9)) << 4) + ((SMOOTHED(11, 15) < SMOOTHED(-6, 5)) << 3) + ((SMOOTHED(-8, 1) < SMOOTHED(-3, 4)) << 2) + ((SMOOTHED(9, -21) < SMOOTHED(10, 2)) << 1) + ((SMOOTHED(2, -1) < SMOOTHED(4, 11)) << 0) ; - desc[43] = ((SMOOTHED(24, 3) < SMOOTHED(2, -2)) << 7) + ((SMOOTHED(-8, 17) < SMOOTHED(-14, -10)) << 6) + ((SMOOTHED(6, 5) < SMOOTHED(-13, 7)) << 5) + ((SMOOTHED(11, 10) < SMOOTHED(0, -1)) << 4) + ((SMOOTHED(4, 6) < SMOOTHED(-10, 6)) << 3) + ((SMOOTHED(-12, -2) < SMOOTHED(5, 6)) << 2) + ((SMOOTHED(3, -1) < SMOOTHED(8, -15)) << 1) + ((SMOOTHED(1, -4) < SMOOTHED(-7, 11)) << 0) ; - desc[44] = ((SMOOTHED(1, 11) < SMOOTHED(5, 0)) << 7) + ((SMOOTHED(6, -12) < SMOOTHED(10, 1)) << 6) + ((SMOOTHED(-3, -2) < SMOOTHED(-1, 4)) << 5) + ((SMOOTHED(-2, -11) < SMOOTHED(-1, 12)) << 4) + ((SMOOTHED(7, -8) < SMOOTHED(-20, -18)) << 3) + ((SMOOTHED(2, 0) < SMOOTHED(-9, 2)) << 2) + ((SMOOTHED(-13, -1) < SMOOTHED(-16, 2)) << 1) + ((SMOOTHED(3, -1) < SMOOTHED(-5, -17)) << 0) ; - desc[45] = ((SMOOTHED(15, 8) < SMOOTHED(3, -14)) << 7) + ((SMOOTHED(-13, -12) < SMOOTHED(6, 15)) << 6) + ((SMOOTHED(2, -8) < SMOOTHED(2, 6)) << 5) + ((SMOOTHED(6, 22) < SMOOTHED(-3, -23)) << 4) + ((SMOOTHED(-2, -7) < SMOOTHED(-6, 0)) << 3) + ((SMOOTHED(13, -10) < SMOOTHED(-6, 6)) << 2) + ((SMOOTHED(6, 7) < SMOOTHED(-10, 12)) << 1) + ((SMOOTHED(-6, 7) < SMOOTHED(-2, 11)) << 0) ; - desc[46] = ((SMOOTHED(0, -22) < SMOOTHED(-2, -17)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-11, -14)) << 6) + ((SMOOTHED(-2, -8) < SMOOTHED(7, 12)) << 5) + ((SMOOTHED(12, -5) < SMOOTHED(7, -13)) << 4) + ((SMOOTHED(2, -2) < SMOOTHED(-7, 6)) << 3) + ((SMOOTHED(0, 8) < SMOOTHED(-3, 23)) << 2) + ((SMOOTHED(6, 12) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(-21, -10) < SMOOTHED(10, 8)) << 0) ; - desc[47] = ((SMOOTHED(-3, 0) < SMOOTHED(7, 15)) << 7) + ((SMOOTHED(7, -6) < SMOOTHED(-5, -12)) << 6) + ((SMOOTHED(-21, -10) < SMOOTHED(12, -11)) << 5) + ((SMOOTHED(-5, -11) < SMOOTHED(8, -11)) << 4) + ((SMOOTHED(5, 0) < SMOOTHED(-11, -1)) << 3) + ((SMOOTHED(8, -9) < SMOOTHED(7, -1)) << 2) + ((SMOOTHED(11, -23) < SMOOTHED(21, -5)) << 1) + ((SMOOTHED(0, -5) < SMOOTHED(-8, 6)) << 0) ; - desc[48] = ((SMOOTHED(-6, 8) < SMOOTHED(8, 12)) << 7) + ((SMOOTHED(-7, 5) < SMOOTHED(3, -2)) << 6) + ((SMOOTHED(-5, -20) < SMOOTHED(-12, 9)) << 5) + ((SMOOTHED(-6, 12) < SMOOTHED(-11, 3)) << 4) + ((SMOOTHED(4, 5) < SMOOTHED(13, 11)) << 3) + ((SMOOTHED(2, 12) < SMOOTHED(13, -12)) << 2) + ((SMOOTHED(-4, -13) < SMOOTHED(4, 7)) << 1) + ((SMOOTHED(0, 15) < SMOOTHED(-3, -16)) << 0) ; - desc[49] = ((SMOOTHED(-3, 2) < SMOOTHED(-2, 14)) << 7) + ((SMOOTHED(4, -14) < SMOOTHED(16, -11)) << 6) + ((SMOOTHED(-13, 3) < SMOOTHED(23, 10)) << 5) + ((SMOOTHED(9, -19) < SMOOTHED(2, 5)) << 4) + ((SMOOTHED(5, 3) < SMOOTHED(14, -7)) << 3) + ((SMOOTHED(19, -13) < SMOOTHED(-11, 15)) << 2) + ((SMOOTHED(14, 0) < SMOOTHED(-2, -5)) << 1) + ((SMOOTHED(11, -4) < SMOOTHED(0, -6)) << 0) ; - desc[50] = ((SMOOTHED(-2, 5) < SMOOTHED(-13, -8)) << 7) + ((SMOOTHED(-11, -15) < SMOOTHED(-7, -17)) << 6) + ((SMOOTHED(1, 3) < SMOOTHED(-10, -8)) << 5) + ((SMOOTHED(-13, -10) < SMOOTHED(7, -12)) << 4) + ((SMOOTHED(0, -13) < SMOOTHED(23, -6)) << 3) + ((SMOOTHED(2, -17) < SMOOTHED(-7, -3)) << 2) + ((SMOOTHED(1, 3) < SMOOTHED(4, -10)) << 1) + ((SMOOTHED(13, 4) < SMOOTHED(14, -6)) << 0) ; - desc[51] = ((SMOOTHED(-19, -2) < SMOOTHED(-1, 5)) << 7) + ((SMOOTHED(9, -8) < SMOOTHED(10, -5)) << 6) + ((SMOOTHED(7, -1) < SMOOTHED(5, 7)) << 5) + ((SMOOTHED(9, -10) < SMOOTHED(19, 0)) << 4) + ((SMOOTHED(7, 5) < SMOOTHED(-4, -7)) << 3) + ((SMOOTHED(-11, 1) < SMOOTHED(-1, -11)) << 2) + ((SMOOTHED(2, -1) < SMOOTHED(-4, 11)) << 1) + ((SMOOTHED(-1, 7) < SMOOTHED(2, -2)) << 0) ; - desc[52] = ((SMOOTHED(1, -20) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(-4, -18) < SMOOTHED(8, -18)) << 6) + ((SMOOTHED(-16, -2) < SMOOTHED(7, -6)) << 5) + ((SMOOTHED(-3, -6) < SMOOTHED(-1, -4)) << 4) + ((SMOOTHED(0, -16) < SMOOTHED(24, -5)) << 3) + ((SMOOTHED(-4, -2) < SMOOTHED(-1, 9)) << 2) + ((SMOOTHED(-8, 2) < SMOOTHED(-6, 15)) << 1) + ((SMOOTHED(11, 4) < SMOOTHED(0, -3)) << 0) ; - desc[53] = ((SMOOTHED(7, 6) < SMOOTHED(2, -10)) << 7) + ((SMOOTHED(-7, -9) < SMOOTHED(12, -6)) << 6) + ((SMOOTHED(24, 15) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(15, -9) < SMOOTHED(-3, -15)) << 4) + ((SMOOTHED(17, -5) < SMOOTHED(11, -10)) << 3) + ((SMOOTHED(-2, 13) < SMOOTHED(-15, 4)) << 2) + ((SMOOTHED(-2, -1) < SMOOTHED(4, -23)) << 1) + ((SMOOTHED(-16, 3) < SMOOTHED(-7, -14)) << 0) ; - desc[54] = ((SMOOTHED(-3, -5) < SMOOTHED(-10, -9)) << 7) + ((SMOOTHED(-5, 3) < SMOOTHED(-2, -1)) << 6) + ((SMOOTHED(-1, 4) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(12, 9) < SMOOTHED(9, -14)) << 4) + ((SMOOTHED(-9, 17) < SMOOTHED(-3, 0)) << 3) + ((SMOOTHED(5, 4) < SMOOTHED(13, -6)) << 2) + ((SMOOTHED(-1, -8) < SMOOTHED(19, 10)) << 1) + ((SMOOTHED(8, -5) < SMOOTHED(-15, 2)) << 0) ; - desc[55] = ((SMOOTHED(-12, -9) < SMOOTHED(-4, -5)) << 7) + ((SMOOTHED(12, 0) < SMOOTHED(24, 4)) << 6) + ((SMOOTHED(8, -2) < SMOOTHED(14, 4)) << 5) + ((SMOOTHED(8, -4) < SMOOTHED(-7, 16)) << 4) + ((SMOOTHED(5, -1) < SMOOTHED(-8, -4)) << 3) + ((SMOOTHED(-2, 18) < SMOOTHED(-5, 17)) << 2) + ((SMOOTHED(8, -2) < SMOOTHED(-9, -2)) << 1) + ((SMOOTHED(3, -7) < SMOOTHED(1, -6)) << 0) ; - desc[56] = ((SMOOTHED(-5, -22) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, -10) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(-3, -13) < SMOOTHED(3, 9)) << 5) + ((SMOOTHED(-4, -1) < SMOOTHED(-1, 0)) << 4) + ((SMOOTHED(-7, -21) < SMOOTHED(12, -19)) << 3) + ((SMOOTHED(-8, 8) < SMOOTHED(24, 8)) << 2) + ((SMOOTHED(12, -6) < SMOOTHED(-2, 3)) << 1) + ((SMOOTHED(-5, -11) < SMOOTHED(-22, -4)) << 0) ; - desc[57] = ((SMOOTHED(-3, 5) < SMOOTHED(-4, 4)) << 7) + ((SMOOTHED(-16, 24) < SMOOTHED(7, -9)) << 6) + ((SMOOTHED(-10, 23) < SMOOTHED(-9, 18)) << 5) + ((SMOOTHED(1, 12) < SMOOTHED(17, 21)) << 4) + ((SMOOTHED(24, -6) < SMOOTHED(-3, -11)) << 3) + ((SMOOTHED(-7, 17) < SMOOTHED(1, -6)) << 2) + ((SMOOTHED(4, 4) < SMOOTHED(2, -7)) << 1) + ((SMOOTHED(14, 6) < SMOOTHED(-12, 3)) << 0) ; - desc[58] = ((SMOOTHED(-6, 0) < SMOOTHED(-16, 13)) << 7) + ((SMOOTHED(-10, 5) < SMOOTHED(7, 12)) << 6) + ((SMOOTHED(5, 2) < SMOOTHED(6, -3)) << 5) + ((SMOOTHED(7, 0) < SMOOTHED(-23, 1)) << 4) + ((SMOOTHED(15, -5) < SMOOTHED(1, 14)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(6, 6)) << 2) + ((SMOOTHED(6, -9) < SMOOTHED(-9, 12)) << 1) + ((SMOOTHED(4, -2) < SMOOTHED(-4, 7)) << 0) ; - desc[59] = ((SMOOTHED(-4, -5) < SMOOTHED(4, 4)) << 7) + ((SMOOTHED(-13, 0) < SMOOTHED(6, -10)) << 6) + ((SMOOTHED(2, -12) < SMOOTHED(-6, -3)) << 5) + ((SMOOTHED(16, 0) < SMOOTHED(-3, 3)) << 4) + ((SMOOTHED(5, -14) < SMOOTHED(6, 11)) << 3) + ((SMOOTHED(5, 11) < SMOOTHED(0, -13)) << 2) + ((SMOOTHED(7, 5) < SMOOTHED(-1, -5)) << 1) + ((SMOOTHED(12, 4) < SMOOTHED(6, 10)) << 0) ; - desc[60] = ((SMOOTHED(-10, 4) < SMOOTHED(-1, -11)) << 7) + ((SMOOTHED(4, 10) < SMOOTHED(-14, 5)) << 6) + ((SMOOTHED(11, -14) < SMOOTHED(-13, 0)) << 5) + ((SMOOTHED(2, 8) < SMOOTHED(12, 24)) << 4) + ((SMOOTHED(-1, 3) < SMOOTHED(-1, 2)) << 3) + ((SMOOTHED(9, -14) < SMOOTHED(-23, 3)) << 2) + ((SMOOTHED(-8, -6) < SMOOTHED(0, 9)) << 1) + ((SMOOTHED(-15, 14) < SMOOTHED(10, -10)) << 0) ; - desc[61] = ((SMOOTHED(-10, -6) < SMOOTHED(-7, -5)) << 7) + ((SMOOTHED(11, 5) < SMOOTHED(-3, -15)) << 6) + ((SMOOTHED(1, 0) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(-11, -6) < SMOOTHED(-4, -18)) << 4) + ((SMOOTHED(9, 0) < SMOOTHED(22, -4)) << 3) + ((SMOOTHED(-5, -1) < SMOOTHED(-9, 4)) << 2) + ((SMOOTHED(-20, 2) < SMOOTHED(1, 6)) << 1) + ((SMOOTHED(1, 2) < SMOOTHED(-9, -12)) << 0) ; - desc[62] = ((SMOOTHED(5, 15) < SMOOTHED(4, -6)) << 7) + ((SMOOTHED(19, 4) < SMOOTHED(4, 11)) << 6) + ((SMOOTHED(17, -4) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(-8, -12) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(11, 9) < SMOOTHED(8, 1)) << 3) + ((SMOOTHED(9, 22) < SMOOTHED(-15, 15)) << 2) + ((SMOOTHED(-7, -7) < SMOOTHED(1, -23)) << 1) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 2)) << 0) ; - desc[63] = ((SMOOTHED(3, -5) < SMOOTHED(11, -11)) << 7) + ((SMOOTHED(3, -18) < SMOOTHED(14, -5)) << 6) + ((SMOOTHED(-20, 7) < SMOOTHED(-10, -23)) << 5) + ((SMOOTHED(-2, -5) < SMOOTHED(6, 0)) << 4) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 3) + ((SMOOTHED(-6, -1) < SMOOTHED(14, -2)) << 2) + ((SMOOTHED(-12, -16) < SMOOTHED(15, 6)) << 1) + ((SMOOTHED(-12, -2) < SMOOTHED(3, -19)) << 0) ; + desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0)); + desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0)); + desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0)); + desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0)); + desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0)); + desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0)); + desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0)); + desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0)); + desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0)); + desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0)); + desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0)); + desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0)); + desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0)); + desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0)); + desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0)); + desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0)); + desc[16] = (uchar)(((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0)); + desc[17] = (uchar)(((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0)); + desc[18] = (uchar)(((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0)); + desc[19] = (uchar)(((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0)); + desc[20] = (uchar)(((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0)); + desc[21] = (uchar)(((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0)); + desc[22] = (uchar)(((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0)); + desc[23] = (uchar)(((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0)); + desc[24] = (uchar)(((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0)); + desc[25] = (uchar)(((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0)); + desc[26] = (uchar)(((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0)); + desc[27] = (uchar)(((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0)); + desc[28] = (uchar)(((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0)); + desc[29] = (uchar)(((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0)); + desc[30] = (uchar)(((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0)); + desc[31] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0)); + desc[32] = (uchar)(((SMOOTHED(16, 12) < SMOOTHED(0, 19)) << 7) + ((SMOOTHED(4, 3) < SMOOTHED(6, 0)) << 6) + ((SMOOTHED(-2, -1) < SMOOTHED(2, 17)) << 5) + ((SMOOTHED(8, 1) < SMOOTHED(3, 1)) << 4) + ((SMOOTHED(-12, -1) < SMOOTHED(-11, 0)) << 3) + ((SMOOTHED(-11, 2) < SMOOTHED(7, 9)) << 2) + ((SMOOTHED(-1, 3) < SMOOTHED(-19, 4)) << 1) + ((SMOOTHED(-1, -11) < SMOOTHED(-1, 3)) << 0)); + desc[33] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-10, -4)) << 7) + ((SMOOTHED(-2, 3) < SMOOTHED(6, 11)) << 6) + ((SMOOTHED(3, 7) < SMOOTHED(-9, -8)) << 5) + ((SMOOTHED(24, -14) < SMOOTHED(-2, -10)) << 4) + ((SMOOTHED(-3, -3) < SMOOTHED(-18, -6)) << 3) + ((SMOOTHED(-13, -10) < SMOOTHED(-7, -1)) << 2) + ((SMOOTHED(2, -7) < SMOOTHED(9, -6)) << 1) + ((SMOOTHED(2, -4) < SMOOTHED(6, -13)) << 0)); + desc[34] = (uchar)(((SMOOTHED(4, -4) < SMOOTHED(-2, 3)) << 7) + ((SMOOTHED(-4, 2) < SMOOTHED(9, 13)) << 6) + ((SMOOTHED(-11, 5) < SMOOTHED(-6, -11)) << 5) + ((SMOOTHED(4, -2) < SMOOTHED(11, -9)) << 4) + ((SMOOTHED(-19, 0) < SMOOTHED(-23, -5)) << 3) + ((SMOOTHED(-5, -7) < SMOOTHED(-3, -6)) << 2) + ((SMOOTHED(-6, -4) < SMOOTHED(12, 14)) << 1) + ((SMOOTHED(12, -11) < SMOOTHED(-8, -16)) << 0)); + desc[35] = (uchar)(((SMOOTHED(-21, 15) < SMOOTHED(-12, 6)) << 7) + ((SMOOTHED(-2, -1) < SMOOTHED(-8, 16)) << 6) + ((SMOOTHED(6, -1) < SMOOTHED(-8, -2)) << 5) + ((SMOOTHED(1, -1) < SMOOTHED(-9, 8)) << 4) + ((SMOOTHED(3, -4) < SMOOTHED(-2, -2)) << 3) + ((SMOOTHED(-7, 0) < SMOOTHED(4, -8)) << 2) + ((SMOOTHED(11, -11) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(2, 3) < SMOOTHED(11, 7)) << 0)); + desc[36] = (uchar)(((SMOOTHED(-7, -4) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(3, -7) < SMOOTHED(-5, 0)) << 6) + ((SMOOTHED(3, -7) < SMOOTHED(-10, -5)) << 5) + ((SMOOTHED(-3, -1) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(0, 8) < SMOOTHED(5, 1)) << 3) + ((SMOOTHED(9, 0) < SMOOTHED(1, 16)) << 2) + ((SMOOTHED(8, 4) < SMOOTHED(-11, -3)) << 1) + ((SMOOTHED(-15, 9) < SMOOTHED(8, 17)) << 0)); + desc[37] = (uchar)(((SMOOTHED(0, 2) < SMOOTHED(-9, 17)) << 7) + ((SMOOTHED(-6, -11) < SMOOTHED(-10, -3)) << 6) + ((SMOOTHED(1, 1) < SMOOTHED(15, -8)) << 5) + ((SMOOTHED(-12, -13) < SMOOTHED(-2, 4)) << 4) + ((SMOOTHED(-6, 4) < SMOOTHED(-6, -10)) << 3) + ((SMOOTHED(5, -7) < SMOOTHED(7, -5)) << 2) + ((SMOOTHED(10, 6) < SMOOTHED(8, 9)) << 1) + ((SMOOTHED(-5, 7) < SMOOTHED(-18, -3)) << 0)); + desc[38] = (uchar)(((SMOOTHED(-6, 3) < SMOOTHED(5, 4)) << 7) + ((SMOOTHED(-10, -13) < SMOOTHED(-5, -3)) << 6) + ((SMOOTHED(-11, 2) < SMOOTHED(-16, 0)) << 5) + ((SMOOTHED(7, -21) < SMOOTHED(-5, -13)) << 4) + ((SMOOTHED(-14, -14) < SMOOTHED(-4, -4)) << 3) + ((SMOOTHED(4, 9) < SMOOTHED(7, -3)) << 2) + ((SMOOTHED(4, 11) < SMOOTHED(10, -4)) << 1) + ((SMOOTHED(6, 17) < SMOOTHED(9, 17)) << 0)); + desc[39] = (uchar)(((SMOOTHED(-10, 8) < SMOOTHED(0, -11)) << 7) + ((SMOOTHED(-6, -16) < SMOOTHED(-6, 8)) << 6) + ((SMOOTHED(-13, 5) < SMOOTHED(10, -5)) << 5) + ((SMOOTHED(3, 2) < SMOOTHED(12, 16)) << 4) + ((SMOOTHED(13, -8) < SMOOTHED(0, -6)) << 3) + ((SMOOTHED(10, 0) < SMOOTHED(4, -11)) << 2) + ((SMOOTHED(8, 5) < SMOOTHED(10, -2)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(-13, 3)) << 0)); + desc[40] = (uchar)(((SMOOTHED(2, 4) < SMOOTHED(-7, -3)) << 7) + ((SMOOTHED(-14, -2) < SMOOTHED(-11, 16)) << 6) + ((SMOOTHED(11, -6) < SMOOTHED(7, 6)) << 5) + ((SMOOTHED(-3, 15) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(-3, 8) < SMOOTHED(12, -12)) << 3) + ((SMOOTHED(-13, 6) < SMOOTHED(-14, 7)) << 2) + ((SMOOTHED(-11, -5) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(7, -6) < SMOOTHED(6, 3)) << 0)); + desc[41] = (uchar)(((SMOOTHED(-4, 10) < SMOOTHED(5, 1)) << 7) + ((SMOOTHED(9, 16) < SMOOTHED(10, 13)) << 6) + ((SMOOTHED(-17, 10) < SMOOTHED(2, 8)) << 5) + ((SMOOTHED(-5, 1) < SMOOTHED(4, -4)) << 4) + ((SMOOTHED(-14, 8) < SMOOTHED(-5, 2)) << 3) + ((SMOOTHED(4, -9) < SMOOTHED(-6, -3)) << 2) + ((SMOOTHED(3, -7) < SMOOTHED(-10, 0)) << 1) + ((SMOOTHED(-2, -8) < SMOOTHED(-10, 4)) << 0)); + desc[42] = (uchar)(((SMOOTHED(-8, 5) < SMOOTHED(-9, 24)) << 7) + ((SMOOTHED(2, -8) < SMOOTHED(8, -9)) << 6) + ((SMOOTHED(-4, 17) < SMOOTHED(-5, 2)) << 5) + ((SMOOTHED(14, 0) < SMOOTHED(-9, 9)) << 4) + ((SMOOTHED(11, 15) < SMOOTHED(-6, 5)) << 3) + ((SMOOTHED(-8, 1) < SMOOTHED(-3, 4)) << 2) + ((SMOOTHED(9, -21) < SMOOTHED(10, 2)) << 1) + ((SMOOTHED(2, -1) < SMOOTHED(4, 11)) << 0)); + desc[43] = (uchar)(((SMOOTHED(24, 3) < SMOOTHED(2, -2)) << 7) + ((SMOOTHED(-8, 17) < SMOOTHED(-14, -10)) << 6) + ((SMOOTHED(6, 5) < SMOOTHED(-13, 7)) << 5) + ((SMOOTHED(11, 10) < SMOOTHED(0, -1)) << 4) + ((SMOOTHED(4, 6) < SMOOTHED(-10, 6)) << 3) + ((SMOOTHED(-12, -2) < SMOOTHED(5, 6)) << 2) + ((SMOOTHED(3, -1) < SMOOTHED(8, -15)) << 1) + ((SMOOTHED(1, -4) < SMOOTHED(-7, 11)) << 0)); + desc[44] = (uchar)(((SMOOTHED(1, 11) < SMOOTHED(5, 0)) << 7) + ((SMOOTHED(6, -12) < SMOOTHED(10, 1)) << 6) + ((SMOOTHED(-3, -2) < SMOOTHED(-1, 4)) << 5) + ((SMOOTHED(-2, -11) < SMOOTHED(-1, 12)) << 4) + ((SMOOTHED(7, -8) < SMOOTHED(-20, -18)) << 3) + ((SMOOTHED(2, 0) < SMOOTHED(-9, 2)) << 2) + ((SMOOTHED(-13, -1) < SMOOTHED(-16, 2)) << 1) + ((SMOOTHED(3, -1) < SMOOTHED(-5, -17)) << 0)); + desc[45] = (uchar)(((SMOOTHED(15, 8) < SMOOTHED(3, -14)) << 7) + ((SMOOTHED(-13, -12) < SMOOTHED(6, 15)) << 6) + ((SMOOTHED(2, -8) < SMOOTHED(2, 6)) << 5) + ((SMOOTHED(6, 22) < SMOOTHED(-3, -23)) << 4) + ((SMOOTHED(-2, -7) < SMOOTHED(-6, 0)) << 3) + ((SMOOTHED(13, -10) < SMOOTHED(-6, 6)) << 2) + ((SMOOTHED(6, 7) < SMOOTHED(-10, 12)) << 1) + ((SMOOTHED(-6, 7) < SMOOTHED(-2, 11)) << 0)); + desc[46] = (uchar)(((SMOOTHED(0, -22) < SMOOTHED(-2, -17)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-11, -14)) << 6) + ((SMOOTHED(-2, -8) < SMOOTHED(7, 12)) << 5) + ((SMOOTHED(12, -5) < SMOOTHED(7, -13)) << 4) + ((SMOOTHED(2, -2) < SMOOTHED(-7, 6)) << 3) + ((SMOOTHED(0, 8) < SMOOTHED(-3, 23)) << 2) + ((SMOOTHED(6, 12) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(-21, -10) < SMOOTHED(10, 8)) << 0)); + desc[47] = (uchar)(((SMOOTHED(-3, 0) < SMOOTHED(7, 15)) << 7) + ((SMOOTHED(7, -6) < SMOOTHED(-5, -12)) << 6) + ((SMOOTHED(-21, -10) < SMOOTHED(12, -11)) << 5) + ((SMOOTHED(-5, -11) < SMOOTHED(8, -11)) << 4) + ((SMOOTHED(5, 0) < SMOOTHED(-11, -1)) << 3) + ((SMOOTHED(8, -9) < SMOOTHED(7, -1)) << 2) + ((SMOOTHED(11, -23) < SMOOTHED(21, -5)) << 1) + ((SMOOTHED(0, -5) < SMOOTHED(-8, 6)) << 0)); + desc[48] = (uchar)(((SMOOTHED(-6, 8) < SMOOTHED(8, 12)) << 7) + ((SMOOTHED(-7, 5) < SMOOTHED(3, -2)) << 6) + ((SMOOTHED(-5, -20) < SMOOTHED(-12, 9)) << 5) + ((SMOOTHED(-6, 12) < SMOOTHED(-11, 3)) << 4) + ((SMOOTHED(4, 5) < SMOOTHED(13, 11)) << 3) + ((SMOOTHED(2, 12) < SMOOTHED(13, -12)) << 2) + ((SMOOTHED(-4, -13) < SMOOTHED(4, 7)) << 1) + ((SMOOTHED(0, 15) < SMOOTHED(-3, -16)) << 0)); + desc[49] = (uchar)(((SMOOTHED(-3, 2) < SMOOTHED(-2, 14)) << 7) + ((SMOOTHED(4, -14) < SMOOTHED(16, -11)) << 6) + ((SMOOTHED(-13, 3) < SMOOTHED(23, 10)) << 5) + ((SMOOTHED(9, -19) < SMOOTHED(2, 5)) << 4) + ((SMOOTHED(5, 3) < SMOOTHED(14, -7)) << 3) + ((SMOOTHED(19, -13) < SMOOTHED(-11, 15)) << 2) + ((SMOOTHED(14, 0) < SMOOTHED(-2, -5)) << 1) + ((SMOOTHED(11, -4) < SMOOTHED(0, -6)) << 0)); + desc[50] = (uchar)(((SMOOTHED(-2, 5) < SMOOTHED(-13, -8)) << 7) + ((SMOOTHED(-11, -15) < SMOOTHED(-7, -17)) << 6) + ((SMOOTHED(1, 3) < SMOOTHED(-10, -8)) << 5) + ((SMOOTHED(-13, -10) < SMOOTHED(7, -12)) << 4) + ((SMOOTHED(0, -13) < SMOOTHED(23, -6)) << 3) + ((SMOOTHED(2, -17) < SMOOTHED(-7, -3)) << 2) + ((SMOOTHED(1, 3) < SMOOTHED(4, -10)) << 1) + ((SMOOTHED(13, 4) < SMOOTHED(14, -6)) << 0)); + desc[51] = (uchar)(((SMOOTHED(-19, -2) < SMOOTHED(-1, 5)) << 7) + ((SMOOTHED(9, -8) < SMOOTHED(10, -5)) << 6) + ((SMOOTHED(7, -1) < SMOOTHED(5, 7)) << 5) + ((SMOOTHED(9, -10) < SMOOTHED(19, 0)) << 4) + ((SMOOTHED(7, 5) < SMOOTHED(-4, -7)) << 3) + ((SMOOTHED(-11, 1) < SMOOTHED(-1, -11)) << 2) + ((SMOOTHED(2, -1) < SMOOTHED(-4, 11)) << 1) + ((SMOOTHED(-1, 7) < SMOOTHED(2, -2)) << 0)); + desc[52] = (uchar)(((SMOOTHED(1, -20) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(-4, -18) < SMOOTHED(8, -18)) << 6) + ((SMOOTHED(-16, -2) < SMOOTHED(7, -6)) << 5) + ((SMOOTHED(-3, -6) < SMOOTHED(-1, -4)) << 4) + ((SMOOTHED(0, -16) < SMOOTHED(24, -5)) << 3) + ((SMOOTHED(-4, -2) < SMOOTHED(-1, 9)) << 2) + ((SMOOTHED(-8, 2) < SMOOTHED(-6, 15)) << 1) + ((SMOOTHED(11, 4) < SMOOTHED(0, -3)) << 0)); + desc[53] = (uchar)(((SMOOTHED(7, 6) < SMOOTHED(2, -10)) << 7) + ((SMOOTHED(-7, -9) < SMOOTHED(12, -6)) << 6) + ((SMOOTHED(24, 15) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(15, -9) < SMOOTHED(-3, -15)) << 4) + ((SMOOTHED(17, -5) < SMOOTHED(11, -10)) << 3) + ((SMOOTHED(-2, 13) < SMOOTHED(-15, 4)) << 2) + ((SMOOTHED(-2, -1) < SMOOTHED(4, -23)) << 1) + ((SMOOTHED(-16, 3) < SMOOTHED(-7, -14)) << 0)); + desc[54] = (uchar)(((SMOOTHED(-3, -5) < SMOOTHED(-10, -9)) << 7) + ((SMOOTHED(-5, 3) < SMOOTHED(-2, -1)) << 6) + ((SMOOTHED(-1, 4) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(12, 9) < SMOOTHED(9, -14)) << 4) + ((SMOOTHED(-9, 17) < SMOOTHED(-3, 0)) << 3) + ((SMOOTHED(5, 4) < SMOOTHED(13, -6)) << 2) + ((SMOOTHED(-1, -8) < SMOOTHED(19, 10)) << 1) + ((SMOOTHED(8, -5) < SMOOTHED(-15, 2)) << 0)); + desc[55] = (uchar)(((SMOOTHED(-12, -9) < SMOOTHED(-4, -5)) << 7) + ((SMOOTHED(12, 0) < SMOOTHED(24, 4)) << 6) + ((SMOOTHED(8, -2) < SMOOTHED(14, 4)) << 5) + ((SMOOTHED(8, -4) < SMOOTHED(-7, 16)) << 4) + ((SMOOTHED(5, -1) < SMOOTHED(-8, -4)) << 3) + ((SMOOTHED(-2, 18) < SMOOTHED(-5, 17)) << 2) + ((SMOOTHED(8, -2) < SMOOTHED(-9, -2)) << 1) + ((SMOOTHED(3, -7) < SMOOTHED(1, -6)) << 0)); + desc[56] = (uchar)(((SMOOTHED(-5, -22) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, -10) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(-3, -13) < SMOOTHED(3, 9)) << 5) + ((SMOOTHED(-4, -1) < SMOOTHED(-1, 0)) << 4) + ((SMOOTHED(-7, -21) < SMOOTHED(12, -19)) << 3) + ((SMOOTHED(-8, 8) < SMOOTHED(24, 8)) << 2) + ((SMOOTHED(12, -6) < SMOOTHED(-2, 3)) << 1) + ((SMOOTHED(-5, -11) < SMOOTHED(-22, -4)) << 0)); + desc[57] = (uchar)(((SMOOTHED(-3, 5) < SMOOTHED(-4, 4)) << 7) + ((SMOOTHED(-16, 24) < SMOOTHED(7, -9)) << 6) + ((SMOOTHED(-10, 23) < SMOOTHED(-9, 18)) << 5) + ((SMOOTHED(1, 12) < SMOOTHED(17, 21)) << 4) + ((SMOOTHED(24, -6) < SMOOTHED(-3, -11)) << 3) + ((SMOOTHED(-7, 17) < SMOOTHED(1, -6)) << 2) + ((SMOOTHED(4, 4) < SMOOTHED(2, -7)) << 1) + ((SMOOTHED(14, 6) < SMOOTHED(-12, 3)) << 0)); + desc[58] = (uchar)(((SMOOTHED(-6, 0) < SMOOTHED(-16, 13)) << 7) + ((SMOOTHED(-10, 5) < SMOOTHED(7, 12)) << 6) + ((SMOOTHED(5, 2) < SMOOTHED(6, -3)) << 5) + ((SMOOTHED(7, 0) < SMOOTHED(-23, 1)) << 4) + ((SMOOTHED(15, -5) < SMOOTHED(1, 14)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(6, 6)) << 2) + ((SMOOTHED(6, -9) < SMOOTHED(-9, 12)) << 1) + ((SMOOTHED(4, -2) < SMOOTHED(-4, 7)) << 0)); + desc[59] = (uchar)(((SMOOTHED(-4, -5) < SMOOTHED(4, 4)) << 7) + ((SMOOTHED(-13, 0) < SMOOTHED(6, -10)) << 6) + ((SMOOTHED(2, -12) < SMOOTHED(-6, -3)) << 5) + ((SMOOTHED(16, 0) < SMOOTHED(-3, 3)) << 4) + ((SMOOTHED(5, -14) < SMOOTHED(6, 11)) << 3) + ((SMOOTHED(5, 11) < SMOOTHED(0, -13)) << 2) + ((SMOOTHED(7, 5) < SMOOTHED(-1, -5)) << 1) + ((SMOOTHED(12, 4) < SMOOTHED(6, 10)) << 0)); + desc[60] = (uchar)(((SMOOTHED(-10, 4) < SMOOTHED(-1, -11)) << 7) + ((SMOOTHED(4, 10) < SMOOTHED(-14, 5)) << 6) + ((SMOOTHED(11, -14) < SMOOTHED(-13, 0)) << 5) + ((SMOOTHED(2, 8) < SMOOTHED(12, 24)) << 4) + ((SMOOTHED(-1, 3) < SMOOTHED(-1, 2)) << 3) + ((SMOOTHED(9, -14) < SMOOTHED(-23, 3)) << 2) + ((SMOOTHED(-8, -6) < SMOOTHED(0, 9)) << 1) + ((SMOOTHED(-15, 14) < SMOOTHED(10, -10)) << 0)); + desc[61] = (uchar)(((SMOOTHED(-10, -6) < SMOOTHED(-7, -5)) << 7) + ((SMOOTHED(11, 5) < SMOOTHED(-3, -15)) << 6) + ((SMOOTHED(1, 0) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(-11, -6) < SMOOTHED(-4, -18)) << 4) + ((SMOOTHED(9, 0) < SMOOTHED(22, -4)) << 3) + ((SMOOTHED(-5, -1) < SMOOTHED(-9, 4)) << 2) + ((SMOOTHED(-20, 2) < SMOOTHED(1, 6)) << 1) + ((SMOOTHED(1, 2) < SMOOTHED(-9, -12)) << 0)); + desc[62] = (uchar)(((SMOOTHED(5, 15) < SMOOTHED(4, -6)) << 7) + ((SMOOTHED(19, 4) < SMOOTHED(4, 11)) << 6) + ((SMOOTHED(17, -4) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(-8, -12) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(11, 9) < SMOOTHED(8, 1)) << 3) + ((SMOOTHED(9, 22) < SMOOTHED(-15, 15)) << 2) + ((SMOOTHED(-7, -7) < SMOOTHED(1, -23)) << 1) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 2)) << 0)); + desc[63] = (uchar)(((SMOOTHED(3, -5) < SMOOTHED(11, -11)) << 7) + ((SMOOTHED(3, -18) < SMOOTHED(14, -5)) << 6) + ((SMOOTHED(-20, 7) < SMOOTHED(-10, -23)) << 5) + ((SMOOTHED(-2, -5) < SMOOTHED(6, 0)) << 4) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 3) + ((SMOOTHED(-6, -1) < SMOOTHED(14, -2)) << 2) + ((SMOOTHED(-12, -16) < SMOOTHED(15, 6)) << 1) + ((SMOOTHED(-12, -2) < SMOOTHED(3, -19)) << 0)); #undef SMOOTHED diff --git a/modules/features2d/src/keypoint.cpp b/modules/features2d/src/keypoint.cpp index 01717f76da..f71186d16f 100644 --- a/modules/features2d/src/keypoint.cpp +++ b/modules/features2d/src/keypoint.cpp @@ -119,6 +119,7 @@ void KeyPoint::convert(const std::vector& keypoints, std::vector& points2f, std::vector& keypoints, float size, float response, int octave, int class_id ) { + keypoints.resize(points2f.size()); for( size_t i = 0; i < points2f.size(); i++ ) keypoints[i] = KeyPoint(points2f[i], size, -1, response, octave, class_id); } diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index 1093901157..795cc1afeb 100755 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -328,6 +328,10 @@ Ptr DescriptorMatcher::create( const string& descriptorMatche { dm = new BruteForceMatcher >(); } + else if( !descriptorMatcherType.compare( "BruteForce-SL2" ) ) // Squared L2 + { + dm = new BruteForceMatcher >(); + } else if( !descriptorMatcherType.compare( "BruteForce-L1" ) ) { dm = new BruteForceMatcher >(); @@ -345,10 +349,10 @@ Ptr DescriptorMatcher::create( const string& descriptorMatche } /* - * BruteForce L2 specialization + * BruteForce SL2 and L2 specialization */ template<> -void BruteForceMatcher >::knnMatchImpl( const Mat& queryDescriptors, vector >& matches, int knn, +void BruteForceMatcher >::knnMatchImpl( const Mat& queryDescriptors, vector >& matches, int knn, const vector& masks, bool compactResult ) { #ifndef HAVE_EIGEN @@ -427,7 +431,7 @@ void BruteForceMatcher >::knnMatchImpl( const Mat& queryDescriptors, v break; e_allDists[bestImgIdx](bestTrainIdx) = -std::numeric_limits::max(); - curMatches->push_back( DMatch(qIdx, bestTrainIdx, bestImgIdx, sqrt((-2)*totalMaxCoeff + queryNorm2)) ); + curMatches->push_back( DMatch(qIdx, bestTrainIdx, bestImgIdx, (-2)*totalMaxCoeff + queryNorm2) ); } std::sort( curMatches->begin(), curMatches->end() ); } @@ -436,7 +440,7 @@ void BruteForceMatcher >::knnMatchImpl( const Mat& queryDescriptors, v } template<> -void BruteForceMatcher >::radiusMatchImpl( const Mat& queryDescriptors, vector >& matches, float maxDistance, +void BruteForceMatcher >::radiusMatchImpl( const Mat& queryDescriptors, vector >& matches, float maxDistance, const vector& masks, bool compactResult ) { #ifndef HAVE_EIGEN @@ -492,7 +496,7 @@ void BruteForceMatcher >::radiusMatchImpl( const Mat& queryDescriptors { if( masks.empty() || isPossibleMatch(masks[iIdx], qIdx, tIdx) ) { - float d = sqrt((-2)*e_allDists[iIdx](tIdx) + queryNorm2); + float d = (-2)*e_allDists[iIdx](tIdx) + queryNorm2; if( d < maxDistance ) curMatches->push_back( DMatch( qIdx, tIdx, iIdx, d ) ); } @@ -504,6 +508,40 @@ void BruteForceMatcher >::radiusMatchImpl( const Mat& queryDescriptors #endif } +inline void sqrtDistance( vector >& matches ) +{ + for( size_t imgIdx = 0; imgIdx < matches.size(); imgIdx++ ) + { + for( size_t matchIdx = 0; matchIdx < matches[imgIdx].size(); matchIdx++ ) + { + matches[imgIdx][matchIdx].distance = std::sqrt( matches[imgIdx][matchIdx].distance ); + } + } +} + +template<> +void BruteForceMatcher >::knnMatchImpl( const Mat& queryDescriptors, vector >& matches, int knn, + const vector& masks, bool compactResult ) +{ + BruteForceMatcher > matcherSL2; + matcherSL2.add( getTrainDescriptors() ); + matcherSL2.knnMatch( queryDescriptors, matches, knn, masks, compactResult ); + + sqrtDistance( matches ); +} + +template<> +void BruteForceMatcher >::radiusMatchImpl( const Mat& queryDescriptors, vector >& matches, float maxDistance, + const vector& masks, bool compactResult ) +{ + const float maxDistance2 = maxDistance * maxDistance; + BruteForceMatcher > matcherSL2; + matcherSL2.add( getTrainDescriptors() ); + matcherSL2.radiusMatch( queryDescriptors, matches, maxDistance2, masks, compactResult ); + + sqrtDistance( matches ); +} + /* * Flann based matcher */ @@ -542,6 +580,195 @@ void FlannBasedMatcher::train() } } +void FlannBasedMatcher::read( const FileNode& fn) +{ + if (indexParams == 0) + indexParams = new flann::IndexParams(); + + FileNode ip = fn["indexParams"]; + CV_Assert(ip.type() == FileNode::SEQ); + + for(size_t i = 0; i < ip.size(); ++i) + { + CV_Assert(ip[i].type() == FileNode::MAP); + std::string name = (std::string)ip[i]["name"]; + int type = (int)ip[i]["type"]; + + switch(type) + { + case CV_8U: + case CV_8S: + case CV_16U: + case CV_16S: + case CV_32S: + indexParams->setInt(name, (int) ip[i]["value"]); + break; + case CV_32F: + indexParams->setFloat(name, (float) ip[i]["value"]); + break; + case CV_64F: + indexParams->setDouble(name, (double) ip[i]["value"]); + break; + case CV_USRTYPE1: + indexParams->setString(name, (std::string) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,2): + indexParams->setBool(name, (int) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,3): + indexParams->setAlgorithm(name, (int) ip[i]["value"]); + break; + }; + } + + if (searchParams == 0) + searchParams = new flann::SearchParams(); + + FileNode sp = fn["searchParams"]; + CV_Assert(sp.type() == FileNode::SEQ); + + for(size_t i = 0; i < sp.size(); ++i) + { + CV_Assert(sp[i].type() == FileNode::MAP); + std::string name = (std::string)sp[i]["name"]; + int type = (int)sp[i]["type"]; + + switch(type) + { + case CV_8U: + case CV_8S: + case CV_16U: + case CV_16S: + case CV_32S: + searchParams->setInt(name, (int) sp[i]["value"]); + break; + case CV_32F: + searchParams->setFloat(name, (float) ip[i]["value"]); + break; + case CV_64F: + searchParams->setDouble(name, (double) ip[i]["value"]); + break; + case CV_USRTYPE1: + searchParams->setString(name, (std::string) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,2): + searchParams->setBool(name, (int) ip[i]["value"]); + break; + case CV_MAKETYPE(CV_USRTYPE1,3): + searchParams->setAlgorithm(name, (int) ip[i]["value"]); + break; + }; + } + + flannIndex.release(); +} + +void FlannBasedMatcher::write( FileStorage& fs) const +{ + fs << "indexParams" << "["; + + if (indexParams != 0) + { + std::vector names; + std::vector types; + std::vector strValues; + std::vector numValues; + + indexParams->getAll(names, types, strValues, numValues); + + for(size_t i = 0; i < names.size(); ++i) + { + fs << "{" << "name" << names[i] << "type" << types[i] << "value"; + switch(types[i]) + { + case CV_8U: + fs << (uchar)numValues[i]; + break; + case CV_8S: + fs << (char)numValues[i]; + break; + case CV_16U: + fs << (ushort)numValues[i]; + break; + case CV_16S: + fs << (short)numValues[i]; + break; + case CV_32S: + case CV_MAKETYPE(CV_USRTYPE1,2): + case CV_MAKETYPE(CV_USRTYPE1,3): + fs << (int)numValues[i]; + break; + case CV_32F: + fs << (float)numValues[i]; + break; + case CV_64F: + fs << (double)numValues[i]; + break; + case CV_USRTYPE1: + fs << strValues[i]; + break; + default: + fs << (double)numValues[i]; + fs << "typename" << strValues[i]; + break; + } + fs << "}"; + } + } + + fs << "]" << "searchParams" << "["; + + if (searchParams != 0) + { + std::vector names; + std::vector types; + std::vector strValues; + std::vector numValues; + + searchParams->getAll(names, types, strValues, numValues); + + for(size_t i = 0; i < names.size(); ++i) + { + fs << "{" << "name" << names[i] << "type" << types[i] << "value"; + switch(types[i]) + { + case CV_8U: + fs << (uchar)numValues[i]; + break; + case CV_8S: + fs << (char)numValues[i]; + break; + case CV_16U: + fs << (ushort)numValues[i]; + break; + case CV_16S: + fs << (short)numValues[i]; + break; + case CV_32S: + case CV_MAKETYPE(CV_USRTYPE1,2): + case CV_MAKETYPE(CV_USRTYPE1,3): + fs << (int)numValues[i]; + break; + case CV_32F: + fs << (float)numValues[i]; + break; + case CV_64F: + fs << (double)numValues[i]; + break; + case CV_USRTYPE1: + fs << strValues[i]; + break; + default: + fs << (double)numValues[i]; + fs << "typename" << strValues[i]; + break; + } + fs << "}"; + } + } + fs << "]"; +} + bool FlannBasedMatcher::isMaskSupported() const { return false; @@ -603,7 +830,7 @@ void FlannBasedMatcher::radiusMatchImpl( const Mat& queryDescriptors, vectorradiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, *searchParams ); + flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, count, *searchParams ); } convertToDMatches( mergedDescriptors, indices, dists, matches ); diff --git a/modules/features2d/src/orb.cpp b/modules/features2d/src/orb.cpp index 90b1655f6c..15c14f3e46 100644 --- a/modules/features2d/src/orb.cpp +++ b/modules/features2d/src/orb.cpp @@ -58,7 +58,7 @@ template SumType * dX_data = reinterpret_cast (dX.data), *dY_data = reinterpret_cast (dY.data); SumType * dX_data_end = dX_data + 9 * 7; PatchType * patch_data = reinterpret_cast (patch.data); - int two_row_offset = 2 * patch.step1(); + int two_row_offset = (int)(2 * patch.step1()); std::vector::const_iterator dX_offset = dX_offsets.begin(), dY_offset = dY_offsets.begin(); // Compute the differences for (; dX_data != dX_data_end; ++dX_data, ++dY_data, ++dX_offset, ++dY_offset) @@ -127,11 +127,11 @@ HarrisResponse::HarrisResponse(const cv::Mat& image, double k) : dX_offsets_.resize(7 * 9); dY_offsets_.resize(7 * 9); std::vector::iterator dX_offsets = dX_offsets_.begin(), dY_offsets = dY_offsets_.begin(); - unsigned int image_step = (unsigned int)image.step1(); - for (size_t y = 0; y <= 6 * image_step; y += image_step) + int x, y, image_step = (int)image.step1(); + for (y = 0; y <= 6 * image_step; y += image_step) { int dX_offset = y + 2, dY_offset = y + 2 * image_step; - for (size_t x = 0; x <= 6; ++x) + for (x = 0; x <= 6; ++x) { *(dX_offsets++) = dX_offset++; *(dY_offsets++) = dY_offset++; @@ -140,10 +140,10 @@ HarrisResponse::HarrisResponse(const cv::Mat& image, double k) : *(dY_offsets++) = dY_offset++; } - for (size_t y = 7 * image_step; y <= 8 * image_step; y += image_step) + for (y = 7 * image_step; y <= 8 * image_step; y += image_step) { int dX_offset = y + 2; - for (size_t x = 0; x <= 6; ++x) + for (x = 0; x <= 6; ++x) *(dX_offsets++) = dX_offset++; } } @@ -405,16 +405,17 @@ private: } int half_kernel = ORB::kKernelWidth / 2; - for (unsigned int i = 0; i < 512; ++i) + for (int i = 0; i < 512; ++i) { - int center = *(pattern_data + 2 * i) + normalized_step_ * (*(pattern_data + 2 * i + 1)); + int center = (int)(*(pattern_data + 2 * i) + normalized_step_ * (*(pattern_data + 2 * i + 1))); + int nstep = (int)normalized_step_; // Points in order 01 // 32 // +1 is added for certain coordinates for the integral image - *(relative_pattern_data++) = center - half_kernel - half_kernel * normalized_step_; - *(relative_pattern_data++) = center + (half_kernel + 1) - half_kernel * normalized_step_; - *(relative_pattern_data++) = center + (half_kernel + 1) + (half_kernel + 1) * normalized_step_; - *(relative_pattern_data++) = center - half_kernel + (half_kernel + 1) * normalized_step_; + *(relative_pattern_data++) = center - half_kernel - half_kernel * nstep; + *(relative_pattern_data++) = center + (half_kernel + 1) - half_kernel * nstep; + *(relative_pattern_data++) = center + (half_kernel + 1) + (half_kernel + 1) * nstep; + *(relative_pattern_data++) = center - half_kernel + (half_kernel + 1) * nstep; } } @@ -765,8 +766,8 @@ void ORB::computeIntegralImage(const cv::Mat & image, unsigned int level, cv::Ma integral(image, integral_image, CV_32S); integral_image_steps_.resize(params_.n_levels_, 0); - unsigned int integral_image_step = integral_image.step1(); - if (integral_image_steps_[level] == integral_image_step) + int integral_image_step = (int)integral_image.step1(); + if ((int)integral_image_steps_[level] == integral_image_step) return; // If the integral image dimensions have changed, recompute everything @@ -828,11 +829,11 @@ void ORB::computeDescriptors(const cv::Mat& image, const cv::Mat& integral_image OrbPatterns* patterns = patterns_[level]; //create the descriptor mat, keypoints.size() rows, BYTES cols - descriptors = cv::Mat::zeros(keypoints.size(), kBytes, CV_8UC1); + descriptors = cv::Mat::zeros((int)keypoints.size(), kBytes, CV_8UC1); for (size_t i = 0; i < keypoints.size(); i++) // look up the test pattern - patterns->compute(keypoints[i], integral_image, descriptors.ptr(i)); + patterns->compute(keypoints[i], integral_image, descriptors.ptr((int)i)); } } diff --git a/modules/features2d/src/sift.cpp b/modules/features2d/src/sift.cpp index 4cdf9207be..179097f636 100644 --- a/modules/features2d/src/sift.cpp +++ b/modules/features2d/src/sift.cpp @@ -1663,7 +1663,9 @@ void SIFT::operator()(const Mat& image, const Mat& mask, // filter points by subMask and convert the points coordinates from subImage size to image size KeyPointsFilter::runByPixelsMask( keypoints, subMask ); int dx = brect.x, dy = brect.y; - for( vector::iterator it = keypoints.begin(); it != keypoints.end(); ++it ) + vector::iterator it = keypoints.begin(), + end = keypoints.end(); + for( ; it != end; ++it ) { it->pt.x += dx; it->pt.y += dy; @@ -1671,6 +1673,48 @@ void SIFT::operator()(const Mat& image, const Mat& mask, } } +void release_features_data( CvSeq* featuresSeq ) +{ + for( int i = 0; i < featuresSeq->total; i++ ) + { + feature * ft = CV_GET_SEQ_ELEM( feature, featuresSeq, i ); + free( ft->feature_data ); + } +} + +// Calculate orientation of features. +// Note: calc_feature_oris() duplicates the points with several dominant orientations. +// So if keypoints was detected by Sift feature detector then some points will be +// duplicated twice. +void recalculateAngles( vector& keypoints, IplImage*** gauss_pyr, + int nOctaves, int nOctaveLayers ) +{ + CvMemStorage* storage = cvCreateMemStorage( 0 ); + CvSeq* featuresSeq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(struct feature), storage ); + + for( size_t i = 0; i < keypoints.size(); i++ ) + { + feature ft; + keyPointToFeature( keypoints[i], ft, SiftParams( nOctaves, nOctaveLayers ) ); + cvSeqPush( featuresSeq, &ft ); + } + + calc_feature_oris( featuresSeq, gauss_pyr ); + + keypoints.resize( featuresSeq->total ); + for( int i = 0; i < featuresSeq->total; i++ ) + { + feature * ft = CV_GET_SEQ_ELEM( feature, featuresSeq, i ); + keypoints[i] = featureToKeyPoint( *ft ); + } + + // Remove duplicated keypoints. + KeyPointsFilter::removeDuplicated( keypoints ); + + release_features_data( featuresSeq ); + cvReleaseMemStorage( &storage ); +} + // descriptors void SIFT::operator()(const Mat& image, const Mat& mask, vector& keypoints, @@ -1694,42 +1738,17 @@ void SIFT::operator()(const Mat& image, const Mat& mask, IplImage img = fimg; ImagePyrData pyrImages( &img, commParams.nOctaves, commParams.nOctaveLayers, SIFT_SIGMA, SIFT_IMG_DBL ); - // Calculate orientation of features. - // Note: calc_feature_oris() duplicates the points with several dominant orientations. - // So if keypoints was detected by Sift feature detector then some points will be - // duplicated twice. + if( descriptorParams.recalculateAngles ) + recalculateAngles( keypoints, pyrImages.gauss_pyr, commParams.nOctaves, commParams.nOctaveLayers ); + CvMemStorage* storage = cvCreateMemStorage( 0 ); CvSeq* featuresSeq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(struct feature), storage ); - if( descriptorParams.recalculateAngles ) - { - for( size_t i = 0; i < keypoints.size(); i++ ) - { - feature* ft = (feature*) calloc( 1, sizeof( struct feature ) ); - keyPointToFeature( keypoints[i], *ft, SiftParams( commParams.nOctaves, commParams.nOctaveLayers ) ); - cvSeqPush( featuresSeq, ft ); - } - calc_feature_oris( featuresSeq, pyrImages.gauss_pyr ); - - keypoints.resize( featuresSeq->total ); - for( int i = 0; i < featuresSeq->total; i++ ) - { - feature * ft = CV_GET_SEQ_ELEM( feature, featuresSeq, i ); - keypoints[i] = featureToKeyPoint( *ft ); - } - - // Remove duplicated keypoints. - KeyPointsFilter::removeDuplicated( keypoints ); - - // Compute descriptors. - cvSeqRemoveSlice( featuresSeq, cvSlice(0, featuresSeq->total) ); - } - for( size_t i = 0; i < keypoints.size(); i++ ) { - feature* ft = (feature*) calloc( 1, sizeof( struct feature ) ); - keyPointToFeature( keypoints[i], *ft, SiftParams( commParams.nOctaves, commParams.nOctaveLayers ) ); - cvSeqPush( featuresSeq, ft ); + feature ft; + keyPointToFeature( keypoints[i], ft, SiftParams( commParams.nOctaves, commParams.nOctaveLayers ) ); + cvSeqPush( featuresSeq, &ft ); } compute_descriptors( featuresSeq, pyrImages.gauss_pyr, SIFT_DESCR_WIDTH, SIFT_DESCR_HIST_BINS ); CV_DbgAssert( (int)keypoints.size() == featuresSeq->total ); @@ -1748,5 +1767,6 @@ void SIFT::operator()(const Mat& image, const Mat& mask, } } + release_features_data( featuresSeq ); cvReleaseMemStorage( &storage ); } diff --git a/modules/features2d/test/test_features2d.cpp b/modules/features2d/test/test_features2d.cpp index 6640077a03..af26a1bf1a 100644 --- a/modules/features2d/test/test_features2d.cpp +++ b/modules/features2d/test/test_features2d.cpp @@ -139,8 +139,8 @@ void CV_FeatureDetectorTest::compareKeypointSets( const vector& validK return; } - int progress = 0, progressCount = validKeypoints.size() * calcKeypoints.size(); - int badPointCount = 0, commonPointCount = max(validKeypoints.size(), calcKeypoints.size()); + int progress = 0, progressCount = (int)(validKeypoints.size() * calcKeypoints.size()); + int badPointCount = 0, commonPointCount = max((int)validKeypoints.size(), (int)calcKeypoints.size()); for( size_t v = 0; v < validKeypoints.size(); v++ ) { int nearestIdx = -1; @@ -148,12 +148,12 @@ void CV_FeatureDetectorTest::compareKeypointSets( const vector& validK for( size_t c = 0; c < calcKeypoints.size(); c++ ) { - progress = update_progress( progress, v*calcKeypoints.size() + c, progressCount, 0 ); + progress = update_progress( progress, (int)(v*calcKeypoints.size() + c), progressCount, 0 ); float curDist = (float)norm( calcKeypoints[c].pt - validKeypoints[v].pt ); if( curDist < minDist ) { minDist = curDist; - nearestIdx = c; + nearestIdx = (int)c; } } @@ -256,7 +256,7 @@ static void writeMatInBin( const Mat& mat, const string& filename ) fwrite( (void*)&mat.rows, sizeof(int), 1, f ); fwrite( (void*)&mat.cols, sizeof(int), 1, f ); fwrite( (void*)&type, sizeof(int), 1, f ); - int dataSize = mat.step * mat.rows * mat.channels(); + int dataSize = (int)(mat.step * mat.rows * mat.channels()); fwrite( (void*)&dataSize, sizeof(int), 1, f ); fwrite( (void*)mat.data, 1, dataSize, f ); fclose(f); @@ -1047,7 +1047,7 @@ TEST( Features2d_DescriptorExtractor_SURF, regression ) TEST( Features2d_DescriptorExtractor_ORB, regression ) { // TODO adjust the parameters below - CV_DescriptorExtractorTest test( "descriptor-orb", (CV_DescriptorExtractorTest::DistanceType)1.0f, + CV_DescriptorExtractorTest test( "descriptor-orb", (CV_DescriptorExtractorTest::DistanceType)3.f, DescriptorExtractor::create("ORB"), 0.010f ); test.safe_run(); } @@ -1059,12 +1059,12 @@ TEST( Features2d_DescriptorExtractor_BRIEF, regression ) test.safe_run(); } -TEST( Features2d_DescriptorExtractor_OpponentSIFT, regression ) +/*TEST( Features2d_DescriptorExtractor_OpponentSIFT, regression ) { CV_DescriptorExtractorTest > test( "descriptor-opponent-sift", 0.18f, DescriptorExtractor::create("OpponentSIFT"), 8.06652f ); test.safe_run(); -} +}*/ TEST( Features2d_DescriptorExtractor_OpponentSURF, regression ) { diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 01d16c8a36..0a23c525bb 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -405,14 +405,14 @@ int CV_FlannTest::radiusSearch( Mat& points, Mat& neighbors ) // 1st way Mat p( 1, points.cols, CV_32FC1, points.ptr(i) ), n( 1, neighbors.cols, CV_32SC1, neighbors.ptr(i) ); - index->radiusSearch( p, n, dist, radius, SearchParams() ); + index->radiusSearch( p, n, dist, radius, neighbors.cols, SearchParams() ); // 2nd way float* fltPtr = points.ptr(i); vector query( fltPtr, fltPtr + points.cols ); vector indices( neighbors1.cols, 0 ); vector dists( dist.cols, 0 ); - index->radiusSearch( query, indices, dists, radius, SearchParams() ); + index->radiusSearch( query, indices, dists, radius, neighbors.cols, SearchParams() ); vector::const_iterator it = indices.begin(); for( j = 0; it != indices.end(); ++it, j++ ) neighbors1.at(i,j) = *it; diff --git a/modules/flann/doc/flann.rst b/modules/flann/doc/flann.rst new file mode 100644 index 0000000000..7eee435ee6 --- /dev/null +++ b/modules/flann/doc/flann.rst @@ -0,0 +1,9 @@ +******************************************************** +flann. Clustering and Search in Multi-Dimensional Spaces +******************************************************** + +.. toctree:: + :maxdepth: 2 + + flann_fast_approximate_nearest_neighbor_search + flann_clustering diff --git a/modules/flann/doc/flann_clustering.rst b/modules/flann/doc/flann_clustering.rst new file mode 100644 index 0000000000..4ea53bd692 --- /dev/null +++ b/modules/flann/doc/flann_clustering.rst @@ -0,0 +1,18 @@ +Clustering +========== + +.. highlight:: cpp + +flann::hierarchicalClustering +-------------------------------------------- +Clusters features using hierarchical k-means algorithm. + +.. ocv:function:: int flann::hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params) + + :param features: The points to be clustered. The matrix must have elements of type ET. + + :param centers: The centers of the clusters obtained. The matrix must have type DT. The number of rows in this matrix represents the number of clusters desired, however, because of the way the cut in the hierarchical tree is chosen, the number of clusters computed will be the highest number of the form ``(branching-1)*k+1`` that's lower than the number of clusters desired, where ``branching`` is the tree's branching factor (see description of the KMeansIndexParams). + + :param params: Parameters used in the construction of the hierarchical k-means tree + +The method clusters the given feature vectors by constructing a hierarchical k-means tree and choosing a cut in the tree that minimizes the cluster's variance. It returns the number of clusters found. diff --git a/modules/flann/doc/flann_fast_approximate_nearest_neighbor_search.rst b/modules/flann/doc/flann_fast_approximate_nearest_neighbor_search.rst new file mode 100644 index 0000000000..5819c02bd3 --- /dev/null +++ b/modules/flann/doc/flann_fast_approximate_nearest_neighbor_search.rst @@ -0,0 +1,193 @@ +Fast Approximate Nearest Neighbor Search +======================================== + +.. highlight:: cpp + + +This section documents OpenCV's interface to the FLANN library. FLANN (Fast Library for Approximate Nearest Neighbors) is a library that contains a collection of algorithms optimized for fast nearest neighbor search in large datasets and for high dimensional features. More information about FLANN can be found in [Muja2009]_ . + + +flann::Index\_ +----------------- + +.. ocv:class:: cv::flann::Index_ + +The FLANN nearest neighbor index class. This class is templated with the type of elements for which the index is built. + + +flann::Index_::Index\_ +-------------------------- +Constructs a nearest neighbor search index for a given dataset. + +.. ocv:function:: flann::Index_::Index_(const Mat& features, const IndexParams& params) + + :param features: Matrix of containing the features(points) to index. The size of the matrix is ``num_features x feature_dimensionality`` and the data type of the elements in the matrix must coincide with the type of the index. + + :param params: Structure containing the index parameters. The type of index that will be constructed depends on the type of this parameter. See the description. + +The method constructs a fast search structure from a set of features using the specified algorithm with specified parameters, as defined by ``params``. ``params`` is a reference to one of the following class ``IndexParams`` descendants: + + * + + **LinearIndexParams** When passing an object of this type, the index will perform a linear, brute-force search. :: + + struct LinearIndexParams : public IndexParams + { + }; + + .. + + * + + **KDTreeIndexParams** When passing an object of this type the index constructed will consist of a set of randomized kd-trees which will be searched in parallel. :: + + struct KDTreeIndexParams : public IndexParams + { + KDTreeIndexParams( int trees = 4 ); + }; + + .. + + * **trees** The number of parallel kd-trees to use. Good values are in the range [1..16] + + * + + **KMeansIndexParams** When passing an object of this type the index constructed will be a hierarchical k-means tree. :: + + struct KMeansIndexParams : public IndexParams + { + KMeansIndexParams( + int branching = 32, + int iterations = 11, + flann_centers_init_t centers_init = CENTERS_RANDOM, + float cb_index = 0.2 ); + }; + + .. + + * **branching** The branching factor to use for the hierarchical k-means tree + + * **iterations** The maximum number of iterations to use in the k-means clustering stage when building the k-means tree. A value of -1 used here means that the k-means clustering should be iterated until convergence + + * **centers_init** The algorithm to use for selecting the initial centers when performing a k-means clustering step. The possible values are ``CENTERS_RANDOM`` (picks the initial cluster centers randomly), ``CENTERS_GONZALES`` (picks the initial centers using Gonzales' algorithm) and ``CENTERS_KMEANSPP`` (picks the initial centers using the algorithm suggested in arthur_kmeanspp_2007 ) + + * **cb_index** This parameter (cluster boundary index) influences the way exploration is performed in the hierarchical kmeans tree. When ``cb_index`` is zero the next kmeans domain to be explored is choosen to be the one with the closest center. A value greater then zero also takes into account the size of the domain. + + * + **CompositeIndexParams** When using a parameters object of this type the index created combines the randomized kd-trees and the hierarchical k-means tree. :: + + struct CompositeIndexParams : public IndexParams + { + CompositeIndexParams( + int trees = 4, + int branching = 32, + int iterations = 11, + flann_centers_init_t centers_init = CENTERS_RANDOM, + float cb_index = 0.2 ); + }; + + .. + + * + **AutotunedIndexParams** When passing an object of this type the index created is automatically tuned to offer the best performance, by choosing the optimal index type (randomized kd-trees, hierarchical kmeans, linear) and parameters for the dataset provided. :: + + struct AutotunedIndexParams : public IndexParams + { + AutotunedIndexParams( + float target_precision = 0.9, + float build_weight = 0.01, + float memory_weight = 0, + float sample_fraction = 0.1 ); + }; + + .. + + * **target_precision** Is a number between 0 and 1 specifying the percentage of the approximate nearest-neighbor searches that return the exact nearest-neighbor. Using a higher value for this parameter gives more accurate results, but the search takes longer. The optimum value usually depends on the application. + + + * **build_weight** Specifies the importance of the index build time raported to the nearest-neighbor search time. In some applications it's acceptable for the index build step to take a long time if the subsequent searches in the index can be performed very fast. In other applications it's required that the index be build as fast as possible even if that leads to slightly longer search times. + + + * **memory_weight** Is used to specify the tradeoff between time (index build time and search time) and memory used by the index. A value less than 1 gives more importance to the time spent and a value greater than 1 gives more importance to the memory usage. + + + * **sample_fraction** Is a number between 0 and 1 indicating what fraction of the dataset to use in the automatic parameter configuration algorithm. Running the algorithm on the full dataset gives the most accurate results, but for very large datasets can take longer than desired. In such case using just a fraction of the data helps speeding up this algorithm while still giving good approximations of the optimum parameters. + + * + **SavedIndexParams** This object type is used for loading a previously saved index from the disk. :: + + struct SavedIndexParams : public IndexParams + { + SavedIndexParams( std::string filename ); + }; + + + .. + + * **filename** The filename in which the index was saved. + + +flann::Index_::knnSearch +---------------------------- +Performs a K-nearest neighbor search for a given query point using the index. + +.. ocv:function:: void flann::Index_::knnSearch(const vector& query, vector& indices, vector& dists, int knn, const SearchParams& params) + +.. ocv:function:: void flann::Index_::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params) + + :param query: The query point + + :param indices: Vector that will contain the indices of the K-nearest neighbors found. It must have at least knn size. + + :param dists: Vector that will contain the distances to the K-nearest neighbors found. It must have at least knn size. + + :param knn: Number of nearest neighbors to search for. + + :param params: + + Search parameters :: + + struct SearchParams { + SearchParams(int checks = 32); + }; + + .. + + * **checks** The number of times the tree(s) in the index should be recursively traversed. A higher value for this parameter would give better search precision, but also take more time. If automatic configuration was used when the index was created, the number of checks required to achieve the specified precision was also computed, in which case this parameter is ignored. + + +flann::Index_::radiusSearch +-------------------------------------- +Performs a radius nearest neighbor search for a given query point. + +.. ocv:function:: int flann::Index_::radiusSearch(const vector& query, vector& indices, vector& dists, float radius, const SearchParams& params) + +.. ocv:function:: int flann::Index_::radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& params) + + :param query: The query point + + :param indices: Vector that will contain the indices of the points found within the search radius in decreasing order of the distance to the query point. If the number of neighbors in the search radius is bigger than the size of this vector, the ones that don't fit in the vector are ignored. + + :param dists: Vector that will contain the distances to the points found within the search radius + + :param radius: The search radius + + :param params: Search parameters + + +flann::Index_::save +------------------------------ +Saves the index to a file. + +.. ocv:function:: void flann::Index_::save(std::string filename) + + :param filename: The file to save the index to + + +flann::Index_::getIndexParameters +-------------------------------------------- +Returns the index paramreters. + +.. ocv:function:: const IndexParams* flann::Index_::getIndexParameters() + +The method is useful in the case of auto-tuned indices, when the parameters are chosen during the index construction. Then, the method can be used to retrieve the actual parameter values. diff --git a/modules/flann/include/opencv2/flann/all_indices.h b/modules/flann/include/opencv2/flann/all_indices.h index 898ac09980..ff53fd84c2 100644 --- a/modules/flann/include/opencv2/flann/all_indices.h +++ b/modules/flann/include/opencv2/flann/all_indices.h @@ -27,50 +27,129 @@ *************************************************************************/ -#ifndef _OPENCV_ALL_INDICES_H_ -#define _OPENCV_ALL_INDICES_H_ +#ifndef OPENCV_FLANN_ALL_INDICES_H_ +#define OPENCV_FLANN_ALL_INDICES_H_ -#include "opencv2/flann/general.h" +#include "general.h" -#include "opencv2/flann/nn_index.h" -#include "opencv2/flann/kdtree_index.h" -#include "opencv2/flann/kmeans_index.h" -#include "opencv2/flann/composite_index.h" -#include "opencv2/flann/linear_index.h" -#include "opencv2/flann/autotuned_index.h" +#include "nn_index.h" +#include "kdtree_index.h" +#include "kdtree_single_index.h" +#include "kmeans_index.h" +#include "composite_index.h" +#include "linear_index.h" +#include "hierarchical_clustering_index.h" +#include "lsh_index.h" +#include "autotuned_index.h" -namespace cvflann + +namespace cvflann { -template -NNIndex* create_index_by_type(const Matrix& dataset, const IndexParams& params) +template +struct index_creator { - flann_algorithm_t index_type = params.getIndexType(); + static NNIndex* create(const Matrix& dataset, const IndexParams& params, const Distance& distance) + { + flann_algorithm_t index_type = get_param(params, "algorithm"); - NNIndex* nnIndex; - switch (index_type) { - case FLANN_INDEX_LINEAR: - nnIndex = new LinearIndex(dataset, (const LinearIndexParams&)params); - break; - case FLANN_INDEX_KDTREE: - nnIndex = new KDTreeIndex(dataset, (const KDTreeIndexParams&)params); - break; - case FLANN_INDEX_KMEANS: - nnIndex = new KMeansIndex(dataset, (const KMeansIndexParams&)params); - break; - case FLANN_INDEX_COMPOSITE: - nnIndex = new CompositeIndex(dataset, (const CompositeIndexParams&) params); - break; - case FLANN_INDEX_AUTOTUNED: - nnIndex = new AutotunedIndex(dataset, (const AutotunedIndexParams&) params); - break; - default: - throw FLANNException("Unknown index type"); - } + NNIndex* nnIndex; + switch (index_type) { + case FLANN_INDEX_LINEAR: + nnIndex = new LinearIndex(dataset, params, distance); + break; + case FLANN_INDEX_KDTREE_SINGLE: + nnIndex = new KDTreeSingleIndex(dataset, params, distance); + break; + case FLANN_INDEX_KDTREE: + nnIndex = new KDTreeIndex(dataset, params, distance); + break; + case FLANN_INDEX_KMEANS: + nnIndex = new KMeansIndex(dataset, params, distance); + break; + case FLANN_INDEX_COMPOSITE: + nnIndex = new CompositeIndex(dataset, params, distance); + break; + case FLANN_INDEX_AUTOTUNED: + nnIndex = new AutotunedIndex(dataset, params, distance); + break; + case FLANN_INDEX_HIERARCHICAL: + nnIndex = new HierarchicalClusteringIndex(dataset, params, distance); + break; + case FLANN_INDEX_LSH: + nnIndex = new LshIndex(dataset, params, distance); + break; + default: + throw FLANNException("Unknown index type"); + } - return nnIndex; + return nnIndex; + } +}; + +template +struct index_creator +{ + static NNIndex* create(const Matrix& dataset, const IndexParams& params, const Distance& distance) + { + flann_algorithm_t index_type = get_param(params, "algorithm"); + + NNIndex* nnIndex; + switch (index_type) { + case FLANN_INDEX_LINEAR: + nnIndex = new LinearIndex(dataset, params, distance); + break; + case FLANN_INDEX_KMEANS: + nnIndex = new KMeansIndex(dataset, params, distance); + break; + case FLANN_INDEX_HIERARCHICAL: + nnIndex = new HierarchicalClusteringIndex(dataset, params, distance); + break; + case FLANN_INDEX_LSH: + nnIndex = new LshIndex(dataset, params, distance); + break; + default: + throw FLANNException("Unknown index type"); + } + + return nnIndex; + } +}; + +template +struct index_creator +{ + static NNIndex* create(const Matrix& dataset, const IndexParams& params, const Distance& distance) + { + flann_algorithm_t index_type = get_param(params, "algorithm"); + + NNIndex* nnIndex; + switch (index_type) { + case FLANN_INDEX_LINEAR: + nnIndex = new LinearIndex(dataset, params, distance); + break; + case FLANN_INDEX_HIERARCHICAL: + nnIndex = new HierarchicalClusteringIndex(dataset, params, distance); + break; + case FLANN_INDEX_LSH: + nnIndex = new LshIndex(dataset, params, distance); + break; + default: + throw FLANNException("Unknown index type"); + } + + return nnIndex; + } +}; + +template +NNIndex* create_index_by_type(const Matrix& dataset, const IndexParams& params, const Distance& distance) +{ + return index_creator::create(dataset, params,distance); } -} //namespace cvflann +} -#endif /* _OPENCV_ALL_INDICES_H_ */ +#endif /* OPENCV_FLANN_ALL_INDICES_H_ */ diff --git a/modules/flann/include/opencv2/flann/allocator.h b/modules/flann/include/opencv2/flann/allocator.h index 0215ac6141..6ca44fcc83 100644 --- a/modules/flann/include/opencv2/flann/allocator.h +++ b/modules/flann/include/opencv2/flann/allocator.h @@ -28,12 +28,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_ALLOCATOR_H_ -#define _OPENCV_ALLOCATOR_H_ +#ifndef OPENCV_FLANN_ALLOCATOR_H_ +#define OPENCV_FLANN_ALLOCATOR_H_ #include #include + namespace cvflann { @@ -47,8 +48,8 @@ namespace cvflann template T* allocate(size_t count = 1) { - T* mem = (T*) ::malloc(sizeof(T)*count); - return mem; + T* mem = (T*) ::malloc(sizeof(T)*count); + return mem; } @@ -70,118 +71,118 @@ T* allocate(size_t count = 1) const size_t WORDSIZE=16; const size_t BLOCKSIZE=8192; -class CV_EXPORTS PooledAllocator +class PooledAllocator { - /* We maintain memory alignment to word boundaries by requiring that all - allocations be in multiples of the machine wordsize. */ - /* Size of machine word in bytes. Must be power of 2. */ - /* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */ + /* We maintain memory alignment to word boundaries by requiring that all + allocations be in multiples of the machine wordsize. */ + /* Size of machine word in bytes. Must be power of 2. */ + /* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */ - int remaining; /* Number of bytes left in current block of storage. */ - void* base; /* Pointer to base of current block of storage. */ - void* loc; /* Current location in block to next allocate memory. */ - int blocksize; + int remaining; /* Number of bytes left in current block of storage. */ + void* base; /* Pointer to base of current block of storage. */ + void* loc; /* Current location in block to next allocate memory. */ + int blocksize; public: - int usedMemory; - int wastedMemory; + int usedMemory; + int wastedMemory; - /** - Default constructor. Initializes a new pool. - */ - PooledAllocator(int blocksize = BLOCKSIZE) - { - this->blocksize = blocksize; - remaining = 0; - base = NULL; + /** + Default constructor. Initializes a new pool. + */ + PooledAllocator(int blocksize = BLOCKSIZE) + { + this->blocksize = blocksize; + remaining = 0; + base = NULL; - usedMemory = 0; - wastedMemory = 0; - } + usedMemory = 0; + wastedMemory = 0; + } - /** - * Destructor. Frees all the memory allocated in this pool. - */ - ~PooledAllocator() - { - void *prev; + /** + * Destructor. Frees all the memory allocated in this pool. + */ + ~PooledAllocator() + { + void* prev; - while (base != NULL) { - prev = *((void **) base); /* Get pointer to prev block. */ - ::free(base); - base = prev; - } - } + while (base != NULL) { + prev = *((void**) base); /* Get pointer to prev block. */ + ::free(base); + base = prev; + } + } - /** - * Returns a pointer to a piece of new memory of the given size in bytes - * allocated from the pool. - */ - void* allocateBytes(int size) - { - int blocksize; + /** + * Returns a pointer to a piece of new memory of the given size in bytes + * allocated from the pool. + */ + void* allocateMemory(int size) + { + int blocksize; - /* Round size up to a multiple of wordsize. The following expression - only works for WORDSIZE that is a power of 2, by masking last bits of - incremented size to zero. - */ - size = (size + (WORDSIZE - 1)) & ~(WORDSIZE - 1); + /* Round size up to a multiple of wordsize. The following expression + only works for WORDSIZE that is a power of 2, by masking last bits of + incremented size to zero. + */ + size = (size + (WORDSIZE - 1)) & ~(WORDSIZE - 1); - /* Check whether a new block must be allocated. Note that the first word - of a block is reserved for a pointer to the previous block. - */ - if (size > remaining) { + /* Check whether a new block must be allocated. Note that the first word + of a block is reserved for a pointer to the previous block. + */ + if (size > remaining) { - wastedMemory += remaining; + wastedMemory += remaining; - /* Allocate new storage. */ - blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ? - size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE; + /* Allocate new storage. */ + blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ? + size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE; - // use the standard C malloc to allocate memory - void* m = ::malloc(blocksize); - if (!m) { + // use the standard C malloc to allocate memory + void* m = ::malloc(blocksize); + if (!m) { fprintf(stderr,"Failed to allocate memory.\n"); - exit(1); - } + return NULL; + } - /* Fill first word of new block with pointer to previous block. */ - ((void **) m)[0] = base; - base = m; + /* Fill first word of new block with pointer to previous block. */ + ((void**) m)[0] = base; + base = m; - int shift = 0; - //int shift = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1); + int shift = 0; + //int shift = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1); - remaining = blocksize - sizeof(void*) - shift; - loc = ((char*)m + sizeof(void*) + shift); - } - void* rloc = loc; - loc = (char*)loc + size; - remaining -= size; + remaining = blocksize - sizeof(void*) - shift; + loc = ((char*)m + sizeof(void*) + shift); + } + void* rloc = loc; + loc = (char*)loc + size; + remaining -= size; - usedMemory += size; + usedMemory += size; - return rloc; - } + return rloc; + } - /** - * Allocates (using this pool) a generic type T. - * - * Params: - * count = number of instances to allocate. - * Returns: pointer (of type T*) to memory buffer - */ + /** + * Allocates (using this pool) a generic type T. + * + * Params: + * count = number of instances to allocate. + * Returns: pointer (of type T*) to memory buffer + */ template - T* allocate(size_t count = 1) - { - T* mem = (T*) this->allocateBytes((int)(sizeof(T)*count)); - return mem; - } + T* allocate(size_t count = 1) + { + T* mem = (T*) this->allocateMemory((int)(sizeof(T)*count)); + return mem; + } }; -} // namespace cvflann +} -#endif //_OPENCV_ALLOCATOR_H_ +#endif //OPENCV_FLANN_ALLOCATOR_H_ diff --git a/modules/flann/include/opencv2/flann/any.h b/modules/flann/include/opencv2/flann/any.h new file mode 100644 index 0000000000..46e11160ce --- /dev/null +++ b/modules/flann/include/opencv2/flann/any.h @@ -0,0 +1,284 @@ +#ifndef OPENCV_FLANN_ANY_H_ +#define OPENCV_FLANN_ANY_H_ +/* + * (C) Copyright Christopher Diggins 2005-2011 + * (C) Copyright Pablo Aguilar 2005 + * (C) Copyright Kevlin Henney 2001 + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt + * + * Adapted for FLANN by Marius Muja + */ + +#include +#include +#include + +namespace cdiggins +{ + +namespace anyimpl +{ + +struct bad_any_cast +{ +}; + +struct empty_any +{ +}; + +struct base_any_policy +{ + virtual void static_delete(void** x) = 0; + virtual void copy_from_value(void const* src, void** dest) = 0; + virtual void clone(void* const* src, void** dest) = 0; + virtual void move(void* const* src, void** dest) = 0; + virtual void* get_value(void** src) = 0; + virtual size_t get_size() = 0; + virtual const std::type_info& type() = 0; + virtual void print(std::ostream& out, void* const* src) = 0; +}; + +template +struct typed_base_any_policy : base_any_policy +{ + virtual size_t get_size() { return sizeof(T); } + virtual const std::type_info& type() { return typeid(T); } + +}; + +template +struct small_any_policy : typed_base_any_policy +{ + virtual void static_delete(void**) { } + virtual void copy_from_value(void const* src, void** dest) + { + new (dest) T(* reinterpret_cast(src)); + } + virtual void clone(void* const* src, void** dest) { *dest = *src; } + virtual void move(void* const* src, void** dest) { *dest = *src; } + virtual void* get_value(void** src) { return reinterpret_cast(src); } + virtual void print(std::ostream& out, void* const* src) { out << *reinterpret_cast(src); } +}; + +template +struct big_any_policy : typed_base_any_policy +{ + virtual void static_delete(void** x) + { + if (* x) delete (* reinterpret_cast(x)); *x = NULL; + } + virtual void copy_from_value(void const* src, void** dest) + { + *dest = new T(*reinterpret_cast(src)); + } + virtual void clone(void* const* src, void** dest) + { + *dest = new T(**reinterpret_cast(src)); + } + virtual void move(void* const* src, void** dest) + { + (*reinterpret_cast(dest))->~T(); + **reinterpret_cast(dest) = **reinterpret_cast(src); + } + virtual void* get_value(void** src) { return *src; } + virtual void print(std::ostream& out, void* const* src) { out << *reinterpret_cast(*src); } +}; + +template +struct choose_policy +{ + typedef big_any_policy type; +}; + +template +struct choose_policy +{ + typedef small_any_policy type; +}; + +struct any; + +/// Choosing the policy for an any type is illegal, but should never happen. +/// This is designed to throw a compiler error. +template<> +struct choose_policy +{ + typedef void type; +}; + +/// Specializations for small types. +#define SMALL_POLICY(TYPE) \ + template<> \ + struct choose_policy { typedef small_any_policy type; \ + }; + +SMALL_POLICY(signed char); +SMALL_POLICY(unsigned char); +SMALL_POLICY(signed short); +SMALL_POLICY(unsigned short); +SMALL_POLICY(signed int); +SMALL_POLICY(unsigned int); +SMALL_POLICY(signed long); +SMALL_POLICY(unsigned long); +SMALL_POLICY(float); +SMALL_POLICY(bool); + +#undef SMALL_POLICY + +/// This function will return a different policy for each type. +template +base_any_policy* get_policy() +{ + static typename choose_policy::type policy; + return &policy; +} +} // namespace anyimpl + +struct any +{ +private: + // fields + anyimpl::base_any_policy* policy; + void* object; + +public: + /// Initializing constructor. + template + any(const T& x) + : policy(anyimpl::get_policy()), object(NULL) + { + assign(x); + } + + /// Empty constructor. + any() + : policy(anyimpl::get_policy()), object(NULL) + { } + + /// Special initializing constructor for string literals. + any(const char* x) + : policy(anyimpl::get_policy()), object(NULL) + { + assign(x); + } + + /// Copy constructor. + any(const any& x) + : policy(anyimpl::get_policy()), object(NULL) + { + assign(x); + } + + /// Destructor. + ~any() + { + policy->static_delete(&object); + } + + /// Assignment function from another any. + any& assign(const any& x) + { + reset(); + policy = x.policy; + policy->clone(&x.object, &object); + return *this; + } + + /// Assignment function. + template + any& assign(const T& x) + { + reset(); + policy = anyimpl::get_policy(); + policy->copy_from_value(&x, &object); + return *this; + } + + /// Assignment operator. + template + any& operator=(const T& x) + { + return assign(x); + } + + /// Assignment operator, specialed for literal strings. + /// They have types like const char [6] which don't work as expected. + any& operator=(const char* x) + { + return assign(x); + } + + /// Utility functions + any& swap(any& x) + { + std::swap(policy, x.policy); + std::swap(object, x.object); + return *this; + } + + /// Cast operator. You can only cast to the original type. + template + T& cast() + { + if (policy->type() != typeid(T)) throw anyimpl::bad_any_cast(); + T* r = reinterpret_cast(policy->get_value(&object)); + return *r; + } + + /// Cast operator. You can only cast to the original type. + template + const T& cast() const + { + if (policy->type() != typeid(T)) throw anyimpl::bad_any_cast(); + void* obj = const_cast(object); + T* r = reinterpret_cast(policy->get_value(&obj)); + return *r; + } + + /// Returns true if the any contains no value. + bool empty() const + { + return policy->type() == typeid(anyimpl::empty_any); + } + + /// Frees any allocated memory, and sets the value to NULL. + void reset() + { + policy->static_delete(&object); + policy = anyimpl::get_policy(); + } + + /// Returns true if the two types are the same. + bool compatible(const any& x) const + { + return policy->type() == x.policy->type(); + } + + /// Returns if the type is compatible with the policy + template + bool has_type() + { + return policy->type() == typeid(T); + } + + const std::type_info& type() const + { + return policy->type(); + } + + friend std::ostream& operator <<(std::ostream& out, const any& any_val); +}; + +inline std::ostream& operator <<(std::ostream& out, const any& any_val) +{ + any_val.policy->print(out,&any_val.object); + return out; +} + +} + +#endif // OPENCV_FLANN_ANY_H_ diff --git a/modules/flann/include/opencv2/flann/autotuned_index.h b/modules/flann/include/opencv2/flann/autotuned_index.h index 0e19f1dc76..8d531753e0 100644 --- a/modules/flann/include/opencv2/flann/autotuned_index.h +++ b/modules/flann/include/opencv2/flann/autotuned_index.h @@ -27,216 +27,204 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ +#ifndef OPENCV_FLANN_AUTOTUNED_INDEX_H_ +#define OPENCV_FLANN_AUTOTUNED_INDEX_H_ -#ifndef _OPENCV_AUTOTUNEDINDEX_H_ -#define _OPENCV_AUTOTUNEDINDEX_H_ - -#include "opencv2/flann/general.h" -#include "opencv2/flann/nn_index.h" -#include "opencv2/flann/ground_truth.h" -#include "opencv2/flann/index_testing.h" -#include "opencv2/flann/sampling.h" -#include "opencv2/flann/all_indices.h" +#include "general.h" +#include "nn_index.h" +#include "ground_truth.h" +#include "index_testing.h" +#include "sampling.h" +#include "kdtree_index.h" +#include "kdtree_single_index.h" +#include "kmeans_index.h" +#include "composite_index.h" +#include "linear_index.h" +#include "logger.h" namespace cvflann { -struct AutotunedIndexParams : public IndexParams { - AutotunedIndexParams( float target_precision_ = 0.8, float build_weight_ = 0.01, - float memory_weight_ = 0, float sample_fraction_ = 0.1) : - IndexParams(FLANN_INDEX_AUTOTUNED), - target_precision(target_precision_), - build_weight(build_weight_), - memory_weight(memory_weight_), - sample_fraction(sample_fraction_) {}; +template +NNIndex* create_index_by_type(const Matrix& dataset, const IndexParams& params, const Distance& distance); - float target_precision; // precision desired (used for autotuning, -1 otherwise) - float build_weight; // build tree time weighting factor - float memory_weight; // index memory weighting factor - float sample_fraction; // what fraction of the dataset to use for autotuning - void print() const - { - logger().info("Index type: %d\n",(int)algorithm); - logger().info("logger(). precision: %g\n", target_precision); - logger().info("Build weight: %g\n", build_weight); - logger().info("Memory weight: %g\n", memory_weight); - logger().info("Sample fraction: %g\n", sample_fraction); - } +struct AutotunedIndexParams : public IndexParams +{ + AutotunedIndexParams(float target_precision = 0.8, float build_weight = 0.01, float memory_weight = 0, float sample_fraction = 0.1) + { + (*this)["algorithm"] = FLANN_INDEX_AUTOTUNED; + // precision desired (used for autotuning, -1 otherwise) + (*this)["target_precision"] = target_precision; + // build tree time weighting factor + (*this)["build_weight"] = build_weight; + // index memory weighting factor + (*this)["memory_weight"] = memory_weight; + // what fraction of the dataset to use for autotuning + (*this)["sample_fraction"] = sample_fraction; + } }; -template ::type > -class AutotunedIndex : public NNIndex +template +class AutotunedIndex : public NNIndex { - NNIndex* bestIndex; - - IndexParams* bestParams; - SearchParams bestSearchParams; - - Matrix sampledDataset; - Matrix testDataset; - Matrix gt_matches; - - float speedup; - - /** - * The dataset used by this index - */ - const Matrix dataset; - - /** - * Index parameters - */ - const AutotunedIndexParams& index_params; - - AutotunedIndex& operator=(const AutotunedIndex&); - AutotunedIndex(const AutotunedIndex&); - public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; - AutotunedIndex(const Matrix& inputData, const AutotunedIndexParams& params = AutotunedIndexParams() ) : - dataset(inputData), index_params(params) - { - bestIndex = NULL; - bestParams = NULL; - } + AutotunedIndex(const Matrix& inputData, const IndexParams& params = AutotunedIndexParams(), Distance d = Distance()) : + dataset_(inputData), distance_(d) + { + target_precision_ = get_param(params, "target_precision",0.8f); + build_weight_ = get_param(params,"build_weight", 0.01f); + memory_weight_ = get_param(params, "memory_weight", 0.0f); + sample_fraction_ = get_param(params,"sample_fraction", 0.1f); + bestIndex_ = NULL; + } + + AutotunedIndex(const AutotunedIndex&); + AutotunedIndex& operator=(const AutotunedIndex&); virtual ~AutotunedIndex() { - if (bestIndex!=NULL) { - delete bestIndex; - } - if (bestParams!=NULL) { - delete bestParams; - } - }; + if (bestIndex_ != NULL) { + delete bestIndex_; + bestIndex_ = NULL; + } + } /** - Method responsible with building the index. - */ - virtual void buildIndex() - { - bestParams = estimateBuildParams(); - logger().info("----------------------------------------------------\n"); - logger().info("Autotuned parameters:\n"); - bestParams->print(); - logger().info("----------------------------------------------------\n"); - flann_algorithm_t index_type = bestParams->getIndexType(); - switch (index_type) { - case FLANN_INDEX_LINEAR: - bestIndex = new LinearIndex(dataset, (const LinearIndexParams&)*bestParams); - break; - case FLANN_INDEX_KDTREE: - bestIndex = new KDTreeIndex(dataset, (const KDTreeIndexParams&)*bestParams); - break; - case FLANN_INDEX_KMEANS: - bestIndex = new KMeansIndex(dataset, (const KMeansIndexParams&)*bestParams); - break; - default: - throw FLANNException("Unknown algorithm choosen by the autotuning, most likely a bug."); - } - bestIndex->buildIndex(); - speedup = estimateSearchParams(bestSearchParams); - } + * Method responsible with building the index. + */ + virtual void buildIndex() + { + bestParams_ = estimateBuildParams(); + Logger::info("----------------------------------------------------\n"); + Logger::info("Autotuned parameters:\n"); + print_params(bestParams_); + Logger::info("----------------------------------------------------\n"); + + bestIndex_ = create_index_by_type(dataset_, bestParams_, distance_); + bestIndex_->buildIndex(); + speedup_ = estimateSearchParams(bestSearchParams_); + Logger::info("----------------------------------------------------\n"); + Logger::info("Search parameters:\n"); + print_params(bestSearchParams_); + Logger::info("----------------------------------------------------\n"); + } /** - Saves the index to a stream - */ + * Saves the index to a stream + */ virtual void saveIndex(FILE* stream) { - save_value(stream, (int)bestIndex->getType()); - bestIndex->saveIndex(stream); - save_value(stream, bestSearchParams); + save_value(stream, (int)bestIndex_->getType()); + bestIndex_->saveIndex(stream); + save_value(stream, get_param(bestSearchParams_, "checks")); } /** - Loads the index from a stream - */ + * Loads the index from a stream + */ virtual void loadIndex(FILE* stream) { - int index_type; - load_value(stream,index_type); - IndexParams* params = ParamsFactory_instance().create((flann_algorithm_t)index_type); - bestIndex = create_index_by_type(dataset, *params); - bestIndex->loadIndex(stream); - load_value(stream, bestSearchParams); + int index_type; + + load_value(stream, index_type); + IndexParams params; + params["algorithm"] = (flann_algorithm_t)index_type; + bestIndex_ = create_index_by_type(dataset_, params, distance_); + bestIndex_->loadIndex(stream); + int checks; + load_value(stream, checks); + bestSearchParams_["checks"] = checks; } - /** - Method that searches for nearest-neighbors - */ - virtual void findNeighbors(ResultSet& result, const ELEM_TYPE* vec, const SearchParams& searchParams) - { - if (searchParams.checks==-2) { - bestIndex->findNeighbors(result, vec, bestSearchParams); - } - else { - bestIndex->findNeighbors(result, vec, searchParams); - } - } + /** + * Method that searches for nearest-neighbors + */ + virtual void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + { + int checks = get_param(searchParams,"checks",FLANN_CHECKS_AUTOTUNED); + if (checks == FLANN_CHECKS_AUTOTUNED) { + bestIndex_->findNeighbors(result, vec, bestSearchParams_); + } + else { + bestIndex_->findNeighbors(result, vec, searchParams); + } + } - const IndexParams* getParameters() const - { - return bestIndex->getParameters(); - } + IndexParams getParameters() const + { + return bestIndex_->getParameters(); + } + SearchParams getSearchParameters() const + { + return bestSearchParams_; + } - /** - Number of features in this index. - */ - virtual size_t size() const - { - return bestIndex->size(); - } + float getSpeedup() const + { + return speedup_; + } - /** - The length of each vector in this index. - */ - virtual size_t veclen() const - { - return bestIndex->veclen(); - } - - /** - The amount of memory (in bytes) this index uses. - */ - virtual int usedMemory() const - { - return bestIndex->usedMemory(); - } /** - * Algorithm name - */ + * Number of features in this index. + */ + virtual size_t size() const + { + return bestIndex_->size(); + } + + /** + * The length of each vector in this index. + */ + virtual size_t veclen() const + { + return bestIndex_->veclen(); + } + + /** + * The amount of memory (in bytes) this index uses. + */ + virtual int usedMemory() const + { + return bestIndex_->usedMemory(); + } + + /** + * Algorithm name + */ virtual flann_algorithm_t getType() const { - return FLANN_INDEX_AUTOTUNED; + return FLANN_INDEX_AUTOTUNED; } private: - struct CostData { + struct CostData + { float searchTimeCost; float buildTimeCost; - float timeCost; float memoryCost; float totalCost; + IndexParams params; }; - typedef std::pair KDTreeCostData; - typedef std::pair KMeansCostData; - - - void evaluate_kmeans(CostData& cost, const KMeansIndexParams& kmeans_params) + void evaluate_kmeans(CostData& cost) { StartStopTimer t; int checks; const int nn = 1; - logger().info("KMeansTree using params: max_iterations=%d, branching=%d\n", kmeans_params.iterations, kmeans_params.branching); - KMeansIndex kmeans(sampledDataset, kmeans_params); + Logger::info("KMeansTree using params: max_iterations=%d, branching=%d\n", + get_param(cost.params,"iterations"), + get_param(cost.params,"branching")); + KMeansIndex kmeans(sampledDataset_, cost.params, distance_); // measure index build time t.start(); kmeans.buildIndex(); @@ -244,25 +232,24 @@ private: float buildTime = (float)t.value; // measure search time - float searchTime = test_index_precision(kmeans, sampledDataset, testDataset, gt_matches, index_params.target_precision, checks, nn);; + float searchTime = test_index_precision(kmeans, sampledDataset_, testDataset_, gt_matches_, target_precision_, checks, distance_, nn); - float datasetMemory = (float)(sampledDataset.rows*sampledDataset.cols*sizeof(float)); - cost.memoryCost = (kmeans.usedMemory()+datasetMemory)/datasetMemory; + float datasetMemory = float(sampledDataset_.rows * sampledDataset_.cols * sizeof(float)); + cost.memoryCost = (kmeans.usedMemory() + datasetMemory) / datasetMemory; cost.searchTimeCost = searchTime; cost.buildTimeCost = buildTime; - cost.timeCost = (buildTime*index_params.build_weight+searchTime); - logger().info("KMeansTree buildTime=%g, searchTime=%g, timeCost=%g, buildTimeFactor=%g\n",buildTime, searchTime, cost.timeCost, index_params.build_weight); + Logger::info("KMeansTree buildTime=%g, searchTime=%g, build_weight=%g\n", buildTime, searchTime, build_weight_); } - void evaluate_kdtree(CostData& cost, const KDTreeIndexParams& kdtree_params) + void evaluate_kdtree(CostData& cost) { StartStopTimer t; int checks; const int nn = 1; - logger().info("KDTree using params: trees=%d\n",kdtree_params.trees); - KDTreeIndex kdtree(sampledDataset, kdtree_params); + Logger::info("KDTree using params: trees=%d\n", get_param(cost.params,"trees")); + KDTreeIndex kdtree(sampledDataset_, cost.params, distance_); t.start(); kdtree.buildIndex(); @@ -270,267 +257,220 @@ private: float buildTime = (float)t.value; //measure search time - float searchTime = test_index_precision(kdtree, sampledDataset, testDataset, gt_matches, index_params.target_precision, checks, nn); + float searchTime = test_index_precision(kdtree, sampledDataset_, testDataset_, gt_matches_, target_precision_, checks, distance_, nn); - float datasetMemory = (float)(sampledDataset.rows*sampledDataset.cols*sizeof(float)); - cost.memoryCost = (kdtree.usedMemory()+datasetMemory)/datasetMemory; + float datasetMemory = float(sampledDataset_.rows * sampledDataset_.cols * sizeof(float)); + cost.memoryCost = (kdtree.usedMemory() + datasetMemory) / datasetMemory; cost.searchTimeCost = searchTime; cost.buildTimeCost = buildTime; - cost.timeCost = (buildTime*index_params.build_weight+searchTime); - logger().info("KDTree buildTime=%g, searchTime=%g, timeCost=%g\n",buildTime, searchTime, cost.timeCost); + Logger::info("KDTree buildTime=%g, searchTime=%g\n", buildTime, searchTime); } -// struct KMeansSimpleDownhillFunctor { -// -// Autotune& autotuner; -// KMeansSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {}; -// -// float operator()(int* params) { -// -// float maxFloat = numeric_limits::max(); -// -// if (params[0]<2) return maxFloat; -// if (params[1]<0) return maxFloat; -// -// CostData c; -// c.params["algorithm"] = KMEANS; -// c.params["centers-init"] = CENTERS_RANDOM; -// c.params["branching"] = params[0]; -// c.params["max-iterations"] = params[1]; -// -// autotuner.evaluate_kmeans(c); -// -// return c.timeCost; -// -// } -// }; -// -// struct KDTreeSimpleDownhillFunctor { -// -// Autotune& autotuner; -// KDTreeSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {}; -// -// float operator()(int* params) { -// float maxFloat = numeric_limits::max(); -// -// if (params[0]<1) return maxFloat; -// -// CostData c; -// c.params["algorithm"] = KDTREE; -// c.params["trees"] = params[0]; -// -// autotuner.evaluate_kdtree(c); -// -// return c.timeCost; -// -// } -// }; + // struct KMeansSimpleDownhillFunctor { + // + // Autotune& autotuner; + // KMeansSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {}; + // + // float operator()(int* params) { + // + // float maxFloat = numeric_limits::max(); + // + // if (params[0]<2) return maxFloat; + // if (params[1]<0) return maxFloat; + // + // CostData c; + // c.params["algorithm"] = KMEANS; + // c.params["centers-init"] = CENTERS_RANDOM; + // c.params["branching"] = params[0]; + // c.params["max-iterations"] = params[1]; + // + // autotuner.evaluate_kmeans(c); + // + // return c.timeCost; + // + // } + // }; + // + // struct KDTreeSimpleDownhillFunctor { + // + // Autotune& autotuner; + // KDTreeSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {}; + // + // float operator()(int* params) { + // float maxFloat = numeric_limits::max(); + // + // if (params[0]<1) return maxFloat; + // + // CostData c; + // c.params["algorithm"] = KDTREE; + // c.params["trees"] = params[0]; + // + // autotuner.evaluate_kdtree(c); + // + // return c.timeCost; + // + // } + // }; - KMeansCostData optimizeKMeans() + void optimizeKMeans(std::vector& costs) { - logger().info("KMEANS, Step 1: Exploring parameter space\n"); + Logger::info("KMEANS, Step 1: Exploring parameter space\n"); // explore kmeans parameters space using combinations of the parameters below int maxIterations[] = { 1, 5, 10, 15 }; int branchingFactors[] = { 16, 32, 64, 128, 256 }; - int kmeansParamSpaceSize = ARRAY_LEN(maxIterations)*ARRAY_LEN(branchingFactors); - - std::vector kmeansCosts(kmeansParamSpaceSize); - -// CostData* kmeansCosts = new CostData[kmeansParamSpaceSize]; + int kmeansParamSpaceSize = FLANN_ARRAY_LEN(maxIterations) * FLANN_ARRAY_LEN(branchingFactors); + costs.reserve(costs.size() + kmeansParamSpaceSize); // evaluate kmeans for all parameter combinations - int cnt = 0; - for (size_t i=0; i0 && kmeansCosts[k].first.timeCost < kmeansCosts[k-1].first.timeCost) { - swap(kmeansCosts[k],kmeansCosts[k-1]); - --k; - } - ++cnt; + evaluate_kmeans(cost); + costs.push_back(cost); } } -// logger().info("KMEANS, Step 2: simplex-downhill optimization\n"); -// -// const int n = 2; -// // choose initial simplex points as the best parameters so far -// int kmeansNMPoints[n*(n+1)]; -// float kmeansVals[n+1]; -// for (int i=0;i0 && kmeansCosts[k].first.totalCost < kmeansCosts[k-1].first.totalCost) { - swap(kmeansCosts[k],kmeansCosts[k-1]); - k--; - } - } - // display the costs obtained - for (int i=0;i& costs) { - - logger().info("KD-TREE, Step 1: Exploring parameter space\n"); + Logger::info("KD-TREE, Step 1: Exploring parameter space\n"); // explore kd-tree parameters space using the parameters below int testTrees[] = { 1, 4, 8, 16, 32 }; - size_t kdtreeParamSpaceSize = ARRAY_LEN(testTrees); - std::vector kdtreeCosts(kdtreeParamSpaceSize); - // evaluate kdtree for all parameter combinations - int cnt = 0; - for (size_t i=0; i0 && kdtreeCosts[k].first.timeCost < kdtreeCosts[k-1].first.timeCost) { - swap(kdtreeCosts[k],kdtreeCosts[k-1]); - --k; - } - ++cnt; + evaluate_kdtree(cost); + costs.push_back(cost); } -// logger().info("KD-TREE, Step 2: simplex-downhill optimization\n"); -// -// const int n = 1; -// // choose initial simplex points as the best parameters so far -// int kdtreeNMPoints[n*(n+1)]; -// float kdtreeVals[n+1]; -// for (int i=0;i0 && kdtreeCosts[k].first.totalCost < kdtreeCosts[k-1].first.totalCost) { - swap(kdtreeCosts[k],kdtreeCosts[k-1]); - k--; - } - } - // display costs obtained - for (size_t i=0;i costs; - logger().info("Entering autotuning, dataset size: %d, sampleSize: %d, testSampleSize: %d\n",dataset.rows, sampleSize, testSampleSize); + int sampleSize = int(sample_fraction_ * dataset_.rows); + int testSampleSize = std::min(sampleSize / 10, 1000); + + Logger::info("Entering autotuning, dataset size: %d, sampleSize: %d, testSampleSize: %d, target precision: %g\n", dataset_.rows, sampleSize, testSampleSize, target_precision_); // For a very small dataset, it makes no sense to build any fancy index, just // use linear search - if (testSampleSize<10) { - logger().info("Choosing linear, dataset too small\n"); - return new LinearIndexParams(); + if (testSampleSize < 10) { + Logger::info("Choosing linear, dataset too small\n"); + return LinearIndexParams(); } // We use a fraction of the original dataset to speedup the autotune algorithm - sampledDataset = random_sample(dataset,sampleSize); + sampledDataset_ = random_sample(dataset_, sampleSize); // We use a cross-validation approach, first we sample a testset from the dataset - testDataset = random_sample(sampledDataset,testSampleSize,true); + testDataset_ = random_sample(sampledDataset_, testSampleSize, true); // We compute the ground truth using linear search - logger().info("Computing ground truth... \n"); - gt_matches = Matrix(new int[testDataset.rows],(long)testDataset.rows, 1); + Logger::info("Computing ground truth... \n"); + gt_matches_ = Matrix(new int[testDataset_.rows], testDataset_.rows, 1); StartStopTimer t; t.start(); - compute_ground_truth(sampledDataset, testDataset, gt_matches, 0); + compute_ground_truth(sampledDataset_, testDataset_, gt_matches_, 0, distance_); t.stop(); - float bestCost = (float)t.value; - IndexParams* bestParams = new LinearIndexParams(); + + CostData linear_cost; + linear_cost.searchTimeCost = (float)t.value; + linear_cost.buildTimeCost = 0; + linear_cost.memoryCost = 0; + linear_cost.params["algorithm"] = FLANN_INDEX_LINEAR; + + costs.push_back(linear_cost); // Start parameter autotune process - logger().info("Autotuning parameters...\n"); + Logger::info("Autotuning parameters...\n"); + optimizeKMeans(costs); + optimizeKDTree(costs); - KMeansCostData kmeansCost = optimizeKMeans(); - if (kmeansCost.first.totalCost 0) { + for (size_t i = 0; i < costs.size(); ++i) { + float crtCost = (costs[i].buildTimeCost * build_weight_ + costs[i].searchTimeCost) / bestTimeCost + + memory_weight_ * costs[i].memoryCost; + if (crtCost < bestCost) { + bestCost = crtCost; + bestParams = costs[i].params; + } + } } - gt_matches.release(); - sampledDataset.release(); - testDataset.release(); + delete[] gt_matches_.data; + delete[] testDataset_.data; + delete[] sampledDataset_.data; return bestParams; } @@ -538,48 +478,48 @@ private: /** - Estimates the search time parameters needed to get the desired precision. - Precondition: the index is built - Postcondition: the searchParams will have the optimum params set, also the speedup obtained over linear search. - */ + * Estimates the search time parameters needed to get the desired precision. + * Precondition: the index is built + * Postcondition: the searchParams will have the optimum params set, also the speedup obtained over linear search. + */ float estimateSearchParams(SearchParams& searchParams) { const int nn = 1; const size_t SAMPLE_COUNT = 1000; - assert(bestIndex!=NULL); // must have a valid index + assert(bestIndex_ != NULL); // must have a valid index float speedup = 0; - int samples = (int)std::min(dataset.rows/10, SAMPLE_COUNT); - if (samples>0) { - Matrix testDataset = random_sample(dataset,samples); + int samples = (int)std::min(dataset_.rows / 10, SAMPLE_COUNT); + if (samples > 0) { + Matrix testDataset = random_sample(dataset_, samples); - logger().info("Computing ground truth\n"); + Logger::info("Computing ground truth\n"); // we need to compute the ground truth first - Matrix gt_matches(new int[testDataset.rows],(long)testDataset.rows,1); + Matrix gt_matches(new int[testDataset.rows], testDataset.rows, 1); StartStopTimer t; t.start(); - compute_ground_truth(dataset, testDataset, gt_matches,1); + compute_ground_truth(dataset_, testDataset, gt_matches, 1, distance_); t.stop(); float linear = (float)t.value; int checks; - logger().info("Estimating number of checks\n"); + Logger::info("Estimating number of checks\n"); float searchTime; float cb_index; - if (bestIndex->getType() == FLANN_INDEX_KMEANS) { - logger().info("KMeans algorithm, estimating cluster border factor\n"); - KMeansIndex* kmeans = (KMeansIndex*)bestIndex; + if (bestIndex_->getType() == FLANN_INDEX_KMEANS) { + Logger::info("KMeans algorithm, estimating cluster border factor\n"); + KMeansIndex* kmeans = (KMeansIndex*)bestIndex_; float bestSearchTime = -1; float best_cb_index = -1; int best_checks = -1; - for (cb_index = 0;cb_index<1.1f; cb_index+=0.2f) { + for (cb_index = 0; cb_index < 1.1f; cb_index += 0.2f) { kmeans->set_cb_index(cb_index); - searchTime = test_index_precision(*kmeans, dataset, testDataset, gt_matches, index_params.target_precision, checks, nn, 1); - if (searchTimeset_cb_index(best_cb_index); - logger().info("Optimum cb_index: %g\n",cb_index); - ((KMeansIndexParams*)bestParams)->cb_index = cb_index; + Logger::info("Optimum cb_index: %g\n", cb_index); + bestParams_["cb_index"] = cb_index; } else { - searchTime = test_index_precision(*bestIndex, dataset, testDataset, gt_matches, index_params.target_precision, checks, nn, 1); + searchTime = test_index_precision(*bestIndex_, dataset_, testDataset, gt_matches, target_precision_, checks, distance_, nn, 1); } - logger().info("Required number of checks: %d \n",checks);; - searchParams.checks = checks; + Logger::info("Required number of checks: %d \n", checks); + searchParams["checks"] = checks; - speedup = linear/searchTime; + speedup = linear / searchTime; - gt_matches.release(); + delete[] gt_matches.data; + delete[] testDataset.data; } return speedup; } +private: + NNIndex* bestIndex_; + + IndexParams bestParams_; + SearchParams bestSearchParams_; + + Matrix sampledDataset_; + Matrix testDataset_; + Matrix gt_matches_; + + float speedup_; + + /** + * The dataset used by this index + */ + const Matrix dataset_; + + /** + * Index parameters + */ + float target_precision_; + float build_weight_; + float memory_weight_; + float sample_fraction_; + + Distance distance_; + + }; +} -} // namespace cvflann - -#endif /* _OPENCV_AUTOTUNEDINDEX_H_ */ +#endif /* OPENCV_FLANN_AUTOTUNED_INDEX_H_ */ diff --git a/modules/flann/include/opencv2/flann/composite_index.h b/modules/flann/include/opencv2/flann/composite_index.h index 7738bf6a35..527ca1ad77 100644 --- a/modules/flann/include/opencv2/flann/composite_index.h +++ b/modules/flann/include/opencv2/flann/composite_index.h @@ -28,135 +28,167 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_COMPOSITETREE_H_ -#define _OPENCV_COMPOSITETREE_H_ +#ifndef OPENCV_FLANN_COMPOSITE_INDEX_H_ +#define OPENCV_FLANN_COMPOSITE_INDEX_H_ -#include "opencv2/flann/general.h" -#include "opencv2/flann/nn_index.h" +#include "general.h" +#include "nn_index.h" +#include "kdtree_index.h" +#include "kmeans_index.h" namespace cvflann { - -struct CompositeIndexParams : public IndexParams { - CompositeIndexParams(int trees_ = 4, int branching_ = 32, int iterations_ = 11, - flann_centers_init_t centers_init_ = FLANN_CENTERS_RANDOM, float cb_index_ = 0.2 ) : - IndexParams(FLANN_INDEX_COMPOSITE), - trees(trees_), - branching(branching_), - iterations(iterations_), - centers_init(centers_init_), - cb_index(cb_index_) {}; - - int trees; // number of randomized trees to use (for kdtree) - int branching; // branching factor (for kmeans tree) - int iterations; // max iterations to perform in one kmeans clustering (kmeans tree) - flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree - float cb_index; // cluster boundary index. Used when searching the kmeans tree - - void print() const - { - logger().info("Index type: %d\n",(int)algorithm); - logger().info("Trees: %d\n", trees); - logger().info("Branching: %d\n", branching); - logger().info("Iterations: %d\n", iterations); - logger().info("Centres initialisation: %d\n", centers_init); - logger().info("Cluster boundary weight: %g\n", cb_index); - } +/** + * Index parameters for the CompositeIndex. + */ +struct CompositeIndexParams : public IndexParams +{ + CompositeIndexParams(int trees = 4, int branching = 32, int iterations = 11, + flann_centers_init_t centers_init = FLANN_CENTERS_RANDOM, float cb_index = 0.2 ) + { + (*this)["algorithm"] = FLANN_INDEX_KMEANS; + // number of randomized trees to use (for kdtree) + (*this)["trees"] = trees; + // branching factor + (*this)["branching"] = branching; + // max iterations to perform in one kmeans clustering (kmeans tree) + (*this)["iterations"] = iterations; + // algorithm used for picking the initial cluster centers for kmeans tree + (*this)["centers_init"] = centers_init; + // cluster boundary index. Used when searching the kmeans tree + (*this)["cb_index"] = cb_index; + } }; - -template ::type > -class CompositeIndex : public NNIndex +/** + * This index builds a kd-tree index and a k-means index and performs nearest + * neighbour search both indexes. This gives a slight boost in search performance + * as some of the neighbours that are missed by one index are found by the other. + */ +template +class CompositeIndex : public NNIndex { - KMeansIndex* kmeans; - KDTreeIndex* kdtree; - - const Matrix dataset; - - const IndexParams& index_params; - - CompositeIndex& operator=(const CompositeIndex&); - CompositeIndex(const CompositeIndex&); public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; - CompositeIndex(const Matrix& inputData, const CompositeIndexParams& params = CompositeIndexParams() ) : - dataset(inputData), index_params(params) - { - KDTreeIndexParams kdtree_params(params.trees); - KMeansIndexParams kmeans_params(params.branching, params.iterations, params.centers_init, params.cb_index); + /** + * Index constructor + * @param inputData dataset containing the points to index + * @param params Index parameters + * @param d Distance functor + * @return + */ + CompositeIndex(const Matrix& inputData, const IndexParams& params = CompositeIndexParams(), + Distance d = Distance()) : index_params_(params) + { + kdtree_index_ = new KDTreeIndex(inputData, params, d); + kmeans_index_ = new KMeansIndex(inputData, params, d); - kdtree = new KDTreeIndex(inputData,kdtree_params); - kmeans = new KMeansIndex(inputData,kmeans_params); + } - } - - virtual ~CompositeIndex() - { - delete kdtree; - delete kmeans; - } + CompositeIndex(const CompositeIndex&); + CompositeIndex& operator=(const CompositeIndex&); + virtual ~CompositeIndex() + { + delete kdtree_index_; + delete kmeans_index_; + } + /** + * @return The index type + */ flann_algorithm_t getType() const { return FLANN_INDEX_COMPOSITE; } - + /** + * @return Size of the index + */ size_t size() const - { - return dataset.rows; - } + { + return kdtree_index_->size(); + } - size_t veclen() const - { - return dataset.cols; - } + /** + * \returns The dimensionality of the features in this index. + */ + size_t veclen() const + { + return kdtree_index_->veclen(); + } + /** + * \returns The amount of memory (in bytes) used by the index. + */ + int usedMemory() const + { + return kmeans_index_->usedMemory() + kdtree_index_->usedMemory(); + } - int usedMemory() const - { - return kmeans->usedMemory()+kdtree->usedMemory(); - } - - void buildIndex() - { - logger().info("Building kmeans tree...\n"); - kmeans->buildIndex(); - logger().info("Building kdtree tree...\n"); - kdtree->buildIndex(); - } - + /** + * \brief Builds the index + */ + void buildIndex() + { + Logger::info("Building kmeans tree...\n"); + kmeans_index_->buildIndex(); + Logger::info("Building kdtree tree...\n"); + kdtree_index_->buildIndex(); + } + /** + * \brief Saves the index to a stream + * \param stream The stream to save the index to + */ void saveIndex(FILE* stream) { - kmeans->saveIndex(stream); - kdtree->saveIndex(stream); + kmeans_index_->saveIndex(stream); + kdtree_index_->saveIndex(stream); } - + /** + * \brief Loads the index from a stream + * \param stream The stream from which the index is loaded + */ void loadIndex(FILE* stream) { - kmeans->loadIndex(stream); - kdtree->loadIndex(stream); + kmeans_index_->loadIndex(stream); + kdtree_index_->loadIndex(stream); } - void findNeighbors(ResultSet& result, const ELEM_TYPE* vec, const SearchParams& searchParams) - { - kmeans->findNeighbors(result,vec,searchParams); - kdtree->findNeighbors(result,vec,searchParams); - } + /** + * \returns The index parameters + */ + IndexParams getParameters() const + { + return index_params_; + } - const IndexParams* getParameters() const - { - return &index_params; - } + /** + * \brief Method that searches for nearest-neighbours + */ + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + { + kmeans_index_->findNeighbors(result, vec, searchParams); + kdtree_index_->findNeighbors(result, vec, searchParams); + } +private: + /** The k-means index */ + KMeansIndex* kmeans_index_; + /** The kd-tree index */ + KDTreeIndex* kdtree_index_; + + /** The index parameters */ + const IndexParams index_params_; }; -} // namespace cvflann +} -#endif //_OPENCV_COMPOSITETREE_H_ +#endif //OPENCV_FLANN_COMPOSITE_INDEX_H_ diff --git a/modules/flann/include/opencv2/flann/config.h b/modules/flann/include/opencv2/flann/config.h new file mode 100644 index 0000000000..56832fd37f --- /dev/null +++ b/modules/flann/include/opencv2/flann/config.h @@ -0,0 +1,38 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2011 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2011 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + + +#ifndef OPENCV_FLANN_CONFIG_H_ +#define OPENCV_FLANN_CONFIG_H_ + +#ifdef FLANN_VERSION_ +#undef FLANN_VERSION_ +#endif +#define FLANN_VERSION_ "1.6.10" + +#endif /* OPENCV_FLANN_CONFIG_H_ */ diff --git a/modules/flann/include/opencv2/flann/defines.h b/modules/flann/include/opencv2/flann/defines.h new file mode 100644 index 0000000000..c71e149ec8 --- /dev/null +++ b/modules/flann/include/opencv2/flann/defines.h @@ -0,0 +1,175 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2011 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2011 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + + +#ifndef OPENCV_FLANN_DEFINES_H_ +#define OPENCV_FLANN_DEFINES_H_ + +#include "config.h" + +#ifdef FLANN_EXPORT +#undef FLANN_EXPORT +#endif +#ifdef WIN32 +/* win32 dll export/import directives */ + #ifdef FLANN_EXPORTS + #define FLANN_EXPORT __declspec(dllexport) + #elif defined(FLANN_STATIC) + #define FLANN_EXPORT + #else + #define FLANN_EXPORT __declspec(dllimport) + #endif +#else +/* unix needs nothing */ + #define FLANN_EXPORT +#endif + + +#ifdef FLANN_DEPRECATED +#undef FLANN_DEPRECATED +#endif +#ifdef __GNUC__ +#define FLANN_DEPRECATED __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define FLANN_DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement FLANN_DEPRECATED for this compiler") +#define FLANN_DEPRECATED +#endif + + +#undef FLANN_PLATFORM_32_BIT +#undef FLANN_PLATFORM_64_BIT +#if __amd64__ || __x86_64__ || _WIN64 || _M_X64 +#define FLANN_PLATFORM_64_BIT +#else +#define FLANN_PLATFORM_32_BIT +#endif + + +#undef FLANN_ARRAY_LEN +#define FLANN_ARRAY_LEN(a) (sizeof(a)/sizeof(a[0])) + +namespace cvflann { + +/* Nearest neighbour index algorithms */ +enum flann_algorithm_t +{ + FLANN_INDEX_LINEAR = 0, + FLANN_INDEX_KDTREE = 1, + FLANN_INDEX_KMEANS = 2, + FLANN_INDEX_COMPOSITE = 3, + FLANN_INDEX_KDTREE_SINGLE = 4, + FLANN_INDEX_HIERARCHICAL = 5, + FLANN_INDEX_LSH = 6, + FLANN_INDEX_SAVED = 254, + FLANN_INDEX_AUTOTUNED = 255, + + // deprecated constants, should use the FLANN_INDEX_* ones instead + LINEAR = 0, + KDTREE = 1, + KMEANS = 2, + COMPOSITE = 3, + KDTREE_SINGLE = 4, + SAVED = 254, + AUTOTUNED = 255 +}; + + + +enum flann_centers_init_t +{ + FLANN_CENTERS_RANDOM = 0, + FLANN_CENTERS_GONZALES = 1, + FLANN_CENTERS_KMEANSPP = 2, + + // deprecated constants, should use the FLANN_CENTERS_* ones instead + CENTERS_RANDOM = 0, + CENTERS_GONZALES = 1, + CENTERS_KMEANSPP = 2 +}; + +enum flann_log_level_t +{ + FLANN_LOG_NONE = 0, + FLANN_LOG_FATAL = 1, + FLANN_LOG_ERROR = 2, + FLANN_LOG_WARN = 3, + FLANN_LOG_INFO = 4, +}; + +enum flann_distance_t +{ + FLANN_DIST_EUCLIDEAN = 1, + FLANN_DIST_L2 = 1, + FLANN_DIST_MANHATTAN = 2, + FLANN_DIST_L1 = 2, + FLANN_DIST_MINKOWSKI = 3, + FLANN_DIST_MAX = 4, + FLANN_DIST_HIST_INTERSECT = 5, + FLANN_DIST_HELLINGER = 6, + FLANN_DIST_CHI_SQUARE = 7, + FLANN_DIST_CS = 7, + FLANN_DIST_KULLBACK_LEIBLER = 8, + FLANN_DIST_KL = 8, + + // deprecated constants, should use the FLANN_DIST_* ones instead + EUCLIDEAN = 1, + MANHATTAN = 2, + MINKOWSKI = 3, + MAX_DIST = 4, + HIST_INTERSECT = 5, + HELLINGER = 6, + CS = 7, + KL = 8, + KULLBACK_LEIBLER = 8 +}; + +enum flann_datatype_t +{ + FLANN_INT8 = 0, + FLANN_INT16 = 1, + FLANN_INT32 = 2, + FLANN_INT64 = 3, + FLANN_UINT8 = 4, + FLANN_UINT16 = 5, + FLANN_UINT32 = 6, + FLANN_UINT64 = 7, + FLANN_FLOAT32 = 8, + FLANN_FLOAT64 = 9 +}; + +enum +{ + FLANN_CHECKS_UNLIMITED = -1, + FLANN_CHECKS_AUTOTUNED = -2 +}; + +} + +#endif /* OPENCV_FLANN_DEFINES_H_ */ diff --git a/modules/flann/include/opencv2/flann/dist.h b/modules/flann/include/opencv2/flann/dist.h index 2ddbee31e8..094fd3435c 100644 --- a/modules/flann/include/opencv2/flann/dist.h +++ b/modules/flann/include/opencv2/flann/dist.h @@ -28,302 +28,777 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_DIST_H_ -#define _OPENCV_DIST_H_ +#ifndef OPENCV_FLANN_DIST_H_ +#define OPENCV_FLANN_DIST_H_ #include +#include +#include +#ifdef _MSC_VER +typedef unsigned uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#include "defines.h" -#include "opencv2/flann/general.h" namespace cvflann { -/** - * Distance function by default set to the custom distance - * function. This can be set to a specific distance function - * for further efficiency. - */ -#define flann_dist custom_dist -//#define flann_dist euclidean_dist +template +inline T abs(T x) { return (x<0) ? -x : x; } + +template<> +inline int abs(int x) { return ::abs(x); } + +template<> +inline float abs(float x) { return fabsf(x); } + +template<> +inline double abs(double x) { return fabs(x); } + +template<> +inline long double abs(long double x) { return fabsl(x); } + + +template +struct Accumulator { typedef T Type; }; +template<> +struct Accumulator { typedef float Type; }; +template<> +struct Accumulator { typedef float Type; }; +template<> +struct Accumulator { typedef float Type; }; +template<> +struct Accumulator { typedef float Type; }; +template<> +struct Accumulator { typedef float Type; }; +template<> +struct Accumulator { typedef float Type; }; + + +class True +{ +}; + +class False +{ +}; /** - * Compute the squared Euclidean distance between two vectors. + * Squared Euclidean distance functor. * - * This is highly optimised, with loop unrolling, as it is one - * of the most expensive inner loops. - * - * The computation of squared root at the end is omitted for - * efficiency. + * This is the simpler, unrolled version. This is preferable for + * very low dimensionality data (eg 3D points) */ -template -double euclidean_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) +template +struct L2_Simple { - double distsq = acc; - double diff0, diff1, diff2, diff3; - Iterator1 lastgroup = last1 - 3; + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; - /* Process 4 items with each loop for efficiency. */ - while (first1 < lastgroup) { - diff0 = first1[0] - first2[0]; - diff1 = first1[1] - first2[1]; - diff2 = first1[2] - first2[2]; - diff3 = first1[3] - first2[3]; - distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; - first1 += 4; - first2 += 4; - } - /* Process last 0-3 pixels. Not needed for standard vector lengths. */ - while (first1 < last1) { - diff0 = *first1++ - *first2++; - distsq += diff0 * diff0; - } - return distsq; -} + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const + { + ResultType result = ResultType(); + ResultType diff; + for(size_t i = 0; i < size; ++i ) { + diff = *a++ - *b++; + result += diff*diff; + } + return result; + } + + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + return (a-b)*(a-b); + } +}; -CV_EXPORTS double euclidean_dist(const unsigned char* first1, const unsigned char* last1, unsigned char* first2, double acc); /** - * Compute the Manhattan (L_1) distance between two vectors. - * - * This is highly optimised, with loop unrolling, as it is one - * of the most expensive inner loops. + * Squared Euclidean distance functor, optimized version */ -template -double manhattan_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) +template +struct L2 { - double distsq = acc; - double diff0, diff1, diff2, diff3; - Iterator1 lastgroup = last1 - 3; + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; - /* Process 4 items with each loop for efficiency. */ - while (first1 < lastgroup) { - diff0 = fabs(first1[0] - first2[0]); - diff1 = fabs(first1[1] - first2[1]); - diff2 = fabs(first1[2] - first2[2]); - diff3 = fabs(first1[3] - first2[3]); - distsq += diff0 + diff1 + diff2 + diff3; - first1 += 4; - first2 += 4; - } - /* Process last 0-3 pixels. Not needed for standard vector lengths. */ - while (first1 < last1) { - diff0 = fabs(*first1++ - *first2++); - distsq += diff0; - } - return distsq; -} + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the squared Euclidean distance between two vectors. + * + * This is highly optimised, with loop unrolling, as it is one + * of the most expensive inner loops. + * + * The computation of squared root at the end is omitted for + * efficiency. + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + ResultType diff0, diff1, diff2, diff3; + Iterator1 last = a + size; + Iterator1 lastgroup = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + diff0 = (ResultType)(a[0] - b[0]); + diff1 = (ResultType)(a[1] - b[1]); + diff2 = (ResultType)(a[2] - b[2]); + diff3 = (ResultType)(a[3] - b[3]); + result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; + a += 4; + b += 4; + + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 pixels. Not needed for standard vector lengths. */ + while (a < last) { + diff0 = (ResultType)(*a++ - *b++); + result += diff0 * diff0; + } + return result; + } + + /** + * Partial euclidean distance, using just one dimension. This is used by the + * kd-tree when computing partial distances while traversing the tree. + * + * Squared root is omitted for efficiency. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + return (a-b)*(a-b); + } +}; -CV_EXPORTS int flann_minkowski_order(); +/* + * Manhattan distance functor, optimized version + */ +template +struct L1 +{ + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the Manhattan (L_1) distance between two vectors. + * + * This is highly optimised, with loop unrolling, as it is one + * of the most expensive inner loops. + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + ResultType diff0, diff1, diff2, diff3; + Iterator1 last = a + size; + Iterator1 lastgroup = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + diff0 = (ResultType)abs(a[0] - b[0]); + diff1 = (ResultType)abs(a[1] - b[1]); + diff2 = (ResultType)abs(a[2] - b[2]); + diff3 = (ResultType)abs(a[3] - b[3]); + result += diff0 + diff1 + diff2 + diff3; + a += 4; + b += 4; + + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 pixels. Not needed for standard vector lengths. */ + while (a < last) { + diff0 = (ResultType)abs(*a++ - *b++); + result += diff0; + } + return result; + } + + /** + * Partial distance, used by the kd-tree. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + return abs(a-b); + } +}; + + + +template +struct MinkowskiDistance +{ + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + int order; + + MinkowskiDistance(int order_) : order(order_) {} + + /** + * Compute the Minkowsky (L_p) distance between two vectors. + * + * This is highly optimised, with loop unrolling, as it is one + * of the most expensive inner loops. + * + * The computation of squared root at the end is omitted for + * efficiency. + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + ResultType diff0, diff1, diff2, diff3; + Iterator1 last = a + size; + Iterator1 lastgroup = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + diff0 = (ResultType)abs(a[0] - b[0]); + diff1 = (ResultType)abs(a[1] - b[1]); + diff2 = (ResultType)abs(a[2] - b[2]); + diff3 = (ResultType)abs(a[3] - b[3]); + result += pow(diff0,order) + pow(diff1,order) + pow(diff2,order) + pow(diff3,order); + a += 4; + b += 4; + + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 pixels. Not needed for standard vector lengths. */ + while (a < last) { + diff0 = (ResultType)abs(*a++ - *b++); + result += pow(diff0,order); + } + return result; + } + + /** + * Partial distance, used by the kd-tree. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + return pow(static_cast(abs(a-b)),order); + } +}; + + + +template +struct MaxDistance +{ + typedef False is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the max distance (L_infinity) between two vectors. + * + * This distance is not a valid kdtree distance, it's not dimensionwise additive. + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + ResultType diff0, diff1, diff2, diff3; + Iterator1 last = a + size; + Iterator1 lastgroup = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + diff0 = abs(a[0] - b[0]); + diff1 = abs(a[1] - b[1]); + diff2 = abs(a[2] - b[2]); + diff3 = abs(a[3] - b[3]); + if (diff0>result) {result = diff0; } + if (diff1>result) {result = diff1; } + if (diff2>result) {result = diff2; } + if (diff3>result) {result = diff3; } + a += 4; + b += 4; + + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 pixels. Not needed for standard vector lengths. */ + while (a < last) { + diff0 = abs(*a++ - *b++); + result = (diff0>result) ? diff0 : result; + } + return result; + } + + /* This distance functor is not dimension-wise additive, which + * makes it an invalid kd-tree distance, not implementing the accum_dist method */ + +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** - * Compute the Minkowski (L_p) distance between two vectors. - * - * This is highly optimised, with loop unrolling, as it is one - * of the most expensive inner loops. - * - * The computation of squared root at the end is omitted for - * efficiency. + * Hamming distance functor - counts the bit differences between two strings - useful for the Brief descriptor + * bit count of A exclusive XOR'ed with B */ -template -double minkowski_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) +struct HammingLUT { - double distsq = acc; - double diff0, diff1, diff2, diff3; - Iterator1 lastgroup = last1 - 3; + typedef False is_kdtree_distance; + typedef False is_vector_space_distance; - int p = flann_minkowski_order(); + typedef unsigned char ElementType; + typedef int ResultType; - /* Process 4 items with each loop for efficiency. */ - while (first1 < lastgroup) { - diff0 = fabs(first1[0] - first2[0]); - diff1 = fabs(first1[1] - first2[1]); - diff2 = fabs(first1[2] - first2[2]); - diff3 = fabs(first1[3] - first2[3]); - distsq += pow(diff0,p) + pow(diff1,p) + pow(diff2,p) + pow(diff3,p); - first1 += 4; - first2 += 4; - } - /* Process last 0-3 pixels. Not needed for standard vector lengths. */ - while (first1 < last1) { - diff0 = fabs(*first1++ - *first2++); - distsq += pow(diff0,p); - } - return distsq; -} + /** this will count the bits in a ^ b + */ + ResultType operator()(const unsigned char* a, const unsigned char* b, int size) const + { + ResultType result = 0; + for (int i = 0; i < size; i++) { + result += byteBitsLookUp(a[i] ^ b[i]); + } + return result; + } -// L_infinity distance (NOT A VALID KD-TREE DISTANCE - NOT DIMENSIONWISE ADDITIVE) -template -double max_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) -{ - double dist = acc; - Iterator1 lastgroup = last1 - 3; - double diff0, diff1, diff2, diff3; + /** \brief given a byte, count the bits using a look up table + * \param b the byte to count bits. The look up table has an entry for all + * values of b, where that entry is the number of bits. + * \return the number of bits in byte b + */ + static unsigned char byteBitsLookUp(unsigned char b) + { + static const unsigned char table[256] = { + /* 0 */ 0, /* 1 */ 1, /* 2 */ 1, /* 3 */ 2, + /* 4 */ 1, /* 5 */ 2, /* 6 */ 2, /* 7 */ 3, + /* 8 */ 1, /* 9 */ 2, /* a */ 2, /* b */ 3, + /* c */ 2, /* d */ 3, /* e */ 3, /* f */ 4, + /* 10 */ 1, /* 11 */ 2, /* 12 */ 2, /* 13 */ 3, + /* 14 */ 2, /* 15 */ 3, /* 16 */ 3, /* 17 */ 4, + /* 18 */ 2, /* 19 */ 3, /* 1a */ 3, /* 1b */ 4, + /* 1c */ 3, /* 1d */ 4, /* 1e */ 4, /* 1f */ 5, + /* 20 */ 1, /* 21 */ 2, /* 22 */ 2, /* 23 */ 3, + /* 24 */ 2, /* 25 */ 3, /* 26 */ 3, /* 27 */ 4, + /* 28 */ 2, /* 29 */ 3, /* 2a */ 3, /* 2b */ 4, + /* 2c */ 3, /* 2d */ 4, /* 2e */ 4, /* 2f */ 5, + /* 30 */ 2, /* 31 */ 3, /* 32 */ 3, /* 33 */ 4, + /* 34 */ 3, /* 35 */ 4, /* 36 */ 4, /* 37 */ 5, + /* 38 */ 3, /* 39 */ 4, /* 3a */ 4, /* 3b */ 5, + /* 3c */ 4, /* 3d */ 5, /* 3e */ 5, /* 3f */ 6, + /* 40 */ 1, /* 41 */ 2, /* 42 */ 2, /* 43 */ 3, + /* 44 */ 2, /* 45 */ 3, /* 46 */ 3, /* 47 */ 4, + /* 48 */ 2, /* 49 */ 3, /* 4a */ 3, /* 4b */ 4, + /* 4c */ 3, /* 4d */ 4, /* 4e */ 4, /* 4f */ 5, + /* 50 */ 2, /* 51 */ 3, /* 52 */ 3, /* 53 */ 4, + /* 54 */ 3, /* 55 */ 4, /* 56 */ 4, /* 57 */ 5, + /* 58 */ 3, /* 59 */ 4, /* 5a */ 4, /* 5b */ 5, + /* 5c */ 4, /* 5d */ 5, /* 5e */ 5, /* 5f */ 6, + /* 60 */ 2, /* 61 */ 3, /* 62 */ 3, /* 63 */ 4, + /* 64 */ 3, /* 65 */ 4, /* 66 */ 4, /* 67 */ 5, + /* 68 */ 3, /* 69 */ 4, /* 6a */ 4, /* 6b */ 5, + /* 6c */ 4, /* 6d */ 5, /* 6e */ 5, /* 6f */ 6, + /* 70 */ 3, /* 71 */ 4, /* 72 */ 4, /* 73 */ 5, + /* 74 */ 4, /* 75 */ 5, /* 76 */ 5, /* 77 */ 6, + /* 78 */ 4, /* 79 */ 5, /* 7a */ 5, /* 7b */ 6, + /* 7c */ 5, /* 7d */ 6, /* 7e */ 6, /* 7f */ 7, + /* 80 */ 1, /* 81 */ 2, /* 82 */ 2, /* 83 */ 3, + /* 84 */ 2, /* 85 */ 3, /* 86 */ 3, /* 87 */ 4, + /* 88 */ 2, /* 89 */ 3, /* 8a */ 3, /* 8b */ 4, + /* 8c */ 3, /* 8d */ 4, /* 8e */ 4, /* 8f */ 5, + /* 90 */ 2, /* 91 */ 3, /* 92 */ 3, /* 93 */ 4, + /* 94 */ 3, /* 95 */ 4, /* 96 */ 4, /* 97 */ 5, + /* 98 */ 3, /* 99 */ 4, /* 9a */ 4, /* 9b */ 5, + /* 9c */ 4, /* 9d */ 5, /* 9e */ 5, /* 9f */ 6, + /* a0 */ 2, /* a1 */ 3, /* a2 */ 3, /* a3 */ 4, + /* a4 */ 3, /* a5 */ 4, /* a6 */ 4, /* a7 */ 5, + /* a8 */ 3, /* a9 */ 4, /* aa */ 4, /* ab */ 5, + /* ac */ 4, /* ad */ 5, /* ae */ 5, /* af */ 6, + /* b0 */ 3, /* b1 */ 4, /* b2 */ 4, /* b3 */ 5, + /* b4 */ 4, /* b5 */ 5, /* b6 */ 5, /* b7 */ 6, + /* b8 */ 4, /* b9 */ 5, /* ba */ 5, /* bb */ 6, + /* bc */ 5, /* bd */ 6, /* be */ 6, /* bf */ 7, + /* c0 */ 2, /* c1 */ 3, /* c2 */ 3, /* c3 */ 4, + /* c4 */ 3, /* c5 */ 4, /* c6 */ 4, /* c7 */ 5, + /* c8 */ 3, /* c9 */ 4, /* ca */ 4, /* cb */ 5, + /* cc */ 4, /* cd */ 5, /* ce */ 5, /* cf */ 6, + /* d0 */ 3, /* d1 */ 4, /* d2 */ 4, /* d3 */ 5, + /* d4 */ 4, /* d5 */ 5, /* d6 */ 5, /* d7 */ 6, + /* d8 */ 4, /* d9 */ 5, /* da */ 5, /* db */ 6, + /* dc */ 5, /* dd */ 6, /* de */ 6, /* df */ 7, + /* e0 */ 3, /* e1 */ 4, /* e2 */ 4, /* e3 */ 5, + /* e4 */ 4, /* e5 */ 5, /* e6 */ 5, /* e7 */ 6, + /* e8 */ 4, /* e9 */ 5, /* ea */ 5, /* eb */ 6, + /* ec */ 5, /* ed */ 6, /* ee */ 6, /* ef */ 7, + /* f0 */ 4, /* f1 */ 5, /* f2 */ 5, /* f3 */ 6, + /* f4 */ 5, /* f5 */ 6, /* f6 */ 6, /* f7 */ 7, + /* f8 */ 5, /* f9 */ 6, /* fa */ 6, /* fb */ 7, + /* fc */ 6, /* fd */ 7, /* fe */ 7, /* ff */ 8 + }; + return table[b]; + } +}; - /* Process 4 items with each loop for efficiency. */ - while (first1 < lastgroup) { - diff0 = fabs(first1[0] - first2[0]); - diff1 = fabs(first1[1] - first2[1]); - diff2 = fabs(first1[2] - first2[2]); - diff3 = fabs(first1[3] - first2[3]); - if (diff0 > dist) dist = diff0; - if (diff1 > dist) dist = diff1; - if (diff2 > dist) dist = diff2; - if (diff3 > dist) dist = diff3; - first1 += 4; - first2 += 4; - } - /* Process last 0-3 pixels. Not needed for standard vector lengths. */ - while (first1 < last1) { - diff0 = fabs(*first1++ - *first2++); - dist = (diff0 > dist) ? diff0 : dist; - } - return dist; -} - - -template -double hist_intersection_kernel(Iterator1 first1, Iterator1 last1, Iterator2 first2) -{ - double kernel = 0; - Iterator1 lastgroup = last1 - 3; - double min0, min1, min2, min3; - - /* Process 4 items with each loop for efficiency. */ - while (first1 < lastgroup) { - min0 = first1[0] < first2[0] ? first1[0] : first2[0]; - min1 = first1[1] < first2[1] ? first1[1] : first2[1]; - min2 = first1[2] < first2[2] ? first1[2] : first2[2]; - min3 = first1[3] < first2[3] ? first1[3] : first2[3]; - kernel += min0 + min1 + min2 + min3; - first1 += 4; - first2 += 4; - } - /* Process last 0-3 pixels. Not needed for standard vector lengths. */ - while (first1 < last1) { - min0 = first1[0] < first2[0] ? first1[0] : first2[0]; - kernel += min0; - first1++; - first2++; - } - return kernel; -} - -template -double hist_intersection_dist_sq(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) -{ - double dist_sq = acc - 2 * hist_intersection_kernel(first1, last1, first2); - while (first1 < last1) { - dist_sq += *first1 + *first2; - first1++; - first2++; - } - return dist_sq; -} - - -// Hellinger distance -template -double hellinger_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) -{ - double distsq = acc; - double diff0, diff1, diff2, diff3; - Iterator1 lastgroup = last1 - 3; - - /* Process 4 items with each loop for efficiency. */ - while (first1 < lastgroup) { - diff0 = sqrt(first1[0]) - sqrt(first2[0]); - diff1 = sqrt(first1[1]) - sqrt(first2[1]); - diff2 = sqrt(first1[2]) - sqrt(first2[2]); - diff3 = sqrt(first1[3]) - sqrt(first2[3]); - distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; - first1 += 4; - first2 += 4; - } - /* Process last 0-3 pixels. Not needed for standard vector lengths. */ - while (first1 < last1) { - diff0 = sqrt(*first1++) - sqrt(*first2++); - distsq += diff0 * diff0; - } - return distsq; -} - - -// chi-dsquare distance -template -double chi_square_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) -{ - double dist = acc; - - while (first1 < last1) { - double sum = *first1 + *first2; - if (sum > 0) { - double diff = *first1 - *first2; - dist += diff * diff / sum; - } - first1++; - first2++; - } - return dist; -} - - -// Kullback–Leibler divergence (NOT SYMMETRIC) -template -double kl_divergence(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) -{ - double div = acc; - - while (first1 < last1) { - if (*first2 != 0) { - double ratio = *first1 / *first2; - if (ratio > 0) { - div += *first1 * log(ratio); - } - } - first1++; - first2++; - } - return div; -} - - - - -CV_EXPORTS flann_distance_t flann_distance_type(); /** - * Custom distance function. The distance computed is dependent on the value - * of the 'flann_distance_type' global variable. - * - * If the last argument 'acc' is passed, the result is accumulated to the value - * of this argument. + * Hamming distance functor (pop count between two binary vectors, i.e. xor them and count the number of bits set) + * That code was taken from brief.cpp in OpenCV */ -template -double custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) +template +struct Hamming { - switch (flann_distance_type()) { - case FLANN_DIST_EUCLIDEAN: - return euclidean_dist(first1, last1, first2, acc); - case FLANN_DIST_MANHATTAN: - return manhattan_dist(first1, last1, first2, acc); - case FLANN_DIST_MINKOWSKI: - return minkowski_dist(first1, last1, first2, acc); - case FLANN_DIST_MAX: - return max_dist(first1, last1, first2, acc); - case FLANN_DIST_HIST_INTERSECT: - return hist_intersection_dist_sq(first1, last1, first2, acc); - case FLANN_DIST_HELLINGER: - return hellinger_dist(first1, last1, first2, acc); - case FLANN_DIST_CS: - return chi_square_dist(first1, last1, first2, acc); - case FLANN_DIST_KL: - return kl_divergence(first1, last1, first2, acc); - default: - return euclidean_dist(first1, last1, first2, acc); - } -} + typedef False is_kdtree_distance; + typedef False is_vector_space_distance; + + + typedef T ElementType; + typedef int ResultType; + + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const + { + ResultType result = 0; +#if __GNUC__ +#if ANDROID && HAVE_NEON + static uint64_t features = android_getCpuFeatures(); + if ((features& ANDROID_CPU_ARM_FEATURE_NEON)) { + for (size_t i = 0; i < size; i += 16) { + uint8x16_t A_vec = vld1q_u8 (a + i); + uint8x16_t B_vec = vld1q_u8 (b + i); + //uint8x16_t veorq_u8 (uint8x16_t, uint8x16_t) + uint8x16_t AxorB = veorq_u8 (A_vec, B_vec); + + uint8x16_t bitsSet += vcntq_u8 (AxorB); + //uint16x8_t vpadalq_u8 (uint16x8_t, uint8x16_t) + uint16x8_t bitSet8 = vpaddlq_u8 (bitsSet); + uint32x4_t bitSet4 = vpaddlq_u16 (bitSet8); + + uint64x2_t bitSet2 = vpaddlq_u32 (bitSet4); + result += vgetq_lane_u64 (bitSet2,0); + result += vgetq_lane_u64 (bitSet2,1); + } + } + else +#endif + //for portability just use unsigned long -- and use the __builtin_popcountll (see docs for __builtin_popcountll) + typedef unsigned long long pop_t; + const size_t modulo = size % sizeof(pop_t); + const pop_t* a2 = reinterpret_cast (a); + const pop_t* b2 = reinterpret_cast (b); + const pop_t* a2_end = a2 + (size / sizeof(pop_t)); + + for (; a2 != a2_end; ++a2, ++b2) result += __builtin_popcountll((*a2) ^ (*b2)); + + if (modulo) { + //in the case where size is not dividable by sizeof(size_t) + //need to mask off the bits at the end + pop_t a_final = 0, b_final = 0; + memcpy(&a_final, a2, modulo); + memcpy(&b_final, b2, modulo); + result += __builtin_popcountll(a_final ^ b_final); + } +#else + HammingLUT lut; + result = lut(reinterpret_cast (a), + reinterpret_cast (b), size * sizeof(pop_t)); +#endif + return result; + } +}; + +template +struct Hamming2 +{ + typedef False is_kdtree_distance; + typedef False is_vector_space_distance; + + typedef T ElementType; + typedef int ResultType; + + /** This is popcount_3() from: + * http://en.wikipedia.org/wiki/Hamming_weight */ + unsigned int popcnt32(uint32_t n) const + { + n -= ((n >> 1) & 0x55555555); + n = (n & 0x33333333) + ((n >> 2) & 0x33333333); + return (((n + (n >> 4))& 0xF0F0F0F)* 0x1010101) >> 24; + } + +#ifdef FLANN_PLATFORM_64_BIT + unsigned int popcnt64(uint64_t n) const + { + n -= ((n >> 1) & 0x5555555555555555); + n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333); + return (((n + (n >> 4))& 0x0f0f0f0f0f0f0f0f)* 0x0101010101010101) >> 56; + } +#endif + + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const + { +#ifdef FLANN_PLATFORM_64_BIT + const uint64_t* pa = reinterpret_cast(a); + const uint64_t* pb = reinterpret_cast(b); + ResultType result = 0; + size /= (sizeof(uint64_t)/sizeof(unsigned char)); + for(size_t i = 0; i < size; ++i ) { + result += popcnt64(*pa ^ *pb); + ++pa; + ++pb; + } +#else + const uint32_t* pa = reinterpret_cast(a); + const uint32_t* pb = reinterpret_cast(b); + ResultType result = 0; + size /= (sizeof(uint32_t)/sizeof(unsigned char)); + for(size_t i = 0; i < size; ++i ) { + result += popcnt32(*pa ^ *pb); + ++pa; + ++pb; + } +#endif + return result; + } +}; + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct HistIntersectionDistance +{ + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the histogram intersection distance + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + ResultType min0, min1, min2, min3; + Iterator1 last = a + size; + Iterator1 lastgroup = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + min0 = (ResultType)(a[0] < b[0] ? a[0] : b[0]); + min1 = (ResultType)(a[1] < b[1] ? a[1] : b[1]); + min2 = (ResultType)(a[2] < b[2] ? a[2] : b[2]); + min3 = (ResultType)(a[3] < b[3] ? a[3] : b[3]); + result += min0 + min1 + min2 + min3; + a += 4; + b += 4; + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 pixels. Not needed for standard vector lengths. */ + while (a < last) { + min0 = (ResultType)(*a < *b ? *a : *b); + result += min0; + } + return result; + } + + /** + * Partial distance, used by the kd-tree. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + return a +struct HellingerDistance +{ + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the histogram intersection distance + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType /*worst_dist*/ = -1) const + { + ResultType result = ResultType(); + ResultType diff0, diff1, diff2, diff3; + Iterator1 last = a + size; + Iterator1 lastgroup = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + diff0 = sqrt(static_cast(a[0])) - sqrt(static_cast(b[0])); + diff1 = sqrt(static_cast(a[1])) - sqrt(static_cast(b[1])); + diff2 = sqrt(static_cast(a[2])) - sqrt(static_cast(b[2])); + diff3 = sqrt(static_cast(a[3])) - sqrt(static_cast(b[3])); + result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; + a += 4; + b += 4; + } + while (a < last) { + diff0 = sqrt(static_cast(*a++)) - sqrt(static_cast(*b++)); + result += diff0 * diff0; + } + return result; + } + + /** + * Partial distance, used by the kd-tree. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + return sqrt(static_cast(a)) - sqrt(static_cast(b)); + } +}; + + +template +struct ChiSquareDistance +{ + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the chi-square distance + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + ResultType sum, diff; + Iterator1 last = a + size; + + while (a < last) { + sum = (ResultType)(*a + *b); + if (sum>0) { + diff = (ResultType)(*a - *b); + result += diff*diff/sum; + } + ++a; + ++b; + + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + return result; + } + + /** + * Partial distance, used by the kd-tree. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + ResultType result = ResultType(); + ResultType sum, diff; + + sum = (ResultType)(a+b); + if (sum>0) { + diff = (ResultType)(a-b); + result = diff*diff/sum; + } + return result; + } +}; + + +template +struct KL_Divergence +{ + typedef True is_kdtree_distance; + typedef True is_vector_space_distance; + + typedef T ElementType; + typedef typename Accumulator::Type ResultType; + + /** + * Compute the Kullback–Leibler divergence + */ + template + ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const + { + ResultType result = ResultType(); + Iterator1 last = a + size; + + while (a < last) { + if (* a != 0) { + ResultType ratio = (ResultType)(*a / *b); + if (ratio>0) { + result += *a * log(ratio); + } + } + ++a; + ++b; + + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + return result; + } + + /** + * Partial distance, used by the kd-tree. + */ + template + inline ResultType accum_dist(const U& a, const V& b, int) const + { + ResultType result = ResultType(); + ResultType ratio = (ResultType)(a / b); + if (ratio>0) { + result = a * log(ratio); + } + return result; + } +}; + + /* * This is a "zero iterator". It basically behaves like a zero filled @@ -333,28 +808,36 @@ double custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double a * zero-filled array. */ template -struct ZeroIterator { +struct ZeroIterator +{ - T operator*() { - return 0; - } + T operator*() + { + return 0; + } - T operator[](int) { - return 0; - } + T operator[](int) + { + return 0; + } - ZeroIterator& operator ++(int) { - return *this; - } + const ZeroIterator& operator ++() + { + return *this; + } - ZeroIterator& operator+=(int) { - return *this; - } + ZeroIterator operator ++(int) + { + return *this; + } + + ZeroIterator& operator+=(int) + { + return *this; + } }; -CV_EXPORTS ZeroIterator& zero(); +} -} // namespace cvflann - -#endif //_OPENCV_DIST_H_ +#endif //OPENCV_FLANN_DIST_H_ diff --git a/modules/flann/include/opencv2/flann/dummy.h b/modules/flann/include/opencv2/flann/dummy.h new file mode 100644 index 0000000000..26bd3fa5dd --- /dev/null +++ b/modules/flann/include/opencv2/flann/dummy.h @@ -0,0 +1,16 @@ + +#ifndef OPENCV_FLANN_DUMMY_H_ +#define OPENCV_FLANN_DUMMY_H_ + +namespace cvflann +{ + +#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined CVAPI_EXPORTS +__declspec(dllexport) +#endif +void dummyfunc(); + +} + + +#endif /* OPENCV_FLANN_DUMMY_H_ */ diff --git a/modules/flann/include/opencv2/flann/dynamic_bitset.h b/modules/flann/include/opencv2/flann/dynamic_bitset.h new file mode 100644 index 0000000000..e88cfaa167 --- /dev/null +++ b/modules/flann/include/opencv2/flann/dynamic_bitset.h @@ -0,0 +1,152 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +/*********************************************************************** + * Author: Vincent Rabaud + *************************************************************************/ + +#ifndef OPENCV_FLANN_DYNAMIC_BITSET_H_ +#define OPENCV_FLANN_DYNAMIC_BITSET_H_ + +//#define FLANN_USE_BOOST 1 +#if FLANN_USE_BOOST +#include +typedef boost::dynamic_bitset<> DynamicBitset; +#else + +#include + +#include "dist.h" + +/** Class re-implementing the boost version of it + * This helps not depending on boost, it also does not do the bound checks + * and has a way to reset a block for speed + */ +class DynamicBitset +{ +public: + /** @param default constructor + */ + DynamicBitset() + { + } + + /** @param only constructor we use in our code + * @param the size of the bitset (in bits) + */ + DynamicBitset(size_t size) + { + resize(size); + reset(); + } + + /** Sets all the bits to 0 + */ + void clear() + { + std::fill(bitset_.begin(), bitset_.end(), 0); + } + + /** @brief checks if the bitset is empty + * @return true if the bitset is empty + */ + bool empty() const + { + return bitset_.empty(); + } + + /** @param set all the bits to 0 + */ + void reset() + { + std::fill(bitset_.begin(), bitset_.end(), 0); + } + + /** @brief set one bit to 0 + * @param + */ + void reset(size_t index) + { + bitset_[index / cell_bit_size_] &= ~(size_t(1) << (index % cell_bit_size_)); + } + + /** @brief sets a specific bit to 0, and more bits too + * This function is useful when resetting a given set of bits so that the + * whole bitset ends up being 0: if that's the case, we don't care about setting + * other bits to 0 + * @param + */ + void reset_block(size_t index) + { + bitset_[index / cell_bit_size_] = 0; + } + + /** @param resize the bitset so that it contains at least size bits + * @param size + */ + void resize(size_t size) + { + size_ = size; + bitset_.resize(size / cell_bit_size_ + 1); + } + + /** @param set a bit to true + * @param index the index of the bit to set to 1 + */ + void set(size_t index) + { + bitset_[index / cell_bit_size_] |= size_t(1) << (index % cell_bit_size_); + } + + /** @param gives the number of contained bits + */ + size_t size() const + { + return size_; + } + + /** @param check if a bit is set + * @param index the index of the bit to check + * @return true if the bit is set + */ + bool test(size_t index) const + { + return (bitset_[index / cell_bit_size_] & (size_t(1) << (index % cell_bit_size_))) != 0; + } + +private: + std::vector bitset_; + size_t size_; + static const unsigned int cell_bit_size_ = CHAR_BIT * sizeof(size_t); +}; + +#endif + +#endif // OPENCV_FLANN_DYNAMIC_BITSET_H_ diff --git a/modules/flann/include/opencv2/flann/flann.hpp b/modules/flann/include/opencv2/flann/flann.hpp index 642b17be66..988988f286 100644 --- a/modules/flann/include/opencv2/flann/flann.hpp +++ b/modules/flann/include/opencv2/flann/flann.hpp @@ -45,7 +45,17 @@ #ifdef __cplusplus +#include "opencv2/core/types_c.h" +#include "opencv2/core/core.hpp" #include "opencv2/flann/flann_base.hpp" +#include "opencv2/flann/miniflann.hpp" + +namespace cvflann +{ + CV_EXPORTS flann_distance_t flann_distance_type(); + FLANN_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order); +} + namespace cv { @@ -61,132 +71,345 @@ template <> struct CvType { static int type() { return CV_32S; } }; template <> struct CvType { static int type() { return CV_32F; } }; template <> struct CvType { static int type() { return CV_64F; } }; - -using ::cvflann::IndexParams; -using ::cvflann::LinearIndexParams; -using ::cvflann::KDTreeIndexParams; -using ::cvflann::KMeansIndexParams; -using ::cvflann::CompositeIndexParams; -using ::cvflann::AutotunedIndexParams; -using ::cvflann::SavedIndexParams; -using ::cvflann::SearchParams; +// bring the flann parameters into this namespace +using ::cvflann::get_param; +using ::cvflann::print_params; + +// bring the flann distances into this namespace +using ::cvflann::L2_Simple; +using ::cvflann::L2; +using ::cvflann::L1; +using ::cvflann::MinkowskiDistance; +using ::cvflann::MaxDistance; +using ::cvflann::HammingLUT; +using ::cvflann::Hamming; +using ::cvflann::Hamming2; +using ::cvflann::HistIntersectionDistance; +using ::cvflann::HellingerDistance; +using ::cvflann::ChiSquareDistance; +using ::cvflann::KL_Divergence; -template -class CV_EXPORTS Index_ { - ::cvflann::Index* nnIndex; +template +class GenericIndex +{ public: - Index_(const Mat& features, const IndexParams& params); + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + + GenericIndex(const Mat& features, const ::cvflann::IndexParams& params, Distance distance = Distance()); + + ~GenericIndex(); + + void knnSearch(const vector& query, vector& indices, + vector& dists, int knn, const ::cvflann::SearchParams& params); + void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); + + int radiusSearch(const vector& query, vector& indices, + vector& dists, DistanceType radius, const ::cvflann::SearchParams& params); + int radiusSearch(const Mat& query, Mat& indices, Mat& dists, + DistanceType radius, const ::cvflann::SearchParams& params); + + void save(std::string filename) { nnIndex->save(filename); } + + int veclen() const { return nnIndex->veclen(); } + + int size() const { return nnIndex->size(); } + + ::cvflann::IndexParams getParameters() { return nnIndex->getParameters(); } + + FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); } + +private: + ::cvflann::Index* nnIndex; +}; + + +#define FLANN_DISTANCE_CHECK \ + if ( ::cvflann::flann_distance_type() != cvflann::FLANN_DIST_L2) { \ + printf("[WARNING] You are using cv::flann::Index (or cv::flann::GenericIndex) and have also changed "\ + "the distance using cvflann::set_distance_type. This is no longer working as expected "\ + "(cv::flann::Index always uses L2). You should create the index templated on the distance, "\ + "for example for L1 distance use: GenericIndex< L1 > \n"); \ + } + + +template +GenericIndex::GenericIndex(const Mat& dataset, const ::cvflann::IndexParams& params, Distance distance) +{ + CV_Assert(dataset.type() == CvType::type()); + CV_Assert(dataset.isContinuous()); + ::cvflann::Matrix m_dataset((ElementType*)dataset.ptr(0), dataset.rows, dataset.cols); + + nnIndex = new ::cvflann::Index(m_dataset, params, distance); + + FLANN_DISTANCE_CHECK + + nnIndex->buildIndex(); +} + +template +GenericIndex::~GenericIndex() +{ + delete nnIndex; +} + +template +void GenericIndex::knnSearch(const vector& query, vector& indices, vector& dists, int knn, const ::cvflann::SearchParams& searchParams) +{ + ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); + ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); + ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); + + FLANN_DISTANCE_CHECK + + nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams); +} + + +template +void GenericIndex::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams) +{ + CV_Assert(queries.type() == CvType::type()); + CV_Assert(queries.isContinuous()); + ::cvflann::Matrix m_queries((ElementType*)queries.ptr(0), queries.rows, queries.cols); + + CV_Assert(indices.type() == CV_32S); + CV_Assert(indices.isContinuous()); + ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); + + CV_Assert(dists.type() == CvType::type()); + CV_Assert(dists.isContinuous()); + ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); + + FLANN_DISTANCE_CHECK + + nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); +} + +template +int GenericIndex::radiusSearch(const vector& query, vector& indices, vector& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) +{ + ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); + ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); + ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); + + FLANN_DISTANCE_CHECK + + return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); +} + +template +int GenericIndex::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) +{ + CV_Assert(query.type() == CvType::type()); + CV_Assert(query.isContinuous()); + ::cvflann::Matrix m_query((ElementType*)query.ptr(0), query.rows, query.cols); + + CV_Assert(indices.type() == CV_32S); + CV_Assert(indices.isContinuous()); + ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); + + CV_Assert(dists.type() == CvType::type()); + CV_Assert(dists.isContinuous()); + ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); + + FLANN_DISTANCE_CHECK + + return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); +} + +/** + * @deprecated Use GenericIndex class instead + */ +template +class FLANN_DEPRECATED Index_ { +public: + typedef typename L2::ElementType ElementType; + typedef typename L2::ResultType DistanceType; + + Index_(const Mat& features, const ::cvflann::IndexParams& params); ~Index_(); - void knnSearch(const vector& query, vector& indices, vector& dists, int knn, const SearchParams& params); - void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params); + void knnSearch(const vector& query, vector& indices, vector& dists, int knn, const ::cvflann::SearchParams& params); + void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); - int radiusSearch(const vector& query, vector& indices, vector& dists, float radius, const SearchParams& params); - int radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& params); + int radiusSearch(const vector& query, vector& indices, vector& dists, DistanceType radius, const ::cvflann::SearchParams& params); + int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params); - void save(std::string filename) { nnIndex->save(filename); } + void save(std::string filename) + { + if (nnIndex_L1) nnIndex_L1->save(filename); + if (nnIndex_L2) nnIndex_L2->save(filename); + } - int veclen() const { return nnIndex->veclen(); } + int veclen() const + { + if (nnIndex_L1) return nnIndex_L1->veclen(); + if (nnIndex_L2) return nnIndex_L2->veclen(); + } - int size() const { return nnIndex->size(); } + int size() const + { + if (nnIndex_L1) return nnIndex_L1->size(); + if (nnIndex_L2) return nnIndex_L2->size(); + } - const IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); } + ::cvflann::IndexParams getParameters() + { + if (nnIndex_L1) return nnIndex_L1->getParameters(); + if (nnIndex_L2) return nnIndex_L2->getParameters(); + + } + FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() + { + if (nnIndex_L1) return nnIndex_L1->getIndexParameters(); + if (nnIndex_L2) return nnIndex_L2->getIndexParameters(); + } + +private: + // providing backwards compatibility for L2 and L1 distances (most common) + ::cvflann::Index< L2 >* nnIndex_L2; + ::cvflann::Index< L1 >* nnIndex_L1; }; template -Index_::Index_(const Mat& dataset, const IndexParams& params) +Index_::Index_(const Mat& dataset, const ::cvflann::IndexParams& params) { - CV_Assert(dataset.type() == CvType::type()); - CV_Assert(dataset.isContinuous()); - ::cvflann::Matrix m_dataset((T*)dataset.ptr(0), dataset.rows, dataset.cols); + printf("[WARNING] The cv::flann::Index_ class is deperecated, use cv::flann::GenericIndex instead\n"); - nnIndex = new ::cvflann::Index(m_dataset, params); - nnIndex->buildIndex(); + CV_Assert(dataset.type() == CvType::type()); + CV_Assert(dataset.isContinuous()); + ::cvflann::Matrix m_dataset((ElementType*)dataset.ptr(0), dataset.rows, dataset.cols); + + if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) { + nnIndex_L1 = NULL; + nnIndex_L2 = new ::cvflann::Index< L2 >(m_dataset, params); + } + else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) { + nnIndex_L1 = new ::cvflann::Index< L1 >(m_dataset, params); + nnIndex_L2 = NULL; + } + else { + printf("[ERROR] cv::flann::Index_ only provides backwards compatibility for the L1 and L2 distances. " + "For other distance types you must use cv::flann::GenericIndex\n"); + CV_Assert(0); + } + if (nnIndex_L1) nnIndex_L1->buildIndex(); + if (nnIndex_L2) nnIndex_L2->buildIndex(); } template Index_::~Index_() { - delete nnIndex; + if (nnIndex_L1) delete nnIndex_L1; + if (nnIndex_L2) delete nnIndex_L2; } template -void Index_::knnSearch(const vector& query, vector& indices, vector& dists, int knn, const SearchParams& searchParams) +void Index_::knnSearch(const vector& query, vector& indices, vector& dists, int knn, const ::cvflann::SearchParams& searchParams) { - ::cvflann::Matrix m_query((T*)&query[0], 1, (int)query.size()); - ::cvflann::Matrix m_indices(&indices[0], 1, (int)indices.size()); - ::cvflann::Matrix m_dists(&dists[0], 1, (int)dists.size()); + ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); + ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); + ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); - nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams); + if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams); + if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams); } template -void Index_::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& searchParams) +void Index_::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams) { - CV_Assert(queries.type() == CvType::type()); + CV_Assert(queries.type() == CvType::type()); CV_Assert(queries.isContinuous()); - ::cvflann::Matrix m_queries((T*)queries.ptr(0), queries.rows, queries.cols); + ::cvflann::Matrix m_queries((ElementType*)queries.ptr(0), queries.rows, queries.cols); CV_Assert(indices.type() == CV_32S); CV_Assert(indices.isContinuous()); ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); - CV_Assert(dists.type() == CV_32F); + CV_Assert(dists.type() == CvType::type()); CV_Assert(dists.isContinuous()); - ::cvflann::Matrix m_dists((float*)dists.ptr(0), dists.rows, dists.cols); - - nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); + ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); + + if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); + if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams); } template -int Index_::radiusSearch(const vector& query, vector& indices, vector& dists, float radius, const SearchParams& searchParams) +int Index_::radiusSearch(const vector& query, vector& indices, vector& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) { - ::cvflann::Matrix m_query((T*)&query[0], 1, (int)query.size()); - ::cvflann::Matrix m_indices(&indices[0], 1, (int)indices.size()); - ::cvflann::Matrix m_dists(&dists[0], 1, (int)dists.size()); + ::cvflann::Matrix m_query((ElementType*)&query[0], 1, query.size()); + ::cvflann::Matrix m_indices(&indices[0], 1, indices.size()); + ::cvflann::Matrix m_dists(&dists[0], 1, dists.size()); - return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); } template -int Index_::radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& searchParams) +int Index_::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams) { - CV_Assert(query.type() == CvType::type()); + CV_Assert(query.type() == CvType::type()); CV_Assert(query.isContinuous()); - ::cvflann::Matrix m_query((T*)query.ptr(0), query.rows, query.cols); + ::cvflann::Matrix m_query((ElementType*)query.ptr(0), query.rows, query.cols); CV_Assert(indices.type() == CV_32S); CV_Assert(indices.isContinuous()); ::cvflann::Matrix m_indices((int*)indices.ptr(0), indices.rows, indices.cols); - CV_Assert(dists.type() == CV_32F); + CV_Assert(dists.type() == CvType::type()); CV_Assert(dists.isContinuous()); - ::cvflann::Matrix m_dists((float*)dists.ptr(0), dists.rows, dists.cols); + ::cvflann::Matrix m_dists((DistanceType*)dists.ptr(0), dists.rows, dists.cols); - return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); + if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams); +} + + +template +int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::IndexParams& params, + Distance d = Distance()) +{ + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + + CV_Assert(features.type() == CvType::type()); + CV_Assert(features.isContinuous()); + ::cvflann::Matrix m_features((ElementType*)features.ptr(0), features.rows, features.cols); + + CV_Assert(centers.type() == CvType::type()); + CV_Assert(centers.isContinuous()); + ::cvflann::Matrix m_centers((DistanceType*)centers.ptr(0), centers.rows, centers.cols); + + return ::cvflann::hierarchicalClustering(m_features, m_centers, params, d); } -typedef Index_ Index; template -int hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params) +FLANN_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const ::cvflann::IndexParams& params) { - CV_Assert(features.type() == CvType::type()); - CV_Assert(features.isContinuous()); - ::cvflann::Matrix m_features((ELEM_TYPE*)features.ptr(0), features.rows, features.cols); - - CV_Assert(centers.type() == CvType::type()); - CV_Assert(centers.isContinuous()); - ::cvflann::Matrix m_centers((DIST_TYPE*)centers.ptr(0), centers.rows, centers.cols); - - return ::cvflann::hierarchicalClustering(m_features, m_centers, params); + printf("[WARNING] cv::flann::hierarchicalClustering is deprecated, use " + "cv::flann::hierarchicalClustering instead\n"); + + if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) { + return hierarchicalClustering< L2 >(features, centers, params); + } + else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) { + return hierarchicalClustering< L1 >(features, centers, params); + } + else { + printf("[ERROR] cv::flann::hierarchicalClustering only provides backwards " + "compatibility for the L1 and L2 distances. " + "For other distance types you must use cv::flann::hierarchicalClustering\n"); + CV_Assert(0); + } } } } // namespace cv::flann diff --git a/modules/flann/include/opencv2/flann/flann_base.hpp b/modules/flann/include/opencv2/flann/flann_base.hpp index 46143df267..04262622bc 100644 --- a/modules/flann/include/opencv2/flann/flann_base.hpp +++ b/modules/flann/include/opencv2/flann/flann_base.hpp @@ -28,232 +28,264 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_FLANN_BASE_HPP_ -#define _OPENCV_FLANN_BASE_HPP_ +#ifndef FLANN_BASE_HPP_ +#define FLANN_BASE_HPP_ #include #include #include #include -#include "opencv2/flann/general.h" -#include "opencv2/flann/matrix.h" -#include "opencv2/flann/result_set.h" -#include "opencv2/flann/index_testing.h" -#include "opencv2/flann/object_factory.h" -#include "opencv2/flann/saving.h" +#include "general.h" +#include "matrix.h" +#include "params.h" +#include "saving.h" -#include "opencv2/flann/all_indices.h" +#include "all_indices.h" namespace cvflann { - /** -Sets the log level used for all flann functions - -Params: - level = verbosity level -*/ -CV_EXPORTS void log_verbosity(int level); - - -/** - * Sets the distance type to use throughout FLANN. - * If distance type specified is MINKOWSKI, the second argument - * specifies which order the minkowski distance should have. + * Sets the log level used for all flann functions + * @param level Verbosity level */ -CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order); +inline void log_verbosity(int level) +{ + if (level >= 0) { + Logger::setLevel(level); + } +} - -struct CV_EXPORTS SavedIndexParams : public IndexParams { - SavedIndexParams(std::string filename_) : IndexParams(FLANN_INDEX_SAVED), filename(filename_) {} - - std::string filename; // filename of the stored index - - void print() const - { - logger().info("Index type: %d\n",(int)algorithm); - logger().info("Filename: %s\n", filename.c_str()); - } +/** + * (Deprecated) Index parameters for creating a saved index. + */ +struct SavedIndexParams : public IndexParams +{ + SavedIndexParams(std::string filename) + { + (* this)["algorithm"] = FLANN_INDEX_SAVED; + (*this)["filename"] = filename; + } }; -template -class CV_EXPORTS Index { - NNIndex* nnIndex; - bool built; +template +NNIndex* load_saved_index(const Matrix& dataset, const std::string& filename, Distance distance) +{ + typedef typename Distance::ElementType ElementType; + + FILE* fin = fopen(filename.c_str(), "rb"); + if (fin == NULL) { + return NULL; + } + IndexHeader header = load_header(fin); + if (header.data_type != Datatype::type()) { + throw FLANNException("Datatype of saved index is different than of the one to be created."); + } + if ((size_t(header.rows) != dataset.rows)||(size_t(header.cols) != dataset.cols)) { + throw FLANNException("The index saved belongs to a different dataset"); + } + + IndexParams params; + params["algorithm"] = header.index_type; + NNIndex* nnIndex = create_index_by_type(dataset, params, distance); + nnIndex->loadIndex(fin); + fclose(fin); + + return nnIndex; +} + + +template +class Index : public NNIndex +{ public: - Index(const Matrix& features, const IndexParams& params); + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; - ~Index(); + Index(const Matrix& features, const IndexParams& params, Distance distance = Distance() ) + : index_params_(params) + { + flann_algorithm_t index_type = get_param(params,"algorithm"); + loaded_ = false; - void buildIndex(); + if (index_type == FLANN_INDEX_SAVED) { + nnIndex_ = load_saved_index(features, get_param(params,"filename"), distance); + loaded_ = true; + } + else { + nnIndex_ = create_index_by_type(features, params, distance); + } + } - void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params); + ~Index() + { + delete nnIndex_; + } - int radiusSearch(const Matrix& query, Matrix& indices, Matrix& dists, float radius, const SearchParams& params); + /** + * Builds the index. + */ + void buildIndex() + { + if (!loaded_) { + nnIndex_->buildIndex(); + } + } - void save(std::string filename); + void save(std::string filename) + { + FILE* fout = fopen(filename.c_str(), "wb"); + if (fout == NULL) { + throw FLANNException("Cannot open file"); + } + save_header(fout, *nnIndex_); + saveIndex(fout); + fclose(fout); + } - int veclen() const; + /** + * \brief Saves the index to a stream + * \param stream The stream to save the index to + */ + virtual void saveIndex(FILE* stream) + { + nnIndex_->saveIndex(stream); + } - int size() const; + /** + * \brief Loads the index from a stream + * \param stream The stream from which the index is loaded + */ + virtual void loadIndex(FILE* stream) + { + nnIndex_->loadIndex(stream); + } - NNIndex* getIndex() { return nnIndex; } + /** + * \returns number of features in this index. + */ + size_t veclen() const + { + return nnIndex_->veclen(); + } - const IndexParams* getIndexParameters() { return nnIndex->getParameters(); } + /** + * \returns The dimensionality of the features in this index. + */ + size_t size() const + { + return nnIndex_->size(); + } + + /** + * \returns The index type (kdtree, kmeans,...) + */ + flann_algorithm_t getType() const + { + return nnIndex_->getType(); + } + + /** + * \returns The amount of memory (in bytes) used by the index. + */ + virtual int usedMemory() const + { + return nnIndex_->usedMemory(); + } + + + /** + * \returns The index parameters + */ + IndexParams getParameters() const + { + return nnIndex_->getParameters(); + } + + /** + * \brief Perform k-nearest neighbor search + * \param[in] queries The query points for which to find the nearest neighbors + * \param[out] indices The indices of the nearest neighbors found + * \param[out] dists Distances to the nearest neighbors found + * \param[in] knn Number of nearest neighbors to return + * \param[in] params Search parameters + */ + void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + { + nnIndex_->knnSearch(queries, indices, dists, knn, params); + } + + /** + * \brief Perform radius search + * \param[in] query The query point + * \param[out] indices The indinces of the neighbors found within the given radius + * \param[out] dists The distances to the nearest neighbors found + * \param[in] radius The radius used for search + * \param[in] params Search parameters + * \returns Number of neighbors found + */ + int radiusSearch(const Matrix& query, Matrix& indices, Matrix& dists, float radius, const SearchParams& params) + { + return nnIndex_->radiusSearch(query, indices, dists, radius, params); + } + + /** + * \brief Method that searches for nearest-neighbours + */ + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + { + nnIndex_->findNeighbors(result, vec, searchParams); + } + + /** + * \brief Returns actual index + */ + FLANN_DEPRECATED NNIndex* getIndex() + { + return nnIndex_; + } + + /** + * \brief Returns index parameters. + * \deprecated use getParameters() instead. + */ + FLANN_DEPRECATED const IndexParams* getIndexParameters() + { + return &index_params_; + } + +private: + /** Pointer to actual index class */ + NNIndex* nnIndex_; + /** Indices if the index was loaded from a file */ + bool loaded_; + /** Parameters passed to the index */ + IndexParams index_params_; }; - -template -NNIndex* load_saved_index(const Matrix& dataset, const std::string& filename) +/** + * Performs a hierarchical clustering of the points passed as argument and then takes a cut in the + * the clustering tree to return a flat clustering. + * @param[in] points Points to be clustered + * @param centers The computed cluster centres. Matrix should be preallocated and centers.rows is the + * number of clusters requested. + * @param params Clustering parameters (The same as for cvflann::KMeansIndex) + * @param d Distance to be used for clustering (eg: cvflann::L2) + * @return number of clusters computed (can be different than clusters.rows and is the highest number + * of the form (branching-1)*K+1 smaller than clusters.rows). + */ +template +int hierarchicalClustering(const Matrix& points, Matrix& centers, + const KMeansIndexParams& params, Distance d = Distance()) { - FILE* fin = fopen(filename.c_str(), "rb"); - if (fin==NULL) { - return NULL; - } - IndexHeader header = load_header(fin); - if (header.data_type!=Datatype::type()) { - throw FLANNException("Datatype of saved index is different than of the one to be created."); - } - if (size_t(header.rows)!=dataset.rows || size_t(header.cols)!=dataset.cols) { - throw FLANNException("The index saved belongs to a different dataset"); - } - - IndexParams* params = ParamsFactory_instance().create(header.index_type); - NNIndex* nnIndex = create_index_by_type(dataset, *params); - nnIndex->loadIndex(fin); - fclose(fin); - - return nnIndex; -} - - -template -Index::Index(const Matrix& dataset, const IndexParams& params) -{ - flann_algorithm_t index_type = params.getIndexType(); - built = false; - - if (index_type==FLANN_INDEX_SAVED) { - nnIndex = load_saved_index(dataset, ((const SavedIndexParams&)params).filename); - built = true; - } - else { - nnIndex = create_index_by_type(dataset, params); - } -} - -template -Index::~Index() -{ - delete nnIndex; -} - -template -void Index::buildIndex() -{ - if (!built) { - nnIndex->buildIndex(); - built = true; - } -} - -template -void Index::knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& searchParams) -{ - if (!built) { - throw FLANNException("You must build the index before searching."); - } - assert(queries.cols==nnIndex->veclen()); - assert(indices.rows>=queries.rows); - assert(dists.rows>=queries.rows); - assert(int(indices.cols)>=knn); - assert(int(dists.cols)>=knn); - - KNNResultSet resultSet(knn); - - for (size_t i = 0; i < queries.rows; i++) { - T* target = queries[i]; - resultSet.init(target, (int)queries.cols); - - nnIndex->findNeighbors(resultSet, target, searchParams); - - int* neighbors = resultSet.getNeighbors(); - float* distances = resultSet.getDistances(); - memcpy(indices[i], neighbors, knn*sizeof(int)); - memcpy(dists[i], distances, knn*sizeof(float)); - } -} - -template -int Index::radiusSearch(const Matrix& query, Matrix& indices, Matrix& dists, float radius, const SearchParams& searchParams) -{ - if (!built) { - throw FLANNException("You must build the index before searching."); - } - if (query.rows!=1) { - fprintf(stderr, "I can only search one feature at a time for range search\n"); - return -1; - } - assert(query.cols==nnIndex->veclen()); - - RadiusResultSet resultSet(radius); - resultSet.init(query.data, (int)query.cols); - nnIndex->findNeighbors(resultSet,query.data,searchParams); - - // TODO: optimise here - int* neighbors = resultSet.getNeighbors(); - float* distances = resultSet.getDistances(); - size_t count_nn = std::min(resultSet.size(), indices.cols); - - assert (dists.cols>=count_nn); - - for (size_t i=0;i -void Index::save(std::string filename) -{ - FILE* fout = fopen(filename.c_str(), "wb"); - if (fout==NULL) { - throw FLANNException("Cannot open file"); - } - save_header(fout, *nnIndex); - nnIndex->saveIndex(fout); - fclose(fout); -} - - -template -int Index::size() const -{ - return nnIndex->size(); -} - -template -int Index::veclen() const -{ - return nnIndex->veclen(); -} - - -template -int hierarchicalClustering(const Matrix& features, Matrix& centers, const KMeansIndexParams& params) -{ - KMeansIndex kmeans(features, params); - kmeans.buildIndex(); + KMeansIndex kmeans(points, params, d); + kmeans.buildIndex(); int clusterNum = kmeans.getClusterCenters(centers); - return clusterNum; + return clusterNum; } -} // namespace cvflann -#endif /* _OPENCV_FLANN_BASE_HPP_ */ +} +#endif /* FLANN_BASE_HPP_ */ diff --git a/modules/flann/include/opencv2/flann/general.h b/modules/flann/include/opencv2/flann/general.h index 880cc84b0c..87e7e2f288 100644 --- a/modules/flann/include/opencv2/flann/general.h +++ b/modules/flann/include/opencv2/flann/general.h @@ -28,119 +28,25 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_GENERAL_H_ -#define _OPENCV_GENERAL_H_ - -#ifdef __cplusplus +#ifndef OPENCV_FLANN_GENERAL_H_ +#define OPENCV_FLANN_GENERAL_H_ +#include "defines.h" #include #include -#include "opencv2/flann/object_factory.h" -#include "opencv2/flann/logger.h" -namespace cvflann { - -#undef ARRAY_LEN -#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0])) - -/* Nearest neighbour index algorithms */ -enum flann_algorithm_t { - FLANN_INDEX_LINEAR = 0, - FLANN_INDEX_KDTREE = 1, - FLANN_INDEX_KMEANS = 2, - FLANN_INDEX_COMPOSITE = 3, - FLANN_INDEX_SAVED = 254, - FLANN_INDEX_AUTOTUNED = 255 -}; - -enum flann_centers_init_t { - FLANN_CENTERS_RANDOM = 0, - FLANN_CENTERS_GONZALES = 1, - FLANN_CENTERS_KMEANSPP = 2 -}; - - -enum flann_distance_t { - FLANN_DIST_EUCLIDEAN = 1, - FLANN_DIST_L2 = 1, - FLANN_DIST_MANHATTAN = 2, - FLANN_DIST_L1 = 2, - FLANN_DIST_MINKOWSKI = 3, - FLANN_DIST_MAX = 4, - FLANN_DIST_HIST_INTERSECT = 5, - FLANN_DIST_HELLINGER = 6, - FLANN_DIST_CHI_SQUARE = 7, - FLANN_DIST_CS = 7, - FLANN_DIST_KULLBACK_LEIBLER = 8, - FLANN_DIST_KL = 8 -}; - -enum flann_datatype_t { - FLANN_INT8 = 0, - FLANN_INT16 = 1, - FLANN_INT32 = 2, - FLANN_INT64 = 3, - FLANN_UINT8 = 4, - FLANN_UINT16 = 5, - FLANN_UINT32 = 6, - FLANN_UINT64 = 7, - FLANN_FLOAT32 = 8, - FLANN_FLOAT64 = 9 -}; - -template -struct DistType +namespace cvflann { - typedef ELEM_TYPE type; -}; -template <> -struct DistType +class FLANNException : public std::runtime_error { - typedef float type; -}; - -template <> -struct DistType -{ - typedef float type; -}; - - -class FLANNException : public std::runtime_error { - public: - FLANNException(const char* message) : std::runtime_error(message) { } - - FLANNException(const std::string& message) : std::runtime_error(message) { } - }; - - -struct CV_EXPORTS IndexParams { -protected: - IndexParams(flann_algorithm_t algorithm_) : algorithm(algorithm_) {}; - public: - virtual ~IndexParams() {} - virtual flann_algorithm_t getIndexType() const { return algorithm; } + FLANNException(const char* message) : std::runtime_error(message) { } - virtual void print() const = 0; - - flann_algorithm_t algorithm; + FLANNException(const std::string& message) : std::runtime_error(message) { } }; +} -typedef ObjectFactory ParamsFactory; -CV_EXPORTS ParamsFactory& ParamsFactory_instance(); -struct CV_EXPORTS SearchParams { - SearchParams(int checks_ = 32) : - checks(checks_) {}; - - int checks; -}; - -} // namespace cvflann - -#endif - -#endif /* _OPENCV_GENERAL_H_ */ +#endif /* OPENCV_FLANN_GENERAL_H_ */ diff --git a/modules/flann/include/opencv2/flann/ground_truth.h b/modules/flann/include/opencv2/flann/ground_truth.h index cb213246e5..8f1c698a22 100644 --- a/modules/flann/include/opencv2/flann/ground_truth.h +++ b/modules/flann/include/opencv2/flann/ground_truth.h @@ -28,39 +28,41 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_GROUND_TRUTH_H_ -#define _OPENCV_GROUND_TRUTH_H_ +#ifndef OPENCV_FLANN_GROUND_TRUTH_H_ +#define OPENCV_FLANN_GROUND_TRUTH_H_ + +#include "dist.h" +#include "matrix.h" -#include "opencv2/flann/dist.h" -#include "opencv2/flann/matrix.h" namespace cvflann { -template -void find_nearest(const Matrix& dataset, T* query, int* matches, int nn, int skip = 0) +template +void find_nearest(const Matrix& dataset, typename Distance::ElementType* query, int* matches, int nn, + int skip = 0, Distance distance = Distance()) { + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; int n = nn + skip; - T* query_end = query + dataset.cols; + int* match = new int[n]; + DistanceType* dists = new DistanceType[n]; - long* match = new long[n]; - T* dists = new T[n]; - - dists[0] = (float)flann_dist(query, query_end, dataset[0]); + dists[0] = distance(dataset[0], query, dataset.cols); match[0] = 0; int dcnt = 1; - for (size_t i=1;i& dataset, T* query, int* matches, int nn, int } } - for (int i=0;i& dataset, T* query, int* matches, int nn, int } -template -void compute_ground_truth(const Matrix& dataset, const Matrix& testset, Matrix& matches, int skip=0) +template +void compute_ground_truth(const Matrix& dataset, const Matrix& testset, Matrix& matches, + int skip=0, Distance d = Distance()) { - for (size_t i=0;i(dataset, testset[i], matches[i], (int)matches.cols, skip, d); } } -} // namespace cvflann +} -#endif //_OPENCV_GROUND_TRUTH_H_ +#endif //OPENCV_FLANN_GROUND_TRUTH_H_ diff --git a/modules/flann/include/opencv2/flann/hdf5.h b/modules/flann/include/opencv2/flann/hdf5.h index 727d5a13ac..ff92434158 100644 --- a/modules/flann/include/opencv2/flann/hdf5.h +++ b/modules/flann/include/opencv2/flann/hdf5.h @@ -27,137 +27,207 @@ *************************************************************************/ -#ifndef _OPENCV_HDF5_H_ -#define _OPENCV_HDF5_H_ +#ifndef OPENCV_FLANN_HDF5_H_ +#define OPENCV_FLANN_HDF5_H_ -#include +#include -#include "opencv2/flann/matrix.h" +#include "matrix.h" +namespace cvflann +{ -#ifndef H5_NO_NAMESPACE - using namespace H5; +namespace +{ + +template +hid_t get_hdf5_type() +{ + throw FLANNException("Unsupported type for IO operations"); +} + +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_CHAR; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_UCHAR; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_SHORT; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_USHORT; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_INT; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_UINT; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_LONG; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_ULONG; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_FLOAT; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_DOUBLE; } +template<> +hid_t get_hdf5_type() { return H5T_NATIVE_LDOUBLE; } +} + + +#define CHECK_ERROR(x,y) if ((x)<0) throw FLANNException((y)); + +template +void save_to_file(const cvflann::Matrix& dataset, const std::string& filename, const std::string& name) +{ + +#if H5Eset_auto_vers == 2 + H5Eset_auto( H5E_DEFAULT, NULL, NULL ); +#else + H5Eset_auto( NULL, NULL ); #endif -namespace cvflann -{ + herr_t status; + hid_t file_id; + file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); + if (file_id < 0) { + file_id = H5Fcreate(filename.c_str(), H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); + } + CHECK_ERROR(file_id,"Error creating hdf5 file."); + hsize_t dimsf[2]; // dataset dimensions + dimsf[0] = dataset.rows; + dimsf[1] = dataset.cols; -namespace { + hid_t space_id = H5Screate_simple(2, dimsf, NULL); + hid_t memspace_id = H5Screate_simple(2, dimsf, NULL); -template -PredType get_hdf5_type() -{ - throw FLANNException("Unsupported type for IO operations"); -} + hid_t dataset_id; +#if H5Dcreate_vers == 2 + dataset_id = H5Dcreate2(file_id, name.c_str(), get_hdf5_type(), space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); +#else + dataset_id = H5Dcreate(file_id, name.c_str(), get_hdf5_type(), space_id, H5P_DEFAULT); +#endif -template<> PredType get_hdf5_type() { return PredType::NATIVE_CHAR; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_UCHAR; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_SHORT; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_USHORT; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_INT; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_UINT; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_LONG; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_ULONG; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_FLOAT; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_DOUBLE; } -template<> PredType get_hdf5_type() { return PredType::NATIVE_LDOUBLE; } + if (dataset_id<0) { +#if H5Dopen_vers == 2 + dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT); +#else + dataset_id = H5Dopen(file_id, name.c_str()); +#endif + } + CHECK_ERROR(dataset_id,"Error creating or opening dataset in file."); + + status = H5Dwrite(dataset_id, get_hdf5_type(), memspace_id, space_id, H5P_DEFAULT, dataset.data ); + CHECK_ERROR(status, "Error writing to dataset"); + + H5Sclose(memspace_id); + H5Sclose(space_id); + H5Dclose(dataset_id); + H5Fclose(file_id); } template -void save_to_file(const cvflann::Matrix& flann_dataset, const std::string& filename, const std::string& name) +void load_from_file(cvflann::Matrix& dataset, const std::string& filename, const std::string& name) { - // Try block to detect exceptions raised by any of the calls inside it - try - { - /* - * Turn off the auto-printing when failure occurs so that we can - * handle the errors appropriately - */ - Exception::dontPrint(); + herr_t status; + hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); + CHECK_ERROR(file_id,"Error opening hdf5 file."); - /* - * Create a new file using H5F_ACC_TRUNC access, - * default file creation properties, and default file - * access properties. - */ - H5File file( filename, H5F_ACC_TRUNC ); + hid_t dataset_id; +#if H5Dopen_vers == 2 + dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT); +#else + dataset_id = H5Dopen(file_id, name.c_str()); +#endif + CHECK_ERROR(dataset_id,"Error opening dataset in file."); - /* - * Define the size of the array and create the data space for fixed - * size dataset. - */ - hsize_t dimsf[2]; // dataset dimensions - dimsf[0] = flann_dataset.rows; - dimsf[1] = flann_dataset.cols; - DataSpace dataspace( 2, dimsf ); + hid_t space_id = H5Dget_space(dataset_id); - /* - * Create a new dataset within the file using defined dataspace and - * datatype and default dataset creation properties. - */ - DataSet dataset = file.createDataSet( name, get_hdf5_type(), dataspace ); + hsize_t dims_out[2]; + H5Sget_simple_extent_dims(space_id, dims_out, NULL); - /* - * Write the data to the dataset using default memory space, file - * space, and transfer properties. - */ - dataset.write( flann_dataset.data, get_hdf5_type() ); - } // end of try block - catch( H5::Exception& error ) - { - error.printError(); - throw FLANNException(error.getDetailMsg()); - } + dataset = cvflann::Matrix(new T[dims_out[0]*dims_out[1]], dims_out[0], dims_out[1]); + + status = H5Dread(dataset_id, get_hdf5_type(), H5S_ALL, H5S_ALL, H5P_DEFAULT, dataset[0]); + CHECK_ERROR(status, "Error reading dataset"); + + H5Sclose(space_id); + H5Dclose(dataset_id); + H5Fclose(file_id); } +#ifdef HAVE_MPI + +namespace mpi +{ +/** + * Loads a the hyperslice corresponding to this processor from a hdf5 file. + * @param flann_dataset Dataset where the data is loaded + * @param filename HDF5 file name + * @param name Name of dataset inside file + */ template -void load_from_file(cvflann::Matrix& flann_dataset, const std::string& filename, const std::string& name) +void load_from_file(cvflann::Matrix& dataset, const std::string& filename, const std::string& name) { - try - { - Exception::dontPrint(); + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; - H5File file( filename, H5F_ACC_RDONLY ); - DataSet dataset = file.openDataSet( name ); + int mpi_size, mpi_rank; + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); - /* - * Check the type used by the dataset matches - */ - if ( !(dataset.getDataType()==get_hdf5_type())) { - throw FLANNException("Dataset matrix type does not match the type to be read."); - } + herr_t status; - /* - * Get dataspace of the dataset. - */ - DataSpace dataspace = dataset.getSpace(); + hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_fapl_mpio(plist_id, comm, info); + hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, plist_id); + CHECK_ERROR(file_id,"Error opening hdf5 file."); + H5Pclose(plist_id); + hid_t dataset_id; +#if H5Dopen_vers == 2 + dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT); +#else + dataset_id = H5Dopen(file_id, name.c_str()); +#endif + CHECK_ERROR(dataset_id,"Error opening dataset in file."); - /* - * Get the dimension size of each dimension in the dataspace and - * display them. - */ - hsize_t dims_out[2]; - dataspace.getSimpleExtentDims( dims_out, NULL); - - flann_dataset.rows = dims_out[0]; - flann_dataset.cols = dims_out[1]; - flann_dataset.data = new T[flann_dataset.rows*flann_dataset.cols]; + hid_t space_id = H5Dget_space(dataset_id); + hsize_t dims[2]; + H5Sget_simple_extent_dims(space_id, dims, NULL); - dataset.read( flann_dataset.data, get_hdf5_type() ); - } // end of try block - catch( H5::Exception &error ) - { - error.printError(); - throw FLANNException(error.getDetailMsg()); - } + hsize_t count[2]; + hsize_t offset[2]; + + hsize_t item_cnt = dims[0]/mpi_size+(dims[0]%mpi_size==0 ? 0 : 1); + hsize_t cnt = (mpi_rank(), memspace_id, space_id, plist_id, dataset.data); + CHECK_ERROR(status, "Error reading dataset"); + + H5Pclose(plist_id); + H5Sclose(space_id); + H5Sclose(memspace_id); + H5Dclose(dataset_id); + H5Fclose(file_id); } +} +#endif // HAVE_MPI +} // namespace cvflann::mpi - -} // namespace cvflann - -#endif /* _OPENCV_HDF5_H_ */ +#endif /* OPENCV_FLANN_HDF5_H_ */ diff --git a/modules/flann/include/opencv2/flann/heap.h b/modules/flann/include/opencv2/flann/heap.h index 0e05451364..dc0a6f7712 100644 --- a/modules/flann/include/opencv2/flann/heap.h +++ b/modules/flann/include/opencv2/flann/heap.h @@ -28,11 +28,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_HEAP_H_ -#define _OPENCV_HEAP_H_ - +#ifndef OPENCV_FLANN_HEAP_H_ +#define OPENCV_FLANN_HEAP_H_ #include +#include namespace cvflann { @@ -43,166 +43,123 @@ namespace cvflann * The priority queue is implemented with a heap. A heap is a complete * (full) binary tree in which each parent is less than both of its * children, but the order of the children is unspecified. - * Note that a heap uses 1-based indexing to allow for power-of-2 - * location of parents and children. We ignore element 0 of Heap array. */ template -class Heap { +class Heap +{ - /** - * Storage array for the heap. - * Type T must be comparable. - */ - T* heap; + /** + * Storage array for the heap. + * Type T must be comparable. + */ + std::vector heap; int length; - /** - * Number of element in the heap - */ - int count; + /** + * Number of element in the heap + */ + int count; public: - /** - * Constructor. - * - * Params: - * size = heap size - */ + /** + * Constructor. + * + * Params: + * size = heap size + */ - Heap(int size) - { - length = size+1; - heap = new T[length]; // heap uses 1-based indexing - count = 0; - } + Heap(int size) + { + length = size; + heap.reserve(length); + count = 0; + } + /** + * + * Returns: heap size + */ + int size() + { + return count; + } - /** - * Destructor. - * - */ - ~Heap() - { - delete[] heap; - } + /** + * Tests if the heap is empty + * + * Returns: true is heap empty, false otherwise + */ + bool empty() + { + return size()==0; + } - /** - * - * Returns: heap size - */ - int size() - { - return count; - } + /** + * Clears the heap. + */ + void clear() + { + heap.clear(); + count = 0; + } - /** - * Tests if the heap is empty - * - * Returns: true is heap empty, false otherwise - */ - bool empty() - { - return size()==0; - } + struct CompareT + { + bool operator()(const T& t_1, const T& t_2) const + { + return t_2 < t_1; + } + }; - /** - * Clears the heap. - */ - void clear() - { - count = 0; - } + /** + * Insert a new element in the heap. + * + * We select the next empty leaf node, and then keep moving any larger + * parents down until the right location is found to store this element. + * + * Params: + * value = the new element to be inserted in the heap + */ + void insert(T value) + { + /* If heap is full, then return without adding this element. */ + if (count == length) { + return; + } - - /** - * Insert a new element in the heap. - * - * We select the next empty leaf node, and then keep moving any larger - * parents down until the right location is found to store this element. - * - * Params: - * value = the new element to be inserted in the heap - */ - void insert(T value) - { - /* If heap is full, then return without adding this element. */ - if (count == length-1) { - return; - } - - int loc = ++(count); /* Remember 1-based indexing. */ - - /* Keep moving parents down until a place is found for this node. */ - int par = loc / 2; /* Location of parent. */ - while (par > 0 && value < heap[par]) { - heap[loc] = heap[par]; /* Move parent down to loc. */ - loc = par; - par = loc / 2; - } - /* Insert the element at the determined location. */ - heap[loc] = value; - } + heap.push_back(value); + static CompareT compareT; + std::push_heap(heap.begin(), heap.end(), compareT); + ++count; + } - /** - * Returns the node of minimum value from the heap (top of the heap). - * - * Params: - * value = out parameter used to return the min element - * Returns: false if heap empty - */ - bool popMin(T& value) - { - if (count == 0) { - return false; - } + /** + * Returns the node of minimum value from the heap (top of the heap). + * + * Params: + * value = out parameter used to return the min element + * Returns: false if heap empty + */ + bool popMin(T& value) + { + if (count == 0) { + return false; + } - /* Switch first node with last. */ - std::swap(heap[1],heap[count]); - - count -= 1; - heapify(1); /* Move new node 1 to right position. */ - - value = heap[count + 1]; - return true; /* Return old last node. */ - } - - - /** - * Reorganizes the heap (a parent is smaller than its children) - * starting with a node. - * - * Params: - * parent = node form which to start heap reorganization. - */ - void heapify(int parent) - { - int minloc = parent; - - /* Check the left child */ - int left = 2 * parent; - if (left <= count && heap[left] < heap[parent]) { - minloc = left; - } - - /* Check the right child */ - int right = left + 1; - if (right <= count && heap[right] < heap[minloc]) { - minloc = right; - } - - /* If a child was smaller, than swap parent with it and Heapify. */ - if (minloc != parent) { - std::swap(heap[parent],heap[minloc]); - heapify(minloc); - } - } + value = heap[0]; + static CompareT compareT; + std::pop_heap(heap.begin(), heap.end(), compareT); + heap.pop_back(); + --count; + return true; /* Return old last node. */ + } }; -} // namespace cvflann +} -#endif //_OPENCV_HEAP_H_ +#endif //OPENCV_FLANN_HEAP_H_ diff --git a/modules/flann/include/opencv2/flann/hierarchical_clustering_index.h b/modules/flann/include/opencv2/flann/hierarchical_clustering_index.h new file mode 100644 index 0000000000..1ca1c10dce --- /dev/null +++ b/modules/flann/include/opencv2/flann/hierarchical_clustering_index.h @@ -0,0 +1,717 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2011 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2011 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +#ifndef OPENCV_FLANN_HIERARCHICAL_CLUSTERING_INDEX_H_ +#define OPENCV_FLANN_HIERARCHICAL_CLUSTERING_INDEX_H_ + +#include +#include +#include +#include +#include +#include + +#include "general.h" +#include "nn_index.h" +#include "dist.h" +#include "matrix.h" +#include "result_set.h" +#include "heap.h" +#include "allocator.h" +#include "random.h" +#include "saving.h" + + +namespace cvflann +{ + +struct HierarchicalClusteringIndexParams : public IndexParams +{ + HierarchicalClusteringIndexParams(int branching = 32, + flann_centers_init_t centers_init = FLANN_CENTERS_RANDOM, + int trees = 4, int leaf_size = 100) + { + (*this)["algorithm"] = FLANN_INDEX_HIERARCHICAL; + // The branching factor used in the hierarchical clustering + (*this)["branching"] = branching; + // Algorithm used for picking the initial cluster centers + (*this)["centers_init"] = centers_init; + // number of parallel trees to build + (*this)["trees"] = trees; + // maximum leaf size + (*this)["leaf_size"] = leaf_size; + } +}; + + +/** + * Hierarchical index + * + * Contains a tree constructed through a hierarchical clustering + * and other information for indexing a set of points for nearest-neighbour matching. + */ +template +class HierarchicalClusteringIndex : public NNIndex +{ +public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + +private: + + + typedef void (HierarchicalClusteringIndex::* centersAlgFunction)(int, int*, int, int*, int&); + + /** + * The function used for choosing the cluster centers. + */ + centersAlgFunction chooseCenters; + + + + /** + * Chooses the initial centers in the k-means clustering in a random manner. + * + * Params: + * k = number of centers + * vecs = the dataset of points + * indices = indices in the dataset + * indices_length = length of indices vector + * + */ + void chooseCentersRandom(int k, int* indices, int indices_length, int* centers, int& centers_length) + { + UniqueRandom r(indices_length); + + int index; + for (index=0; index=0 && rnd < n); + + centers[0] = indices[rnd]; + + int index; + for (index=1; indexbest_val) { + best_val = dist; + best_index = j; + } + } + if (best_index!=-1) { + centers[index] = indices[best_index]; + } + else { + break; + } + } + centers_length = index; + } + + + /** + * Chooses the initial centers in the k-means using the algorithm + * proposed in the KMeans++ paper: + * Arthur, David; Vassilvitskii, Sergei - k-means++: The Advantages of Careful Seeding + * + * Implementation of this function was converted from the one provided in Arthur's code. + * + * Params: + * k = number of centers + * vecs = the dataset of points + * indices = indices in the dataset + * Returns: + */ + void chooseCentersKMeanspp(int k, int* indices, int indices_length, int* centers, int& centers_length) + { + int n = indices_length; + + double currentPot = 0; + DistanceType* closestDistSq = new DistanceType[n]; + + // Choose one random center and set the closestDistSq values + int index = rand_int(n); + assert(index >=0 && index < n); + centers[0] = indices[index]; + + for (int i = 0; i < n; i++) { + closestDistSq[i] = distance(dataset[indices[i]], dataset[indices[index]], dataset.cols); + currentPot += closestDistSq[i]; + } + + + const int numLocalTries = 1; + + // Choose each center + int centerCount; + for (centerCount = 1; centerCount < k; centerCount++) { + + // Repeat several trials + double bestNewPot = -1; + int bestNewIndex = 0; + for (int localTrial = 0; localTrial < numLocalTries; localTrial++) { + + // Choose our center - have to be slightly careful to return a valid answer even accounting + // for possible rounding errors + double randVal = rand_double(currentPot); + for (index = 0; index < n-1; index++) { + if (randVal <= closestDistSq[index]) break; + else randVal -= closestDistSq[index]; + } + + // Compute the new potential + double newPot = 0; + for (int i = 0; i < n; i++) newPot += std::min( distance(dataset[indices[i]], dataset[indices[index]], dataset.cols), closestDistSq[i] ); + + // Store the best result + if ((bestNewPot < 0)||(newPot < bestNewPot)) { + bestNewPot = newPot; + bestNewIndex = index; + } + } + + // Add the appropriate center + centers[centerCount] = indices[bestNewIndex]; + currentPot = bestNewPot; + for (int i = 0; i < n; i++) closestDistSq[i] = std::min( distance(dataset[indices[i]], dataset[indices[bestNewIndex]], dataset.cols), closestDistSq[i] ); + } + + centers_length = centerCount; + + delete[] closestDistSq; + } + + +public: + + + /** + * Index constructor + * + * Params: + * inputData = dataset with the input features + * params = parameters passed to the hierarchical k-means algorithm + */ + HierarchicalClusteringIndex(const Matrix& inputData, const IndexParams& index_params = HierarchicalClusteringIndexParams(), + Distance d = Distance()) + : dataset(inputData), params(index_params), root(NULL), indices(NULL), distance(d) + { + memoryCounter = 0; + + size_ = dataset.rows; + veclen_ = dataset.cols; + + branching_ = get_param(params,"branching",32); + centers_init_ = get_param(params,"centers_init", FLANN_CENTERS_RANDOM); + trees_ = get_param(params,"trees",4); + leaf_size_ = get_param(params,"leaf_size",100); + + if (centers_init_==FLANN_CENTERS_RANDOM) { + chooseCenters = &HierarchicalClusteringIndex::chooseCentersRandom; + } + else if (centers_init_==FLANN_CENTERS_GONZALES) { + chooseCenters = &HierarchicalClusteringIndex::chooseCentersGonzales; + } + else if (centers_init_==FLANN_CENTERS_KMEANSPP) { + chooseCenters = &HierarchicalClusteringIndex::chooseCentersKMeanspp; + } + else { + throw FLANNException("Unknown algorithm for choosing initial centers."); + } + + trees_ = get_param(params,"trees",4); + root = new NodePtr[trees_]; + indices = new int*[trees_]; + } + + HierarchicalClusteringIndex(const HierarchicalClusteringIndex&); + HierarchicalClusteringIndex& operator=(const HierarchicalClusteringIndex&); + + /** + * Index destructor. + * + * Release the memory used by the index. + */ + virtual ~HierarchicalClusteringIndex() + { + if (indices!=NULL) { + delete[] indices; + } + } + + /** + * Returns size of index. + */ + size_t size() const + { + return size_; + } + + /** + * Returns the length of an index feature. + */ + size_t veclen() const + { + return veclen_; + } + + + /** + * Computes the inde memory usage + * Returns: memory used by the index + */ + int usedMemory() const + { + return pool.usedMemory+pool.wastedMemory+memoryCounter; + } + + /** + * Builds the index + */ + void buildIndex() + { + if (branching_<2) { + throw FLANNException("Branching factor must be at least 2"); + } + for (int i=0; i(); + computeClustering(root[i], indices[i], size_, branching_,0); + } + } + + + flann_algorithm_t getType() const + { + return FLANN_INDEX_HIERARCHICAL; + } + + + void saveIndex(FILE* stream) + { + save_value(stream, branching_); + save_value(stream, trees_); + save_value(stream, centers_init_); + save_value(stream, leaf_size_); + save_value(stream, memoryCounter); + for (int i=0; i& result, const ElementType* vec, const SearchParams& searchParams) + { + + int maxChecks = get_param(searchParams,"checks",32); + + // Priority queue storing intermediate branches in the best-bin-first search + Heap* heap = new Heap(size_); + + std::vector checked(size_,false); + int checks = 0; + for (int i=0; ipopMin(branch) && (checks BranchSt; + + + + void save_tree(FILE* stream, NodePtr node, int num) + { + save_value(stream, *node); + if (node->childs==NULL) { + int indices_offset = node->indices - indices[num]; + save_value(stream, indices_offset); + } + else { + for(int i=0; ichilds[i], num); + } + } + } + + + void load_tree(FILE* stream, NodePtr& node, int num) + { + node = pool.allocate(); + load_value(stream, *node); + if (node->childs==NULL) { + int indices_offset; + load_value(stream, indices_offset); + node->indices = indices[num] + indices_offset; + } + else { + node->childs = pool.allocate(branching_); + for(int i=0; ichilds[i], num); + } + } + } + + + + + void computeLabels(int* indices, int indices_length, int* centers, int centers_length, int* labels, DistanceType& cost) + { + cost = 0; + for (int i=0; inew_dist) { + labels[i] = j; + dist = new_dist; + } + } + cost += dist; + } + } + + /** + * The method responsible with actually doing the recursive hierarchical + * clustering + * + * Params: + * node = the node to cluster + * indices = indices of the points belonging to the current node + * branching = the branching factor to use in the clustering + * + * TODO: for 1-sized clusters don't store a cluster center (it's the same as the single cluster point) + */ + void computeClustering(NodePtr node, int* indices, int indices_length, int branching, int level) + { + node->size = indices_length; + node->level = level; + + if (indices_length < leaf_size_) { // leaf node + node->indices = indices; + std::sort(node->indices,node->indices+indices_length); + node->childs = NULL; + return; + } + + std::vector centers(branching); + std::vector labels(indices_length); + + int centers_length; + (this->*chooseCenters)(branching, indices, indices_length, ¢ers[0], centers_length); + + if (centers_lengthindices = indices; + std::sort(node->indices,node->indices+indices_length); + node->childs = NULL; + return; + } + + + // assign points to clusters + DistanceType cost; + computeLabels(indices, indices_length, ¢ers[0], centers_length, &labels[0], cost); + + node->childs = pool.allocate(branching); + int start = 0; + int end = start; + for (int i=0; ichilds[i] = pool.allocate(); + node->childs[i]->pivot = centers[i]; + node->childs[i]->indices = NULL; + computeClustering(node->childs[i],indices+start, end-start, branching, level+1); + start=end; + } + } + + + + /** + * Performs one descent in the hierarchical k-means tree. The branches not + * visited are stored in a priority queue. + * + * Params: + * node = node to explore + * result = container for the k-nearest neighbors found + * vec = query points + * checks = how many points in the dataset have been checked so far + * maxChecks = maximum dataset points to checks + */ + + + void findNN(NodePtr node, ResultSet& result, const ElementType* vec, int& checks, int maxChecks, + Heap* heap, std::vector& checked) + { + if (node->childs==NULL) { + if (checks>=maxChecks) { + if (result.full()) return; + } + checks += node->size; + for (int i=0; isize; ++i) { + int index = node->indices[i]; + if (!checked[index]) { + DistanceType dist = distance(dataset[index], vec, veclen_); + result.addPoint(dist, index); + checked[index] = true; + } + } + } + else { + DistanceType* domain_distances = new DistanceType[branching_]; + int best_index = 0; + domain_distances[best_index] = distance(vec, dataset[node->childs[best_index]->pivot], veclen_); + for (int i=1; ichilds[i]->pivot], veclen_); + if (domain_distances[i]insert(BranchSt(node->childs[i],domain_distances[i])); + } + } + delete[] domain_distances; + findNN(node->childs[best_index],result,vec, checks, maxChecks, heap, checked); + } + } + +private: + + + /** + * The dataset used by this index + */ + const Matrix dataset; + + /** + * Parameters used by this index + */ + IndexParams params; + + + /** + * Number of features in the dataset. + */ + size_t size_; + + /** + * Length of each feature. + */ + size_t veclen_; + + /** + * The root node in the tree. + */ + NodePtr* root; + + /** + * Array of indices to vectors in the dataset. + */ + int** indices; + + + /** + * The distance + */ + Distance distance; + + /** + * Pooled memory allocator. + * + * Using a pooled memory allocator is more efficient + * than allocating memory directly when there is a large + * number small of memory allocations. + */ + PooledAllocator pool; + + /** + * Memory occupied by the index. + */ + int memoryCounter; + + /** index parameters */ + int branching_; + int trees_; + flann_centers_init_t centers_init_; + int leaf_size_; + + +}; + +} + +#endif /* OPENCV_FLANN_HIERARCHICAL_CLUSTERING_INDEX_H_ */ diff --git a/modules/flann/include/opencv2/flann/index_testing.h b/modules/flann/include/opencv2/flann/index_testing.h index 476c2c2c65..c98a14b1ce 100644 --- a/modules/flann/include/opencv2/flann/index_testing.h +++ b/modules/flann/include/opencv2/flann/index_testing.h @@ -28,36 +28,50 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_TESTING_H_ -#define _OPENCV_TESTING_H_ +#ifndef OPENCV_FLANN_INDEX_TESTING_H_ +#define OPENCV_FLANN_INDEX_TESTING_H_ #include #include +#include -#include "opencv2/flann/matrix.h" -#include "opencv2/flann/nn_index.h" -#include "opencv2/flann/result_set.h" -#include "opencv2/flann/logger.h" -#include "opencv2/flann/timer.h" - +#include "matrix.h" +#include "nn_index.h" +#include "result_set.h" +#include "logger.h" +#include "timer.h" namespace cvflann { -CV_EXPORTS int countCorrectMatches(int* neighbors, int* groundTruth, int n); - - -template -float computeDistanceRaport(const Matrix& inputData, ELEM_TYPE* target, int* neighbors, int* groundTruth, int veclen, int n) +inline int countCorrectMatches(int* neighbors, int* groundTruth, int n) { - ELEM_TYPE* target_end = target + veclen; - float ret = 0; - for (int i=0;i +typename Distance::ResultType computeDistanceRaport(const Matrix& inputData, typename Distance::ElementType* target, + int* neighbors, int* groundTruth, int veclen, int n, const Distance& distance) +{ + typedef typename Distance::ResultType DistanceType; + + DistanceType ret = 0; + for (int i=0; i& inputData, ELEM_TYPE* targe return ret; } -template -float search_with_ground_truth(NNIndex& index, const Matrix& inputData, const Matrix& testData, const Matrix& matches, int nn, int checks, float& time, float& dist, int skipMatches) +template +float search_with_ground_truth(NNIndex& index, const Matrix& inputData, + const Matrix& testData, const Matrix& matches, int nn, int checks, + float& time, typename Distance::ResultType& dist, const Distance& distance, int skipMatches) { + typedef typename Distance::ResultType DistanceType; + if (matches.cols resultSet(nn+skipMatches); + KNNResultSet resultSet(nn+skipMatches); SearchParams searchParams(checks); + int* indices = new int[nn+skipMatches]; + DistanceType* dists = new DistanceType[nn+skipMatches]; + int* neighbors = indices + skipMatches; + int correct = 0; - float distR = 0; + DistanceType distR = 0; StartStopTimer t; int repeats = 0; while (t.value<0.2) { @@ -90,65 +112,69 @@ float search_with_ground_truth(NNIndex& index, const Matrix(inputData, testData[i], neighbors, matches[i], testData.cols, nn, distance); } t.stop(); } - time = (float)(t.value/repeats); + time = float(t.value/repeats); + delete[] indices; + delete[] dists; float precicion = (float)correct/(nn*testData.rows); dist = distR/(testData.rows*nn); - logger().info("%8d %10.4g %10.5g %10.5g %10.5g\n", - checks, precicion, time, 1000.0 * time / testData.rows, dist); + Logger::info("%8d %10.4g %10.5g %10.5g %10.5g\n", + checks, precicion, time, 1000.0 * time / testData.rows, dist); return precicion; } -template -float test_index_checks(NNIndex& index, const Matrix& inputData, const Matrix& testData, const Matrix& matches, - int checks, float& precision, int nn = 1, int skipMatches = 0) +template +float test_index_checks(NNIndex& index, const Matrix& inputData, + const Matrix& testData, const Matrix& matches, + int checks, float& precision, const Distance& distance, int nn = 1, int skipMatches = 0) { - logger().info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n"); - logger().info("---------------------------------------------------------\n"); + typedef typename Distance::ResultType DistanceType; + + Logger::info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n"); + Logger::info("---------------------------------------------------------\n"); float time = 0; - float dist = 0; - precision = search_with_ground_truth(index, inputData, testData, matches, nn, checks, time, dist, skipMatches); + DistanceType dist = 0; + precision = search_with_ground_truth(index, inputData, testData, matches, nn, checks, time, dist, distance, skipMatches); return time; } -template -float test_index_precision(NNIndex& index, const Matrix& inputData, const Matrix& testData, const Matrix& matches, - float precision, int& checks, int nn = 1, int skipMatches = 0) +template +float test_index_precision(NNIndex& index, const Matrix& inputData, + const Matrix& testData, const Matrix& matches, + float precision, int& checks, const Distance& distance, int nn = 1, int skipMatches = 0) { - const float SEARCH_EPS = 0.001f; + typedef typename Distance::ResultType DistanceType; + const float SEARCH_EPS = 0.001f; - logger().info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n"); - logger().info("---------------------------------------------------------\n"); + Logger::info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n"); + Logger::info("---------------------------------------------------------\n"); int c2 = 1; float p2; int c1 = 1; float p1; float time; - float dist; + DistanceType dist; - p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches); + p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, distance, skipMatches); if (p2>precision) { - logger().info("Got as close as I can\n"); + Logger::info("Got as close as I can\n"); checks = c2; return time; } @@ -157,18 +183,18 @@ float test_index_precision(NNIndex& index, const Matrix& i c1 = c2; p1 = p2; c2 *=2; - p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches); + p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, distance, skipMatches); } int cx; float realPrecision; if (fabs(p2-precision)>SEARCH_EPS) { - logger().info("Start linear estimation\n"); + Logger::info("Start linear estimation\n"); // after we got to values in the vecinity of the desired precision // use linear approximation get a better estimation cx = (c1+c2)/2; - realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches); + realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, distance, skipMatches); while (fabs(realPrecision-precision)>SEARCH_EPS) { if (realPrecision& index, const Matrix& i } cx = (c1+c2)/2; if (cx==c1) { - logger().info("Got as close as I can\n"); + Logger::info("Got as close as I can\n"); break; } - realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches); + realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, distance, skipMatches); } c2 = cx; p2 = realPrecision; - } else { - logger().info("No need for linear estimation\n"); + } + else { + Logger::info("No need for linear estimation\n"); cx = c2; realPrecision = p2; } @@ -199,11 +226,14 @@ float test_index_precision(NNIndex& index, const Matrix& i } -template -float test_index_precisions(NNIndex& index, const Matrix& inputData, const Matrix& testData, const Matrix& matches, - float* precisions, int precisions_length, int nn = 1, int skipMatches = 0, float maxTime = 0) +template +void test_index_precisions(NNIndex& index, const Matrix& inputData, + const Matrix& testData, const Matrix& matches, + float* precisions, int precisions_length, const Distance& distance, int nn = 1, int skipMatches = 0, float maxTime = 0) { - const float SEARCH_EPS = 0.001; + typedef typename Distance::ResultType DistanceType; + + const float SEARCH_EPS = 0.001; // make sure precisions array is sorted std::sort(precisions, precisions+precisions_length); @@ -211,8 +241,8 @@ float test_index_precisions(NNIndex& index, const Matrix& int pindex = 0; float precision = precisions[pindex]; - logger().info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist"); - logger().info("---------------------------------------------------------"); + Logger::info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n"); + Logger::info("---------------------------------------------------------\n"); int c2 = 1; float p2; @@ -221,9 +251,9 @@ float test_index_precisions(NNIndex& index, const Matrix& float p1; float time; - float dist; + DistanceType dist; - p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches); + p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, distance, skipMatches); // if precision for 1 run down the tree is already // better then some of the requested precisions, then @@ -233,30 +263,30 @@ float test_index_precisions(NNIndex& index, const Matrix& } if (pindex==precisions_length) { - logger().info("Got as close as I can\n"); - return time; + Logger::info("Got as close as I can\n"); + return; } - for (int i=pindex;i 0 && time > maxTime && p2 0)&&(time > maxTime)&&(p2SEARCH_EPS) { - logger().info("Start linear estimation\n"); + Logger::info("Start linear estimation\n"); // after we got to values in the vecinity of the desired precision // use linear approximation get a better estimation cx = (c1+c2)/2; - realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches); + realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, distance, skipMatches); while (fabs(realPrecision-precision)>SEARCH_EPS) { if (realPrecision& index, const Matrix& } cx = (c1+c2)/2; if (cx==c1) { - logger().info("Got as close as I can\n"); + Logger::info("Got as close as I can\n"); break; } - realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches); + realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, distance, skipMatches); } c2 = cx; p2 = realPrecision; - } else { - logger().info("No need for linear estimation\n"); + } + else { + Logger::info("No need for linear estimation\n"); cx = c2; realPrecision = p2; } } - return time; } -} // namespace cvflann +} -#endif //_OPENCV_TESTING_H_ +#endif //OPENCV_FLANN_INDEX_TESTING_H_ diff --git a/modules/flann/include/opencv2/flann/kdtree_index.h b/modules/flann/include/opencv2/flann/kdtree_index.h index 7344165e0d..dc0971c9ef 100644 --- a/modules/flann/include/opencv2/flann/kdtree_index.h +++ b/modules/flann/include/opencv2/flann/kdtree_index.h @@ -28,38 +28,35 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_KDTREE_H_ -#define _OPENCV_KDTREE_H_ +#ifndef OPENCV_FLANN_KDTREE_INDEX_H_ +#define OPENCV_FLANN_KDTREE_INDEX_H_ #include #include #include #include -#include "opencv2/flann/general.h" -#include "opencv2/flann/nn_index.h" -#include "opencv2/flann/matrix.h" -#include "opencv2/flann/result_set.h" -#include "opencv2/flann/heap.h" -#include "opencv2/flann/allocator.h" -#include "opencv2/flann/random.h" -#include "opencv2/flann/saving.h" +#include "general.h" +#include "nn_index.h" +#include "dynamic_bitset.h" +#include "matrix.h" +#include "result_set.h" +#include "heap.h" +#include "allocator.h" +#include "random.h" +#include "saving.h" namespace cvflann { -struct CV_EXPORTS KDTreeIndexParams : public IndexParams { - KDTreeIndexParams(int trees_ = 4) : IndexParams(FLANN_INDEX_KDTREE), trees(trees_) {}; - - int trees; // number of randomized trees to use (for kdtree) - - void print() const - { - logger().info("Index type: %d\n",(int)algorithm); - logger().info("Trees: %d\n", trees); - } - +struct KDTreeIndexParams : public IndexParams +{ + KDTreeIndexParams(int trees = 4) + { + (*this)["algorithm"] = FLANN_INDEX_KDTREE; + (*this)["trees"] = trees; + } }; @@ -69,223 +66,126 @@ struct CV_EXPORTS KDTreeIndexParams : public IndexParams { * Contains the k-d trees and other information for indexing a set of points * for nearest-neighbor matching. */ -template ::type > -class KDTreeIndex : public NNIndex +template +class KDTreeIndex : public NNIndex { +public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; - enum { - /** - * To improve efficiency, only SAMPLE_MEAN random values are used to - * compute the mean and variance at each level when building a tree. - * A value of 100 seems to perform as well as using all values. - */ - SAMPLE_MEAN = 100, - /** - * Top random dimensions to consider - * - * When creating random trees, the dimension on which to subdivide is - * selected at random from among the top RAND_DIM dimensions with the - * highest variance. A value of 5 works well. - */ - RAND_DIM=5 - }; - - - /** - * Number of randomized trees that are used - */ - int numTrees; - - /** - * Array of indices to vectors in the dataset. - */ - int* vind; - - - /** - * The dataset used by this index - */ - const Matrix dataset; - - const IndexParams& index_params; - - size_t size_; - size_t veclen_; - - - DIST_TYPE* mean; - DIST_TYPE* var; - - - /*--------------------- Internal Data Structures --------------------------*/ - - /** - * A node of the binary k-d tree. - * - * This is All nodes that have vec[divfeat] < divval are placed in the - * child1 subtree, else child2., A leaf node is indicated if both children are NULL. - */ - struct TreeSt { - /** - * Index of the vector feature used for subdivision. - * If this is a leaf node (both children are NULL) then - * this holds vector index for this leaf. - */ - int divfeat; - /** - * The value used for subdivision. - */ - DIST_TYPE divval; - /** - * The child nodes. - */ - TreeSt *child1, *child2; - }; - typedef TreeSt* Tree; /** - * Array of k-d trees used to find neighbours. + * KDTree constructor + * + * Params: + * inputData = dataset with the input features + * params = parameters passed to the kdtree algorithm */ - Tree* trees; - typedef BranchStruct BranchSt; - typedef BranchSt* Branch; + KDTreeIndex(const Matrix& inputData, const IndexParams& params = KDTreeIndexParams(), + Distance d = Distance() ) : + dataset_(inputData), index_params_(params), distance_(d) + { + size_ = dataset_.rows; + veclen_ = dataset_.cols; - /** - * Pooled memory allocator. - * - * Using a pooled memory allocator is more efficient - * than allocating memory directly when there is a large - * number small of memory allocations. - */ - PooledAllocator pool; + trees_ = get_param(index_params_,"trees",4); + tree_roots_ = new NodePtr[trees_]; + + // Create a permutable array of indices to the input vectors. + vind_.resize(size_); + for (size_t i = 0; i < size_; ++i) { + vind_[i] = int(i); + } + + mean_ = new DistanceType[veclen_]; + var_ = new DistanceType[veclen_]; + } + KDTreeIndex(const KDTreeIndex&); + KDTreeIndex& operator=(const KDTreeIndex&); + + /** + * Standard destructor + */ + ~KDTreeIndex() + { + if (tree_roots_!=NULL) { + delete[] tree_roots_; + } + delete[] mean_; + delete[] var_; + } + + /** + * Builds the index + */ + void buildIndex() + { + /* Construct the randomized trees. */ + for (int i = 0; i < trees_; i++) { + /* Randomize the order of vectors to allow for unbiased sampling. */ + std::random_shuffle(vind_.begin(), vind_.end()); + tree_roots_[i] = divideTree(&vind_[0], int(size_) ); + } + } -public: flann_algorithm_t getType() const { return FLANN_INDEX_KDTREE; } - /** - * KDTree constructor - * - * Params: - * inputData = dataset with the input features - * params = parameters passed to the kdtree algorithm - */ - KDTreeIndex(const Matrix& inputData, const KDTreeIndexParams& params = KDTreeIndexParams() ) : - dataset(inputData), index_params(params) - { - size_ = dataset.rows; - veclen_ = dataset.cols; - - numTrees = params.trees; - trees = new Tree[numTrees]; - - // get the parameters -// if (params.find("trees") != params.end()) { -// numTrees = (int)params["trees"]; -// trees = new Tree[numTrees]; -// } -// else { -// numTrees = -1; -// trees = NULL; -// } - - // Create a permutable array of indices to the input vectors. - vind = new int[size_]; - for (size_t i = 0; i < size_; i++) { - vind[i] = (int)i; - } - - mean = new DIST_TYPE[veclen_]; - var = new DIST_TYPE[veclen_]; - } - - /** - * Standard destructor - */ - ~KDTreeIndex() - { - delete[] vind; - if (trees!=NULL) { - delete[] trees; - } - delete[] mean; - delete[] var; - } - - - /** - * Builds the index - */ - void buildIndex() - { - /* Construct the randomized trees. */ - for (int i = 0; i < numTrees; i++) { - /* Randomize the order of vectors to allow for unbiased sampling. */ - for (int j = (int)size_; j > 0; --j) { - int rnd = rand_int(j); - std::swap(vind[j-1], vind[rnd]); - } - trees[i] = divideTree(0, (int)size_ - 1); - } - } - - void saveIndex(FILE* stream) { - save_value(stream, numTrees); - for (int i=0;i& result, const ELEM_TYPE* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) { - int maxChecks = searchParams.checks; + int maxChecks = get_param(searchParams,"checks", 32); + float epsError = 1+get_param(searchParams,"eps",0.0f); - if (maxChecks<0) { - getExactNeighbors(result, vec); - } else { - getNeighbors(result, vec, maxChecks); + if (maxChecks==FLANN_CHECKS_UNLIMITED) { + getExactNeighbors(result, vec, epsError); + } + else { + getNeighbors(result, vec, maxChecks, epsError); } } - const IndexParams* getParameters() const - { - return &index_params; - } + IndexParams getParameters() const + { + return index_params_; + } private: - KDTreeIndex& operator=(const KDTreeIndex&); - KDTreeIndex(const KDTreeIndex&); - - void save_tree(FILE* stream, Tree tree) + /*--------------------- Internal Data Structures --------------------------*/ + struct Node { - save_value(stream, *tree); - if (tree->child1!=NULL) { - save_tree(stream, tree->child1); - } - if (tree->child2!=NULL) { - save_tree(stream, tree->child2); - } + /** + * Dimension used for subdivision. + */ + int divfeat; + /** + * The values used for subdivision. + */ + DistanceType divval; + /** + * The child nodes. + */ + Node* child1, * child2; + }; + typedef Node* NodePtr; + typedef BranchStruct BranchSt; + typedef BranchSt* Branch; + + + + void save_tree(FILE* stream, NodePtr tree) + { + save_value(stream, *tree); + if (tree->child1!=NULL) { + save_tree(stream, tree->child1); + } + if (tree->child2!=NULL) { + save_tree(stream, tree->child2); + } } - void load_tree(FILE* stream, Tree& tree) + void load_tree(FILE* stream, NodePtr& tree) { - tree = pool.allocate(); - load_value(stream, *tree); - if (tree->child1!=NULL) { - load_tree(stream, tree->child1); - } - if (tree->child2!=NULL) { - load_tree(stream, tree->child2); - } + tree = pool_.allocate(); + load_value(stream, *tree); + if (tree->child1!=NULL) { + load_tree(stream, tree->child1); + } + if (tree->child2!=NULL) { + load_tree(stream, tree->child2); + } } - /** - * Create a tree node that subdivides the list of vecs from vind[first] - * to vind[last]. The routine is called recursively on each sublist. - * Place a pointer to this new tree node in the location pTree. - * - * Params: pTree = the new node to create - * first = index of the first vector - * last = index of the last vector - */ - Tree divideTree(int first, int last) - { - Tree node = pool.allocate(); // allocate memory + /** + * Create a tree node that subdivides the list of vecs from vind[first] + * to vind[last]. The routine is called recursively on each sublist. + * Place a pointer to this new tree node in the location pTree. + * + * Params: pTree = the new node to create + * first = index of the first vector + * last = index of the last vector + */ + NodePtr divideTree(int* ind, int count) + { + NodePtr node = pool_.allocate(); // allocate memory - /* If only one exemplar remains, then make this a leaf node. */ - if (first == last) { - node->child1 = node->child2 = NULL; /* Mark as leaf node. */ - node->divfeat = vind[first]; /* Store index of this vec. */ - } - else { - chooseDivision(node, first, last); - subdivide(node, first, last); - } + /* If too few exemplars remain, then make this a leaf node. */ + if ( count == 1) { + node->child1 = node->child2 = NULL; /* Mark as leaf node. */ + node->divfeat = *ind; /* Store index of this vec. */ + } + else { + int idx; + int cutfeat; + DistanceType cutval; + meanSplit(ind, count, idx, cutfeat, cutval); - return node; - } - - - /** - * Choose which feature to use in order to subdivide this set of vectors. - * Make a random choice among those with the highest variance, and use - * its variance as the threshold value. - */ - void chooseDivision(Tree node, int first, int last) - { - memset(mean,0,veclen_*sizeof(DIST_TYPE)); - memset(var,0,veclen_*sizeof(DIST_TYPE)); - - /* Compute mean values. Only the first SAMPLE_MEAN values need to be - sampled to get a good estimate. - */ - int end = std::min(first + SAMPLE_MEAN, last); - for (int j = first; j <= end; ++j) { - ELEM_TYPE* v = dataset[vind[j]]; - for (size_t k=0; kdivfeat = cutfeat; + node->divval = cutval; + node->child1 = divideTree(ind, idx); + node->child2 = divideTree(ind+idx, count-idx); } - /* Compute variances (no need to divide by count). */ - for (int j = first; j <= end; ++j) { - ELEM_TYPE* v = dataset[vind[j]]; + return node; + } + + + /** + * Choose which feature to use in order to subdivide this set of vectors. + * Make a random choice among those with the highest variance, and use + * its variance as the threshold value. + */ + void meanSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval) + { + memset(mean_,0,veclen_*sizeof(DistanceType)); + memset(var_,0,veclen_*sizeof(DistanceType)); + + /* Compute mean values. Only the first SAMPLE_MEAN values need to be + sampled to get a good estimate. + */ + int cnt = std::min((int)SAMPLE_MEAN+1, count); + for (int j = 0; j < cnt; ++j) { + ElementType* v = dataset_[ind[j]]; for (size_t k=0; kdivfeat = selectDivision(var); - node->divval = mean[node->divfeat]; + } + for (size_t k=0; kcount/2) index = lim1; + else if (lim2 v[topind[num-1]]) { - /* Put this element at end of topind. */ - if (num < RAND_DIM) { - topind[num++] = (int)i; /* Add to list. */ - } - else { - topind[num-1] = (int)i; /* Replace last element. */ - } - /* Bubble end value down to right location by repeated swapping. */ - int j = num - 1; - while (j > 0 && v[topind[j]] > v[topind[j-1]]) { + /* Create a list of the indices of the top RAND_DIM values. */ + for (size_t i = 0; i < veclen_; ++i) { + if ((num < RAND_DIM)||(v[i] > v[topind[num-1]])) { + /* Put this element at end of topind. */ + if (num < RAND_DIM) { + topind[num++] = i; /* Add to list. */ + } + else { + topind[num-1] = i; /* Replace last element. */ + } + /* Bubble end value down to right location by repeated swapping. */ + int j = num - 1; + while (j > 0 && v[topind[j]] > v[topind[j-1]]) { std::swap(topind[j], topind[j-1]); - --j; - } - } - } - /* Select a random integer in range [0,num-1], and return that index. */ - int rnd = rand_int(num); - return topind[rnd]; - } + --j; + } + } + } + /* Select a random integer in range [0,num-1], and return that index. */ + int rnd = rand_int(num); + return (int)topind[rnd]; + } - /** - * Subdivide the list of exemplars using the feature and division - * value given in this node. Call divideTree recursively on each list. - */ - void subdivide(Tree node, int first, int last) - { - /* Move vector indices for left subtree to front of list. */ - int i = first; - int j = last; - while (i <= j) { - int ind = vind[i]; - ELEM_TYPE val = dataset[ind][node->divfeat]; - if (val < node->divval) { - ++i; - } else { - /* Move to end of list by swapping vind i and j. */ - std::swap(vind[i], vind[j]); - --j; - } - } - /* If either list is empty, it means we have hit the unlikely case - in which all remaining features are identical. Split in the middle - to maintain a balanced tree. - */ - if ( (i == first) || (i == last+1)) { - i = (first+last+1)/2; - } + /** + * Subdivide the list of points by a plane perpendicular on axe corresponding + * to the 'cutfeat' dimension at 'cutval' position. + * + * On return: + * dataset[ind[0..lim1-1]][cutfeat]cutval + */ + void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2) + { + /* Move vector indices for left subtree to front of list. */ + int left = 0; + int right = count-1; + for (;; ) { + while (left<=right && dataset_[ind[left]][cutfeat]=cutval) --right; + if (left>right) break; + std::swap(ind[left], ind[right]); ++left; --right; + } + lim1 = left; + right = count-1; + for (;; ) { + while (left<=right && dataset_[ind[left]][cutfeat]<=cutval) ++left; + while (left<=right && dataset_[ind[right]][cutfeat]>cutval) --right; + if (left>right) break; + std::swap(ind[left], ind[right]); ++left; --right; + } + lim2 = left; + } - node->child1 = divideTree(first, i - 1); - node->child2 = divideTree(i, last); - } + /** + * Performs an exact nearest neighbor search. The exact search performs a full + * traversal of the tree. + */ + void getExactNeighbors(ResultSet& result, const ElementType* vec, float epsError) + { + // checkID -= 1; /* Set a different unique ID for each search. */ - - - /** - * Performs an exact nearest neighbor search. The exact search performs a full - * traversal of the tree. - */ - void getExactNeighbors(ResultSet& result, const ELEM_TYPE* vec) - { -// checkID -= 1; /* Set a different unique ID for each search. */ - - if (numTrees > 1) { + if (trees_ > 1) { fprintf(stderr,"It doesn't make any sense to use more than one tree for exact search"); - } - if (numTrees>0) { - searchLevelExact(result, vec, trees[0], 0.0); - } - assert(result.full()); - } + } + if (trees_>0) { + searchLevelExact(result, vec, tree_roots_[0], 0.0, epsError); + } + assert(result.full()); + } - /** - * Performs the approximate nearest-neighbor search. The search is approximate - * because the tree traversal is abandoned after a given number of descends in - * the tree. - */ - void getNeighbors(ResultSet& result, const ELEM_TYPE* vec, int maxCheck) - { - int i; - BranchSt branch; + /** + * Performs the approximate nearest-neighbor search. The search is approximate + * because the tree traversal is abandoned after a given number of descends in + * the tree. + */ + void getNeighbors(ResultSet& result, const ElementType* vec, int maxCheck, float epsError) + { + int i; + BranchSt branch; - int checkCount = 0; - Heap* heap = new Heap((int)size_); - std::vector checked(size_,false); + int checkCount = 0; + Heap* heap = new Heap((int)size_); + DynamicBitset checked(size_); - /* Search once through each tree down to root. */ - for (i = 0; i < numTrees; ++i) { - searchLevel(result, vec, trees[i], 0.0, checkCount, maxCheck, heap, checked); - } + /* Search once through each tree down to root. */ + for (i = 0; i < trees_; ++i) { + searchLevel(result, vec, tree_roots_[i], 0, checkCount, maxCheck, epsError, heap, checked); + } - /* Keep searching other branches from heap until finished. */ - while ( heap->popMin(branch) && (checkCount < maxCheck || !result.full() )) { - searchLevel(result, vec, branch.node, branch.mindistsq, checkCount, maxCheck, heap, checked); - } + /* Keep searching other branches from heap until finished. */ + while ( heap->popMin(branch) && (checkCount < maxCheck || !result.full() )) { + searchLevel(result, vec, branch.node, branch.mindist, checkCount, maxCheck, epsError, heap, checked); + } - delete heap; + delete heap; - assert(result.full()); - } + assert(result.full()); + } - /** - * Search starting from a given node of the tree. Based on any mismatches at - * higher levels, all exemplars below this level must have a distance of - * at least "mindistsq". - */ - void searchLevel(ResultSet& result, const ELEM_TYPE* vec, Tree node, float mindistsq, int& checkCount, int maxCheck, - Heap* heap, std::vector& checked) - { - if (result.worstDist()& result_set, const ElementType* vec, NodePtr node, DistanceType mindist, int& checkCount, int maxCheck, + float epsError, Heap* heap, DynamicBitset& checked) + { + if (result_set.worstDist()child1 == NULL && node->child2 == NULL) { - - /* Do not check same node more than once when searching multiple trees. - Once a vector is checked, we set its location in vind to the - current checkID. - */ - if (checked[node->divfeat] == true || checkCount>=maxCheck) { - if (result.full()) return; - } + /* If this is a leaf node, then do check and return. */ + if ((node->child1 == NULL)&&(node->child2 == NULL)) { + /* Do not check same node more than once when searching multiple trees. + Once a vector is checked, we set its location in vind to the + current checkID. + */ + int index = node->divfeat; + if ( checked.test(index) || ((checkCount>=maxCheck)&& result_set.full()) ) return; + checked.set(index); checkCount++; - checked[node->divfeat] = true; - result.addPoint(dataset[node->divfeat],node->divfeat); - return; - } + DistanceType dist = distance_(dataset_[index], vec, veclen_); + result_set.addPoint(dist,index); - /* Which child branch should be taken first? */ - ELEM_TYPE val = vec[node->divfeat]; - DIST_TYPE diff = val - node->divval; - Tree bestChild = (diff < 0) ? node->child1 : node->child2; - Tree otherChild = (diff < 0) ? node->child2 : node->child1; + return; + } - /* Create a branch record for the branch not taken. Add distance - of this feature boundary (we don't attempt to correct for any - use of this feature in a parent node, which is unlikely to - happen and would have only a small effect). Don't bother - adding more branches to heap after halfway point, as cost of - adding exceeds their value. - */ + /* Which child branch should be taken first? */ + ElementType val = vec[node->divfeat]; + DistanceType diff = val - node->divval; + NodePtr bestChild = (diff < 0) ? node->child1 : node->child2; + NodePtr otherChild = (diff < 0) ? node->child2 : node->child1; - DIST_TYPE new_distsq = (DIST_TYPE)flann_dist(&val, &val+1, &node->divval, mindistsq); -// if (2 * checkCount < maxCheck || !result.full()) { - if (new_distsq < result.worstDist() || !result.full()) { - heap->insert( BranchSt::make_branch(otherChild, new_distsq) ); - } + /* Create a branch record for the branch not taken. Add distance + of this feature boundary (we don't attempt to correct for any + use of this feature in a parent node, which is unlikely to + happen and would have only a small effect). Don't bother + adding more branches to heap after halfway point, as cost of + adding exceeds their value. + */ - /* Call recursively to search next level down. */ - searchLevel(result, vec, bestChild, mindistsq, checkCount, maxCheck, heap, checked); - } + DistanceType new_distsq = mindist + distance_.accum_dist(val, node->divval, node->divfeat); + // if (2 * checkCount < maxCheck || !result.full()) { + if ((new_distsq*epsError < result_set.worstDist())|| !result_set.full()) { + heap->insert( BranchSt(otherChild, new_distsq) ); + } - /** - * Performs an exact search in the tree starting from a node. - */ - void searchLevelExact(ResultSet& result, const ELEM_TYPE* vec, Tree node, float mindistsq) - { - if (mindistsq>result.worstDist()) { - return; - } + /* Call recursively to search next level down. */ + searchLevel(result_set, vec, bestChild, mindist, checkCount, maxCheck, epsError, heap, checked); + } - /* If this is a leaf node, then do check and return. */ - if (node->child1 == NULL && node->child2 == NULL) { + /** + * Performs an exact search in the tree starting from a node. + */ + void searchLevelExact(ResultSet& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist, const float epsError) + { + /* If this is a leaf node, then do check and return. */ + if ((node->child1 == NULL)&&(node->child2 == NULL)) { + int index = node->divfeat; + DistanceType dist = distance_(dataset_[index], vec, veclen_); + result_set.addPoint(dist,index); + return; + } - /* Do not check same node more than once when searching multiple trees. - Once a vector is checked, we set its location in vind to the - current checkID. - */ -// if (vind[node->divfeat] == checkID) -// return; -// vind[node->divfeat] = checkID; + /* Which child branch should be taken first? */ + ElementType val = vec[node->divfeat]; + DistanceType diff = val - node->divval; + NodePtr bestChild = (diff < 0) ? node->child1 : node->child2; + NodePtr otherChild = (diff < 0) ? node->child2 : node->child1; - result.addPoint(dataset[node->divfeat],node->divfeat); - return; - } + /* Create a branch record for the branch not taken. Add distance + of this feature boundary (we don't attempt to correct for any + use of this feature in a parent node, which is unlikely to + happen and would have only a small effect). Don't bother + adding more branches to heap after halfway point, as cost of + adding exceeds their value. + */ - /* Which child branch should be taken first? */ - ELEM_TYPE val = vec[node->divfeat]; - DIST_TYPE diff = val - node->divval; - Tree bestChild = (diff < 0) ? node->child1 : node->child2; - Tree otherChild = (diff < 0) ? node->child2 : node->child1; + DistanceType new_distsq = mindist + distance_.accum_dist(val, node->divval, node->divfeat); + + /* Call recursively to search next level down. */ + searchLevelExact(result_set, vec, bestChild, mindist, epsError); + + if (new_distsq*epsError<=result_set.worstDist()) { + searchLevelExact(result_set, vec, otherChild, new_distsq, epsError); + } + } - /* Call recursively to search next level down. */ - searchLevelExact(result, vec, bestChild, mindistsq); - DIST_TYPE new_distsq = (DIST_TYPE)flann_dist(&val, &val+1, &node->divval, mindistsq); - searchLevelExact(result, vec, otherChild, new_distsq); - } +private: -}; // class KDTree + enum + { + /** + * To improve efficiency, only SAMPLE_MEAN random values are used to + * compute the mean and variance at each level when building a tree. + * A value of 100 seems to perform as well as using all values. + */ + SAMPLE_MEAN = 100, + /** + * Top random dimensions to consider + * + * When creating random trees, the dimension on which to subdivide is + * selected at random from among the top RAND_DIM dimensions with the + * highest variance. A value of 5 works well. + */ + RAND_DIM=5 + }; -} // namespace cvflann -#endif //_OPENCV_KDTREE_H_ + /** + * Number of randomized trees that are used + */ + int trees_; + + /** + * Array of indices to vectors in the dataset. + */ + std::vector vind_; + + /** + * The dataset used by this index + */ + const Matrix dataset_; + + IndexParams index_params_; + + size_t size_; + size_t veclen_; + + + DistanceType* mean_; + DistanceType* var_; + + + /** + * Array of k-d trees used to find neighbours. + */ + NodePtr* tree_roots_; + + /** + * Pooled memory allocator. + * + * Using a pooled memory allocator is more efficient + * than allocating memory directly when there is a large + * number small of memory allocations. + */ + PooledAllocator pool_; + + Distance distance_; + + +}; // class KDTreeForest + +} + +#endif //OPENCV_FLANN_KDTREE_INDEX_H_ diff --git a/modules/flann/include/opencv2/flann/kdtree_single_index.h b/modules/flann/include/opencv2/flann/kdtree_single_index.h new file mode 100644 index 0000000000..9436a11f83 --- /dev/null +++ b/modules/flann/include/opencv2/flann/kdtree_single_index.h @@ -0,0 +1,634 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +#ifndef OPENCV_FLANN_KDTREE_SINGLE_INDEX_H_ +#define OPENCV_FLANN_KDTREE_SINGLE_INDEX_H_ + +#include +#include +#include +#include + +#include "general.h" +#include "nn_index.h" +#include "matrix.h" +#include "result_set.h" +#include "heap.h" +#include "allocator.h" +#include "random.h" +#include "saving.h" + +namespace cvflann +{ + +struct KDTreeSingleIndexParams : public IndexParams +{ + KDTreeSingleIndexParams(int leaf_max_size = 10, bool reorder = true, int dim = -1) + { + (*this)["algorithm"] = FLANN_INDEX_KDTREE_SINGLE; + (*this)["leaf_max_size"] = leaf_max_size; + (*this)["reorder"] = reorder; + (*this)["dim"] = dim; + } +}; + + +/** + * Randomized kd-tree index + * + * Contains the k-d trees and other information for indexing a set of points + * for nearest-neighbor matching. + */ +template +class KDTreeSingleIndex : public NNIndex +{ +public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + + + /** + * KDTree constructor + * + * Params: + * inputData = dataset with the input features + * params = parameters passed to the kdtree algorithm + */ + KDTreeSingleIndex(const Matrix& inputData, const IndexParams& params = KDTreeSingleIndexParams(), + Distance d = Distance() ) : + dataset_(inputData), index_params_(params), distance_(d) + { + size_ = dataset_.rows; + dim_ = dataset_.cols; + int dim_param = get_param(params,"dim",-1); + if (dim_param>0) dim_ = dim_param; + leaf_max_size_ = get_param(params,"leaf_max_size",10); + reorder_ = get_param(params,"reorder",true); + + // Create a permutable array of indices to the input vectors. + vind_.resize(size_); + for (size_t i = 0; i < size_; i++) { + vind_[i] = i; + } + } + + KDTreeSingleIndex(const KDTreeSingleIndex&); + KDTreeSingleIndex& operator=(const KDTreeSingleIndex&); + + /** + * Standard destructor + */ + ~KDTreeSingleIndex() + { + if (reorder_) delete[] data_.data; + } + + /** + * Builds the index + */ + void buildIndex() + { + computeBoundingBox(root_bbox_); + root_node_ = divideTree(0, size_, root_bbox_ ); // construct the tree + + if (reorder_) { + delete[] data_.data; + data_ = cvflann::Matrix(new ElementType[size_*dim_], size_, dim_); + for (size_t i=0; i& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + { + assert(queries.cols == veclen()); + assert(indices.rows >= queries.rows); + assert(dists.rows >= queries.rows); + assert(int(indices.cols) >= knn); + assert(int(dists.cols) >= knn); + + KNNSimpleResultSet resultSet(knn); + for (size_t i = 0; i < queries.rows; i++) { + resultSet.init(indices[i], dists[i]); + findNeighbors(resultSet, queries[i], params); + } + } + + IndexParams getParameters() const + { + return index_params_; + } + + /** + * Find set of nearest neighbors to vec. Their indices are stored inside + * the result object. + * + * Params: + * result = the result object in which the indices of the nearest-neighbors are stored + * vec = the vector for which to search the nearest neighbors + * maxCheck = the maximum number of restarts (in a best-bin-first manner) + */ + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) + { + float epsError = 1+get_param(searchParams,"eps",0.0f); + + std::vector dists(dim_,0); + DistanceType distsq = computeInitialDistances(vec, dists); + searchLevel(result, vec, root_node_, distsq, dists, epsError); + } + +private: + + + /*--------------------- Internal Data Structures --------------------------*/ + struct Node + { + /** + * Indices of points in leaf node + */ + int left, right; + /** + * Dimension used for subdivision. + */ + int divfeat; + /** + * The values used for subdivision. + */ + DistanceType divlow, divhigh; + /** + * The child nodes. + */ + Node* child1, * child2; + }; + typedef Node* NodePtr; + + + struct Interval + { + DistanceType low, high; + }; + + typedef std::vector BoundingBox; + + typedef BranchStruct BranchSt; + typedef BranchSt* Branch; + + + + + void save_tree(FILE* stream, NodePtr tree) + { + save_value(stream, *tree); + if (tree->child1!=NULL) { + save_tree(stream, tree->child1); + } + if (tree->child2!=NULL) { + save_tree(stream, tree->child2); + } + } + + + void load_tree(FILE* stream, NodePtr& tree) + { + tree = pool_.allocate(); + load_value(stream, *tree); + if (tree->child1!=NULL) { + load_tree(stream, tree->child1); + } + if (tree->child2!=NULL) { + load_tree(stream, tree->child2); + } + } + + + void computeBoundingBox(BoundingBox& bbox) + { + bbox.resize(dim_); + for (size_t i=0; ibbox[i].high) bbox[i].high = (DistanceType)dataset_[k][i]; + } + } + } + + + /** + * Create a tree node that subdivides the list of vecs from vind[first] + * to vind[last]. The routine is called recursively on each sublist. + * Place a pointer to this new tree node in the location pTree. + * + * Params: pTree = the new node to create + * first = index of the first vector + * last = index of the last vector + */ + NodePtr divideTree(int left, int right, BoundingBox& bbox) + { + NodePtr node = pool_.allocate(); // allocate memory + + /* If too few exemplars remain, then make this a leaf node. */ + if ( (right-left) <= leaf_max_size_) { + node->child1 = node->child2 = NULL; /* Mark as leaf node. */ + node->left = left; + node->right = right; + + // compute bounding-box of leaf points + for (size_t i=0; idataset_[vind_[k]][i]) bbox[i].low=(DistanceType)dataset_[vind_[k]][i]; + if (bbox[i].highdivfeat = cutfeat; + + BoundingBox left_bbox(bbox); + left_bbox[cutfeat].high = cutval; + node->child1 = divideTree(left, left+idx, left_bbox); + + BoundingBox right_bbox(bbox); + right_bbox[cutfeat].low = cutval; + node->child2 = divideTree(left+idx, right, right_bbox); + + node->divlow = left_bbox[cutfeat].high; + node->divhigh = right_bbox[cutfeat].low; + + for (size_t i=0; imax_elem) max_elem = val; + } + } + + void middleSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox) + { + // find the largest span from the approximate bounding box + ElementType max_span = bbox[0].high-bbox[0].low; + cutfeat = 0; + cutval = (bbox[0].high+bbox[0].low)/2; + for (size_t i=1; imax_span) { + max_span = span; + cutfeat = i; + cutval = (bbox[i].high+bbox[i].low)/2; + } + } + + // compute exact span on the found dimension + ElementType min_elem, max_elem; + computeMinMax(ind, count, cutfeat, min_elem, max_elem); + cutval = (min_elem+max_elem)/2; + max_span = max_elem - min_elem; + + // check if a dimension of a largest span exists + size_t k = cutfeat; + for (size_t i=0; imax_span) { + computeMinMax(ind, count, i, min_elem, max_elem); + span = max_elem - min_elem; + if (span>max_span) { + max_span = span; + cutfeat = i; + cutval = (min_elem+max_elem)/2; + } + } + } + int lim1, lim2; + planeSplit(ind, count, cutfeat, cutval, lim1, lim2); + + if (lim1>count/2) index = lim1; + else if (lim2max_span) { + max_span = span; + } + } + DistanceType max_spread = -1; + cutfeat = 0; + for (size_t i=0; i(DistanceType)((1-EPS)*max_span)) { + ElementType min_elem, max_elem; + computeMinMax(ind, count, cutfeat, min_elem, max_elem); + DistanceType spread = (DistanceType)(max_elem-min_elem); + if (spread>max_spread) { + cutfeat = i; + max_spread = spread; + } + } + } + // split in the middle + DistanceType split_val = (bbox[cutfeat].low+bbox[cutfeat].high)/2; + ElementType min_elem, max_elem; + computeMinMax(ind, count, cutfeat, min_elem, max_elem); + + if (split_valmax_elem) cutval = (DistanceType)max_elem; + else cutval = split_val; + + int lim1, lim2; + planeSplit(ind, count, cutfeat, cutval, lim1, lim2); + + if (lim1>count/2) index = lim1; + else if (lim2cutval + */ + void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2) + { + /* Move vector indices for left subtree to front of list. */ + int left = 0; + int right = count-1; + for (;; ) { + while (left<=right && dataset_[ind[left]][cutfeat]=cutval) --right; + if (left>right) break; + std::swap(ind[left], ind[right]); ++left; --right; + } + /* If either list is empty, it means that all remaining features + * are identical. Split in the middle to maintain a balanced tree. + */ + lim1 = left; + right = count-1; + for (;; ) { + while (left<=right && dataset_[ind[left]][cutfeat]<=cutval) ++left; + while (left<=right && dataset_[ind[right]][cutfeat]>cutval) --right; + if (left>right) break; + std::swap(ind[left], ind[right]); ++left; --right; + } + lim2 = left; + } + + DistanceType computeInitialDistances(const ElementType* vec, std::vector& dists) + { + DistanceType distsq = 0.0; + + for (size_t i = 0; i < dim_; ++i) { + if (vec[i] < root_bbox_[i].low) { + dists[i] = distance_.accum_dist(vec[i], root_bbox_[i].low, i); + distsq += dists[i]; + } + if (vec[i] > root_bbox_[i].high) { + dists[i] = distance_.accum_dist(vec[i], root_bbox_[i].high, i); + distsq += dists[i]; + } + } + + return distsq; + } + + /** + * Performs an exact search in the tree starting from a node. + */ + void searchLevel(ResultSet& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq, + std::vector& dists, const float epsError) + { + /* If this is a leaf node, then do check and return. */ + if ((node->child1 == NULL)&&(node->child2 == NULL)) { + DistanceType worst_dist = result_set.worstDist(); + for (int i=node->left; iright; ++i) { + int index = reorder_ ? i : vind_[i]; + DistanceType dist = distance_(vec, data_[index], dim_, worst_dist); + if (distdivfeat; + ElementType val = vec[idx]; + DistanceType diff1 = val - node->divlow; + DistanceType diff2 = val - node->divhigh; + + NodePtr bestChild; + NodePtr otherChild; + DistanceType cut_dist; + if ((diff1+diff2)<0) { + bestChild = node->child1; + otherChild = node->child2; + cut_dist = distance_.accum_dist(val, node->divhigh, idx); + } + else { + bestChild = node->child2; + otherChild = node->child1; + cut_dist = distance_.accum_dist( val, node->divlow, idx); + } + + /* Call recursively to search next level down. */ + searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError); + + DistanceType dst = dists[idx]; + mindistsq = mindistsq + cut_dist - dst; + dists[idx] = cut_dist; + if (mindistsq*epsError<=result_set.worstDist()) { + searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError); + } + dists[idx] = dst; + } + +private: + + /** + * The dataset used by this index + */ + const Matrix dataset_; + + IndexParams index_params_; + + int leaf_max_size_; + bool reorder_; + + + /** + * Array of indices to vectors in the dataset. + */ + std::vector vind_; + + Matrix data_; + + size_t size_; + size_t dim_; + + /** + * Array of k-d trees used to find neighbours. + */ + NodePtr root_node_; + + BoundingBox root_bbox_; + + /** + * Pooled memory allocator. + * + * Using a pooled memory allocator is more efficient + * than allocating memory directly when there is a large + * number small of memory allocations. + */ + PooledAllocator pool_; + + Distance distance_; +}; // class KDTree + +} + +#endif //OPENCV_FLANN_KDTREE_SINGLE_INDEX_H_ diff --git a/modules/flann/include/opencv2/flann/kmeans_index.h b/modules/flann/include/opencv2/flann/kmeans_index.h index 67abba5447..624c27abe8 100644 --- a/modules/flann/include/opencv2/flann/kmeans_index.h +++ b/modules/flann/include/opencv2/flann/kmeans_index.h @@ -28,8 +28,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_KMEANSTREE_H_ -#define _OPENCV_KMEANSTREE_H_ +#ifndef OPENCV_FLANN_KMEANS_INDEX_H_ +#define OPENCV_FLANN_KMEANS_INDEX_H_ #include #include @@ -38,41 +38,36 @@ #include #include -#include "opencv2/flann/general.h" -#include "opencv2/flann/nn_index.h" -#include "opencv2/flann/matrix.h" -#include "opencv2/flann/result_set.h" -#include "opencv2/flann/heap.h" -#include "opencv2/flann/allocator.h" -#include "opencv2/flann/random.h" +#include "general.h" +#include "nn_index.h" +#include "dist.h" +#include "matrix.h" +#include "result_set.h" +#include "heap.h" +#include "allocator.h" +#include "random.h" +#include "saving.h" +#include "logger.h" namespace cvflann { -struct CV_EXPORTS KMeansIndexParams : public IndexParams { - KMeansIndexParams(int branching_ = 32, int iterations_ = 11, - flann_centers_init_t centers_init_ = FLANN_CENTERS_RANDOM, float cb_index_ = 0.2 ) : - IndexParams(FLANN_INDEX_KMEANS), - branching(branching_), - iterations(iterations_), - centers_init(centers_init_), - cb_index(cb_index_) {}; - - int branching; // branching factor (for kmeans tree) - int iterations; // max iterations to perform in one kmeans clustering (kmeans tree) - flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree - float cb_index; // cluster boundary index. Used when searching the kmeans tree - - void print() const - { - logger().info("Index type: %d\n",(int)algorithm); - logger().info("Branching: %d\n", branching); - logger().info("Iterations: %d\n", iterations); - logger().info("Centres initialisation: %d\n", centers_init); - logger().info("Cluster boundary weight: %g\n", cb_index); - } - +struct KMeansIndexParams : public IndexParams +{ + KMeansIndexParams(int branching = 32, int iterations = 11, + flann_centers_init_t centers_init = FLANN_CENTERS_RANDOM, float cb_index = 0.2 ) + { + (*this)["algorithm"] = FLANN_INDEX_KMEANS; + // branching factor + (*this)["branching"] = branching; + // max iterations to perform in one kmeans clustering (kmeans tree) + (*this)["iterations"] = iterations; + // algorithm used for picking the initial cluster centers for kmeans tree + (*this)["centers_init"] = centers_init; + // cluster boundary index. Used when searching the kmeans tree + (*this)["cb_index"] = cb_index; + } }; @@ -82,145 +77,40 @@ struct CV_EXPORTS KMeansIndexParams : public IndexParams { * Contains a tree constructed through a hierarchical kmeans clustering * and other information for indexing a set of points for nearest-neighbour matching. */ -template ::type > -class KMeansIndex : public NNIndex +template +class KMeansIndex : public NNIndex { +public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; - /** - * The branching factor used in the hierarchical k-means clustering - */ - int branching; - /** - * Maximum number of iterations to use when performing k-means - * clustering - */ - int max_iter; - /** - * Cluster border index. This is used in the tree search phase when determining - * the closest cluster to explore next. A zero value takes into account only - * the cluster centres, a value greater then zero also take into account the size - * of the cluster. + typedef void (KMeansIndex::* centersAlgFunction)(int, int*, int, int*, int&); + + /** + * The function used for choosing the cluster centers. */ - float cb_index; - - /** - * The dataset used by this index - */ - const Matrix dataset; - - const IndexParams& index_params; - - /** - * Number of features in the dataset. - */ - size_t size_; - - /** - * Length of each feature. - */ - size_t veclen_; - - - /** - * Struture representing a node in the hierarchical k-means tree. - */ - struct KMeansNodeSt { - /** - * The cluster center. - */ - DIST_TYPE* pivot; - /** - * The cluster radius. - */ - DIST_TYPE radius; - /** - * The cluster mean radius. - */ - DIST_TYPE mean_radius; - /** - * The cluster variance. - */ - DIST_TYPE variance; - /** - * The cluster size (number of points in the cluster) - */ - int size; - /** - * Child nodes (only for non-terminal nodes) - */ - KMeansNodeSt** childs; - /** - * Node points (only for terminal nodes) - */ - int* indices; - /** - * Level - */ - int level; - }; - typedef KMeansNodeSt* KMeansNode; - - - - /** - * Alias definition for a nicer syntax. - */ - typedef BranchStruct BranchSt; - - - /** - * The root node in the tree. - */ - KMeansNode root; - - /** - * Array of indices to vectors in the dataset. - */ - int* indices; - - - /** - * Pooled memory allocator. - * - * Using a pooled memory allocator is more efficient - * than allocating memory directly when there is a large - * number small of memory allocations. - */ - PooledAllocator pool; - - /** - * Memory occupied by the index. - */ - int memoryCounter; - - - typedef void (KMeansIndex::*centersAlgFunction)(int, int*, int, int*, int&); - - /** - * The function used for choosing the cluster centers. - */ centersAlgFunction chooseCenters; /** - * Chooses the initial centers in the k-means clustering in a random manner. - * - * Params: - * k = number of centers - * vecs = the dataset of points - * indices = indices in the dataset - * indices_length = length of indices vector - * - */ + * Chooses the initial centers in the k-means clustering in a random manner. + * + * Params: + * k = number of centers + * vecs = the dataset of points + * indices = indices in the dataset + * indices_length = length of indices vector + * + */ void chooseCentersRandom(int k, int* indices, int indices_length, int* centers, int& centers_length) { UniqueRandom r(indices_length); int index; - for (index=0;index centers[index] = indices[rnd]; - for (int j=0;j /** - * Chooses the initial centers in the k-means using Gonzales' algorithm - * so that the centers are spaced apart from each other. - * - * Params: - * k = number of centers - * vecs = the dataset of points - * indices = indices in the dataset - * Returns: - */ + * Chooses the initial centers in the k-means using Gonzales' algorithm + * so that the centers are spaced apart from each other. + * + * Params: + * k = number of centers + * vecs = the dataset of points + * indices = indices in the dataset + * Returns: + */ void chooseCentersGonzales(int k, int* indices, int indices_length, int* centers, int& centers_length) { int n = indices_length; @@ -269,11 +159,11 @@ class KMeansIndex : public NNIndex for (index=1; index /** - * Chooses the initial centers in the k-means using the algorithm - * proposed in the KMeans++ paper: - * Arthur, David; Vassilvitskii, Sergei - k-means++: The Advantages of Careful Seeding - * - * Implementation of this function was converted from the one provided in Arthur's code. - * - * Params: - * k = number of centers - * vecs = the dataset of points - * indices = indices in the dataset - * Returns: - */ + * Chooses the initial centers in the k-means using the algorithm + * proposed in the KMeans++ paper: + * Arthur, David; Vassilvitskii, Sergei - k-means++: The Advantages of Careful Seeding + * + * Implementation of this function was converted from the one provided in Arthur's code. + * + * Params: + * k = number of centers + * vecs = the dataset of points + * indices = indices in the dataset + * Returns: + */ void chooseCentersKMeanspp(int k, int* indices, int indices_length, int* centers, int& centers_length) { int n = indices_length; double currentPot = 0; - double* closestDistSq = new double[n]; + DistanceType* closestDistSq = new DistanceType[n]; // Choose one random center and set the closestDistSq values int index = rand_int(n); @@ -320,7 +210,7 @@ class KMeansIndex : public NNIndex centers[0] = indices[index]; for (int i = 0; i < n; i++) { - closestDistSq[i] = flann_dist(dataset[indices[i]], dataset[indices[i]] + dataset.cols, dataset[indices[index]]); + closestDistSq[i] = distance_(dataset_[indices[i]], dataset_[indices[index]], dataset_.cols); currentPot += closestDistSq[i]; } @@ -338,21 +228,18 @@ class KMeansIndex : public NNIndex // Choose our center - have to be slightly careful to return a valid answer even accounting // for possible rounding errors - double randVal = rand_double(currentPot); + double randVal = rand_double(currentPot); for (index = 0; index < n-1; index++) { - if (randVal <= closestDistSq[index]) - break; - else - randVal -= closestDistSq[index]; + if (randVal <= closestDistSq[index]) break; + else randVal -= closestDistSq[index]; } // Compute the new potential double newPot = 0; - for (int i = 0; i < n; i++) - newPot += std::min( flann_dist(dataset[indices[i]], dataset[indices[i]] + dataset.cols, dataset[indices[index]]), closestDistSq[i] ); + for (int i = 0; i < n; i++) newPot += std::min( distance_(dataset_[indices[i]], dataset_[indices[index]], dataset_.cols), closestDistSq[i] ); // Store the best result - if (bestNewPot < 0 || newPot < bestNewPot) { + if ((bestNewPot < 0)||(newPot < bestNewPot)) { bestNewPot = newPot; bestNewIndex = index; } @@ -361,90 +248,93 @@ class KMeansIndex : public NNIndex // Add the appropriate center centers[centerCount] = indices[bestNewIndex]; currentPot = bestNewPot; - for (int i = 0; i < n; i++) - closestDistSq[i] = std::min( flann_dist(dataset[indices[i]], dataset[indices[i]]+dataset.cols, dataset[indices[bestNewIndex]]), closestDistSq[i] ); + for (int i = 0; i < n; i++) closestDistSq[i] = std::min( distance_(dataset_[indices[i]], dataset_[indices[bestNewIndex]], dataset_.cols), closestDistSq[i] ); } centers_length = centerCount; - delete[] closestDistSq; + delete[] closestDistSq; } public: - flann_algorithm_t getType() const { return FLANN_INDEX_KMEANS; } - /** - * Index constructor - * - * Params: - * inputData = dataset with the input features - * params = parameters passed to the hierarchical k-means algorithm - */ - KMeansIndex(const Matrix& inputData, const KMeansIndexParams& params = KMeansIndexParams() ) - : dataset(inputData), index_params(params), root(NULL), indices(NULL) - { - memoryCounter = 0; + /** + * Index constructor + * + * Params: + * inputData = dataset with the input features + * params = parameters passed to the hierarchical k-means algorithm + */ + KMeansIndex(const Matrix& inputData, const IndexParams& params = KMeansIndexParams(), + Distance d = Distance()) + : dataset_(inputData), index_params_(params), root_(NULL), indices_(NULL), distance_(d) + { + memoryCounter_ = 0; - size_ = dataset.rows; - veclen_ = dataset.cols; + size_ = dataset_.rows; + veclen_ = dataset_.cols; - branching = params.branching; - max_iter = params.iterations; - if (max_iter<0) { - max_iter = (std::numeric_limits::max)(); + branching_ = get_param(params,"branching",32); + iterations_ = get_param(params,"iterations",11); + if (iterations_<0) { + iterations_ = (std::numeric_limits::max)(); } - flann_centers_init_t centersInit = params.centers_init; + centers_init_ = get_param(params,"centers_init",FLANN_CENTERS_RANDOM); - if (centersInit==FLANN_CENTERS_RANDOM) { - chooseCenters = &KMeansIndex::chooseCentersRandom; + if (centers_init_==FLANN_CENTERS_RANDOM) { + chooseCenters = &KMeansIndex::chooseCentersRandom; } - else if (centersInit==FLANN_CENTERS_GONZALES) { - chooseCenters = &KMeansIndex::chooseCentersGonzales; + else if (centers_init_==FLANN_CENTERS_GONZALES) { + chooseCenters = &KMeansIndex::chooseCentersGonzales; } - else if (centersInit==FLANN_CENTERS_KMEANSPP) { - chooseCenters = &KMeansIndex::chooseCentersKMeanspp; + else if (centers_init_==FLANN_CENTERS_KMEANSPP) { + chooseCenters = &KMeansIndex::chooseCentersKMeanspp; } - else { - throw FLANNException("Unknown algorithm for choosing initial centers."); - } - cb_index = 0.4f; + else { + throw FLANNException("Unknown algorithm for choosing initial centers."); + } + cb_index_ = 0.4f; - } + } - /** - * Index destructor. - * - * Release the memory used by the index. - */ - virtual ~KMeansIndex() - { - if (root != NULL) { - free_centers(root); - } - if (indices!=NULL) { - delete[] indices; - } - } + KMeansIndex(const KMeansIndex&); + KMeansIndex& operator=(const KMeansIndex&); + /** - * Returns size of index. - */ - size_t size() const + * Index destructor. + * + * Release the memory used by the index. + */ + virtual ~KMeansIndex() + { + if (root_ != NULL) { + free_centers(root_); + } + if (indices_!=NULL) { + delete[] indices_; + } + } + + /** + * Returns size of index. + */ + size_t size() const { return size_; } /** - * Returns the length of an index feature. - */ + * Returns the length of an index feature. + */ size_t veclen() const { return veclen_; @@ -453,67 +343,73 @@ public: void set_cb_index( float index) { - cb_index = index; + cb_index_ = index; } + /** + * Computes the inde memory usage + * Returns: memory used by the index + */ + int usedMemory() const + { + return pool_.usedMemory+pool_.wastedMemory+memoryCounter_; + } - /** - * Computes the inde memory usage - * Returns: memory used by the index - */ - int usedMemory() const - { - return pool.usedMemory+pool.wastedMemory+memoryCounter; - } + /** + * Builds the index + */ + void buildIndex() + { + if (branching_<2) { + throw FLANNException("Branching factor must be at least 2"); + } - /** - * Builds the index - */ - void buildIndex() - { - if (branching<2) { - throw FLANNException("Branching factor must be at least 2"); - } + indices_ = new int[size_]; + for (size_t i=0; i(); - computeNodeStatistics(root, indices, (int)size_); - computeClustering(root, indices, (int)size_, branching,0); - } + root_ = pool_.allocate(); + computeNodeStatistics(root_, indices_, (int)size_); + computeClustering(root_, indices_, (int)size_, branching_,0); + } void saveIndex(FILE* stream) { - save_value(stream, branching); - save_value(stream, max_iter); - save_value(stream, memoryCounter); - save_value(stream, cb_index); - save_value(stream, *indices, (int)size_); + save_value(stream, branching_); + save_value(stream, iterations_); + save_value(stream, memoryCounter_); + save_value(stream, cb_index_); + save_value(stream, *indices_, (int)size_); - save_tree(stream, root); + save_tree(stream, root_); } void loadIndex(FILE* stream) { - load_value(stream, branching); - load_value(stream, max_iter); - load_value(stream, memoryCounter); - load_value(stream, cb_index); - if (indices!=NULL) { - delete[] indices; - } - indices = new int[size_]; - load_value(stream, *indices, (int)size_); + load_value(stream, branching_); + load_value(stream, iterations_); + load_value(stream, memoryCounter_); + load_value(stream, cb_index_); + if (indices_!=NULL) { + delete[] indices_; + } + indices_ = new int[size_]; + load_value(stream, *indices_, size_); + + if (root_!=NULL) { + free_centers(root_); + } + load_tree(stream, root_); + + index_params_["algorithm"] = getType(); + index_params_["branching"] = branching_; + index_params_["iterations"] = iterations_; + index_params_["centers_init"] = centers_init_; + index_params_["cb_index"] = cb_index_; - if (root!=NULL) { - free_centers(root); - } - load_tree(stream, root); } @@ -526,25 +422,24 @@ public: * vec = the vector for which to search the nearest neighbors * searchParams = parameters that influence the search algorithm (checks, cb_index) */ - void findNeighbors(ResultSet& result, const ELEM_TYPE* vec, const SearchParams& searchParams) + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) { - int maxChecks = searchParams.checks; + int maxChecks = get_param(searchParams,"checks",32); - if (maxChecks<0) { - findExactNN(root, result, vec); + if (maxChecks==FLANN_CHECKS_UNLIMITED) { + findExactNN(root_, result, vec); } else { - // Priority queue storing intermediate branches in the best-bin-first search + // Priority queue storing intermediate branches in the best-bin-first search Heap* heap = new Heap((int)size_); int checks = 0; - - findNN(root, result, vec, checks, maxChecks, heap); + findNN(root_, result, vec, checks, maxChecks, heap); BranchSt branch; while (heap->popMin(branch) && (checks& centers) + int getClusterCenters(Matrix& centers) { int numClusters = centers.rows; if (numClusters<1) { throw FLANNException("Number of clusters must be at least 1"); } - float variance; - KMeansNode* clusters = new KMeansNode[numClusters]; + DistanceType variance; + KMeansNodePtr* clusters = new KMeansNodePtr[numClusters]; - int clusterCount = getMinVarianceClusters(root, clusters, numClusters, variance); + int clusterCount = getMinVarianceClusters(root_, clusters, numClusters, variance); -// logger().info("Clusters requested: %d, returning %d\n",numClusters, clusterCount); + Logger::info("Clusters requested: %d, returning %d\n",numClusters, clusterCount); - - for (int i=0;ipivot; - for (size_t j=0;jpivot; + for (size_t j=0; jpivot), (int)veclen_); - if (node->childs==NULL) { - int indices_offset = (int)(node->indices - indices); - save_value(stream, indices_offset); - } - else { - for(int i=0; ichilds[i]); - } - } + return index_params_; } - void load_tree(FILE* stream, KMeansNode& node) +private: + /** + * Struture representing a node in the hierarchical k-means tree. + */ + struct KMeansNode { - node = pool.allocate(); - load_value(stream, *node); - node->pivot = new DIST_TYPE[veclen_]; - load_value(stream, *(node->pivot), (int)veclen_); - if (node->childs==NULL) { - int indices_offset; - load_value(stream, indices_offset); - node->indices = indices + indices_offset; - } - else { - node->childs = pool.allocate(branching); - for(int i=0; ichilds[i]); - } - } + /** + * The cluster center. + */ + DistanceType* pivot; + /** + * The cluster radius. + */ + DistanceType radius; + /** + * The cluster mean radius. + */ + DistanceType mean_radius; + /** + * The cluster variance. + */ + DistanceType variance; + /** + * The cluster size (number of points in the cluster) + */ + int size; + /** + * Child nodes (only for non-terminal nodes) + */ + KMeansNode** childs; + /** + * Node points (only for terminal nodes) + */ + int* indices; + /** + * Level + */ + int level; + }; + typedef KMeansNode* KMeansNodePtr; + + /** + * Alias definition for a nicer syntax. + */ + typedef BranchStruct BranchSt; + + + + + void save_tree(FILE* stream, KMeansNodePtr node) + { + save_value(stream, *node); + save_value(stream, *(node->pivot), (int)veclen_); + if (node->childs==NULL) { + int indices_offset = (int)(node->indices - indices_); + save_value(stream, indices_offset); + } + else { + for(int i=0; ichilds[i]); + } + } + } + + + void load_tree(FILE* stream, KMeansNodePtr& node) + { + node = pool_.allocate(); + load_value(stream, *node); + node->pivot = new DistanceType[veclen_]; + load_value(stream, *(node->pivot), (int)veclen_); + if (node->childs==NULL) { + int indices_offset; + load_value(stream, indices_offset); + node->indices = indices_ + indices_offset; + } + else { + node->childs = pool_.allocate(branching_); + for(int i=0; ichilds[i]); + } + } } /** - * Helper function - */ - void free_centers(KMeansNode node) + * Helper function + */ + void free_centers(KMeansNodePtr node) { delete[] node->pivot; if (node->childs!=NULL) { - for (int k=0;kchilds[k]); } } } - /** - * Computes the statistics of a node (mean, radius, variance). - * - * Params: - * node = the node to use - * indices = the indices of the points belonging to the node - */ - void computeNodeStatistics(KMeansNode node, int* indices, int indices_length) { + /** + * Computes the statistics of a node (mean, radius, variance). + * + * Params: + * node = the node to use + * indices = the indices of the points belonging to the node + */ + void computeNodeStatistics(KMeansNodePtr node, int* indices, int indices_length) + { - double radius = 0; - double variance = 0; - DIST_TYPE* mean = new DIST_TYPE[veclen_]; - memoryCounter += (int)(veclen_*sizeof(DIST_TYPE)); + DistanceType radius = 0; + DistanceType variance = 0; + DistanceType* mean = new DistanceType[veclen_]; + memoryCounter_ += int(veclen_*sizeof(DistanceType)); - memset(mean,0,veclen_*sizeof(float)); + memset(mean,0,veclen_*sizeof(DistanceType)); - for (size_t i=0;i(), veclen_); + } + for (size_t j=0; j(), veclen_); - double tmp = 0; - for (int i=0;iradius) { - radius = tmp; - } - } + DistanceType tmp = 0; + for (int i=0; iradius) { + radius = tmp; + } + } - node->variance = (DIST_TYPE)variance; - node->radius = (DIST_TYPE)radius; - node->pivot = mean; - } + node->variance = variance; + node->radius = radius; + node->pivot = mean; + } - /** - * The method responsible with actually doing the recursive hierarchical - * clustering - * - * Params: - * node = the node to cluster - * indices = indices of the points belonging to the current node - * branching = the branching factor to use in the clustering - * - * TODO: for 1-sized clusters don't store a cluster center (it's the same as the single cluster point) - */ - void computeClustering(KMeansNode node, int* indices, int indices_length, int branching, int level) - { - node->size = indices_length; - node->level = level; + /** + * The method responsible with actually doing the recursive hierarchical + * clustering + * + * Params: + * node = the node to cluster + * indices = indices of the points belonging to the current node + * branching = the branching factor to use in the clustering + * + * TODO: for 1-sized clusters don't store a cluster center (it's the same as the single cluster point) + */ + void computeClustering(KMeansNodePtr node, int* indices, int indices_length, int branching, int level) + { + node->size = indices_length; + node->level = level; - if (indices_length < branching) { - node->indices = indices; - std::sort(node->indices,node->indices+indices_length); - node->childs = NULL; - return; - } - - int* centers_idx = new int[branching]; - int centers_length; - (this->*chooseCenters)(branching, indices, indices_length, centers_idx, centers_length); - - if (centers_lengthindices = indices; std::sort(node->indices,node->indices+indices_length); node->childs = NULL; - return; - } + return; + } + + int* centers_idx = new int[branching]; + int centers_length; + (this->*chooseCenters)(branching, indices, indices_length, centers_idx, centers_length); + + if (centers_lengthindices = indices; + std::sort(node->indices,node->indices+indices_length); + node->childs = NULL; + delete [] centers_idx; + return; + } - Matrix dcenters(new double[branching*veclen_],branching,(long)veclen_); + Matrix dcenters(new double[branching*veclen_],branching,veclen_); for (int i=0; inew_sq_dist) { - belongs_to[i] = j; - sq_dist = new_sq_dist; - } - } - if (sq_dist>radiuses[belongs_to[i]]) { - radiuses[belongs_to[i]] = (float)sq_dist; + DistanceType sq_dist = distance_(dataset_[indices[i]], dcenters[0], veclen_); + belongs_to[i] = 0; + for (int j=1; jnew_sq_dist) { + belongs_to[i] = j; + sq_dist = new_sq_dist; + } } - count[belongs_to[i]]++; - } + if (sq_dist>radiuses[belongs_to[i]]) { + radiuses[belongs_to[i]] = sq_dist; + } + count[belongs_to[i]]++; + } - bool converged = false; - int iteration = 0; - while (!converged && iterationnew_sq_dist) { - new_centroid = j; - sq_dist = new_sq_dist; - } - } - if (sq_dist>radiuses[new_centroid]) { - radiuses[new_centroid] = sq_dist; - } - if (new_centroid != belongs_to[i]) { - count[belongs_to[i]]--; - count[new_centroid]++; - belongs_to[i] = new_centroid; + // reassign points to clusters + for (int i=0; inew_sq_dist) { + new_centroid = j; + sq_dist = new_sq_dist; + } + } + if (sq_dist>radiuses[new_centroid]) { + radiuses[new_centroid] = sq_dist; + } + if (new_centroid != belongs_to[i]) { + count[belongs_to[i]]--; + count[new_centroid]++; + belongs_to[i] = new_centroid; - converged = false; - } - } + converged = false; + } + } - for (int i=0;ichilds = pool.allocate(branching); - int start = 0; - int end = start; - for (int c=0;cchilds = pool_.allocate(branching); + int start = 0; + int end = start; + for (int c=0; c(), veclen_); + variance += d; + mean_radius += sqrt(d); std::swap(indices[i],indices[end]); std::swap(belongs_to[i],belongs_to[end]); - end++; - } - } - variance /= s; - mean_radius /= s; - variance -= flann_dist(centers[c],centers[c]+veclen_,zero()); + end++; + } + } + variance /= s; + mean_radius /= s; + variance -= distance_(centers[c], ZeroIterator(), veclen_); - node->childs[c] = pool.allocate(); - node->childs[c]->radius = radiuses[c]; - node->childs[c]->pivot = centers[c]; - node->childs[c]->variance = (float)variance; - node->childs[c]->mean_radius = (float)mean_radius; - node->childs[c]->indices = NULL; - computeClustering(node->childs[c],indices+start, end-start, branching, level+1); - start=end; - } + node->childs[c] = pool_.allocate(); + node->childs[c]->radius = radiuses[c]; + node->childs[c]->pivot = centers[c]; + node->childs[c]->variance = variance; + node->childs[c]->mean_radius = mean_radius; + node->childs[c]->indices = NULL; + computeClustering(node->childs[c],indices+start, end-start, branching, level+1); + start=end; + } - delete[] dcenters.data; - delete[] centers; - delete[] radiuses; - delete[] count; - delete[] belongs_to; - } + delete[] dcenters.data; + delete[] centers; + delete[] radiuses; + delete[] count; + delete[] belongs_to; + } - /** - * Performs one descent in the hierarchical k-means tree. The branches not - * visited are stored in a priority queue. + /** + * Performs one descent in the hierarchical k-means tree. The branches not + * visited are stored in a priority queue. * * Params: * node = node to explore @@ -898,218 +837,279 @@ private: */ - void findNN(KMeansNode node, ResultSet& result, const ELEM_TYPE* vec, int& checks, int maxChecks, - Heap* heap) - { - // Ignore those clusters that are too far away - { - DIST_TYPE bsq = (DIST_TYPE)flann_dist(vec, vec+veclen_, node->pivot); - DIST_TYPE rsq = node->radius; - DIST_TYPE wsq = result.worstDist(); + void findNN(KMeansNodePtr node, ResultSet& result, const ElementType* vec, int& checks, int maxChecks, + Heap* heap) + { + // Ignore those clusters that are too far away + { + DistanceType bsq = distance_(vec, node->pivot, veclen_); + DistanceType rsq = node->radius; + DistanceType wsq = result.worstDist(); - DIST_TYPE val = bsq-rsq-wsq; - DIST_TYPE val2 = val*val-4*rsq*wsq; + DistanceType val = bsq-rsq-wsq; + DistanceType val2 = val*val-4*rsq*wsq; - //if (val>0) { - if (val>0 && val2>0) { - return; - } - } + //if (val>0) { + if ((val>0)&&(val2>0)) { + return; + } + } - if (node->childs==NULL) { + if (node->childs==NULL) { if (checks>=maxChecks) { if (result.full()) return; } checks += node->size; - for (int i=0;isize;++i) { - result.addPoint(dataset[node->indices[i]], node->indices[i]); - } - } - else { - float* domain_distances = new float[branching]; - int closest_center = exploreNodeBranches(node, vec, domain_distances, heap); - delete[] domain_distances; - findNN(node->childs[closest_center],result,vec, checks, maxChecks, heap); - } - } + for (int i=0; isize; ++i) { + int index = node->indices[i]; + DistanceType dist = distance_(dataset_[index], vec, veclen_); + result.addPoint(dist, index); + } + } + else { + DistanceType* domain_distances = new DistanceType[branching_]; + int closest_center = exploreNodeBranches(node, vec, domain_distances, heap); + delete[] domain_distances; + findNN(node->childs[closest_center],result,vec, checks, maxChecks, heap); + } + } - /** - * Helper function that computes the nearest childs of a node to a given query point. - * Params: - * node = the node - * q = the query point - * distances = array with the distances to each child node. - * Returns: - */ - int exploreNodeBranches(KMeansNode node, const ELEM_TYPE* q, float* domain_distances, Heap* heap) - { + /** + * Helper function that computes the nearest childs of a node to a given query point. + * Params: + * node = the node + * q = the query point + * distances = array with the distances to each child node. + * Returns: + */ + int exploreNodeBranches(KMeansNodePtr node, const ElementType* q, DistanceType* domain_distances, Heap* heap) + { - int best_index = 0; - domain_distances[best_index] = (float)flann_dist(q,q+veclen_,node->childs[best_index]->pivot); - for (int i=1;ichilds[i]->pivot); - if (domain_distances[i]childs[best_index]->pivot, veclen_); + for (int i=1; ichilds[i]->pivot, veclen_); + if (domain_distances[i]childs[best_index]->pivot; - for (int i=0;ichilds[i]->variance; + // float* best_center = node->childs[best_index]->pivot; + for (int i=0; ichilds[i]->variance; -// float dist_to_border = getDistanceToBorder(node.childs[i].pivot,best_center,q); -// if (domain_distances[i]insert(BranchSt::make_branch(node->childs[i],domain_distances[i])); - } - } + // float dist_to_border = getDistanceToBorder(node.childs[i].pivot,best_center,q); + // if (domain_distances[i]insert(BranchSt(node->childs[i],domain_distances[i])); + } + } - return best_index; - } + return best_index; + } - /** - * Function the performs exact nearest neighbor search by traversing the entire tree. - */ - void findExactNN(KMeansNode node, ResultSet& result, const ELEM_TYPE* vec) - { - // Ignore those clusters that are too far away - { - float bsq = (float)flann_dist(vec, vec+veclen_, node->pivot); - float rsq = node->radius; - float wsq = result.worstDist(); + /** + * Function the performs exact nearest neighbor search by traversing the entire tree. + */ + void findExactNN(KMeansNodePtr node, ResultSet& result, const ElementType* vec) + { + // Ignore those clusters that are too far away + { + DistanceType bsq = distance_(vec, node->pivot, veclen_); + DistanceType rsq = node->radius; + DistanceType wsq = result.worstDist(); - float val = bsq-rsq-wsq; - float val2 = val*val-4*rsq*wsq; + DistanceType val = bsq-rsq-wsq; + DistanceType val2 = val*val-4*rsq*wsq; - // if (val>0) { - if (val>0 && val2>0) { - return; - } - } + // if (val>0) { + if ((val>0)&&(val2>0)) { + return; + } + } - if (node->childs==NULL) { - for (int i=0;isize;++i) { - result.addPoint(dataset[node->indices[i]], node->indices[i]); - } - } - else { - int* sort_indices = new int[branching]; + if (node->childs==NULL) { + for (int i=0; isize; ++i) { + int index = node->indices[i]; + DistanceType dist = distance_(dataset_[index], vec, veclen_); + result.addPoint(dist, index); + } + } + else { + int* sort_indices = new int[branching_]; - getCenterOrdering(node, vec, sort_indices); + getCenterOrdering(node, vec, sort_indices); - for (int i=0; ichilds[sort_indices[i]],result,vec); - } + for (int i=0; ichilds[sort_indices[i]],result,vec); + } - delete[] sort_indices; - } - } + delete[] sort_indices; + } + } - /** - * Helper function. - * - * I computes the order in which to traverse the child nodes of a particular node. - */ - void getCenterOrdering(KMeansNode node, const ELEM_TYPE* q, int* sort_indices) - { - float* domain_distances = new float[branching]; - for (int i=0;ichilds[i]->pivot); + /** + * Helper function. + * + * I computes the order in which to traverse the child nodes of a particular node. + */ + void getCenterOrdering(KMeansNodePtr node, const ElementType* q, int* sort_indices) + { + DistanceType* domain_distances = new DistanceType[branching_]; + for (int i=0; ichilds[i]->pivot, veclen_); - int j=0; - while (domain_distances[j]j;--k) { - domain_distances[k] = domain_distances[k-1]; - sort_indices[k] = sort_indices[k-1]; - } - domain_distances[j] = dist; - sort_indices[j] = i; - } - delete[] domain_distances; - } + int j=0; + while (domain_distances[j]j; --k) { + domain_distances[k] = domain_distances[k-1]; + sort_indices[k] = sort_indices[k-1]; + } + domain_distances[j] = dist; + sort_indices[j] = i; + } + delete[] domain_distances; + } - /** - * Method that computes the squared distance from the query point q - * from inside region with center c to the border between this - * region and the region with center p - */ - float getDistanceToBorder(float* p, float* c, float* q) - { - float sum = 0; - float sum2 = 0; + /** + * Method that computes the squared distance from the query point q + * from inside region with center c to the border between this + * region and the region with center p + */ + DistanceType getDistanceToBorder(DistanceType* p, DistanceType* c, DistanceType* q) + { + DistanceType sum = 0; + DistanceType sum2 = 0; - for (int i=0;ivariance*root->size; + DistanceType meanVariance = root->variance*root->size; - while (clusterCount::max)(); - int splitIndex = -1; + while (clusterCount::max)(); + int splitIndex = -1; - for (int i=0;ichilds != NULL) { + for (int i=0; ichilds != NULL) { - float variance = meanVariance - clusters[i]->variance*clusters[i]->size; + DistanceType variance = meanVariance - clusters[i]->variance*clusters[i]->size; - for (int j=0;jchilds[j]->variance*clusters[i]->childs[j]->size; - } - if (variancechilds[j]->variance*clusters[i]->childs[j]->size; + } + if (variance clusters_length) break; + if (splitIndex==-1) break; + if ( (branching_+clusterCount-1) > clusters_length) break; - meanVariance = minVariance; + meanVariance = minVariance; - // split node - KMeansNode toSplit = clusters[splitIndex]; - clusters[splitIndex] = toSplit->childs[0]; - for (int i=1;ichilds[i]; - } - } + // split node + KMeansNodePtr toSplit = clusters[splitIndex]; + clusters[splitIndex] = toSplit->childs[0]; + for (int i=1; ichilds[i]; + } + } - varianceValue = meanVariance/root->size; - return clusterCount; - } + varianceValue = meanVariance/root->size; + return clusterCount; + } + +private: + /** The branching factor used in the hierarchical k-means clustering */ + int branching_; + + /** Maximum number of iterations to use when performing k-means clustering */ + int iterations_; + + /** Algorithm for choosing the cluster centers */ + flann_centers_init_t centers_init_; + + /** + * Cluster border index. This is used in the tree search phase when determining + * the closest cluster to explore next. A zero value takes into account only + * the cluster centres, a value greater then zero also take into account the size + * of the cluster. + */ + float cb_index_; + + /** + * The dataset used by this index + */ + const Matrix dataset_; + + /** Index parameters */ + IndexParams index_params_; + + /** + * Number of features in the dataset. + */ + size_t size_; + + /** + * Length of each feature. + */ + size_t veclen_; + + /** + * The root node in the tree. + */ + KMeansNodePtr root_; + + /** + * Array of indices to vectors in the dataset. + */ + int* indices_; + + /** + * The distance + */ + Distance distance_; + + /** + * Pooled memory allocator. + */ + PooledAllocator pool_; + + /** + * Memory occupied by the index. + */ + int memoryCounter_; }; +} - -//register_index(KMEANS,KMeansTree) - -} // namespace cvflann - -#endif //_OPENCV_KMEANSTREE_H_ +#endif //OPENCV_FLANN_KMEANS_INDEX_H_ diff --git a/modules/flann/include/opencv2/flann/linear_index.h b/modules/flann/include/opencv2/flann/linear_index.h index 3a17ade65e..ecb99f281b 100644 --- a/modules/flann/include/opencv2/flann/linear_index.h +++ b/modules/flann/include/opencv2/flann/linear_index.h @@ -28,41 +28,40 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_LINEARSEARCH_H_ -#define _OPENCV_LINEARSEARCH_H_ - -#include "opencv2/flann/general.h" -#include "opencv2/flann/nn_index.h" +#ifndef OPENCV_FLANN_LINEAR_INDEX_H_ +#define OPENCV_FLANN_LINEAR_INDEX_H_ +#include "general.h" +#include "nn_index.h" namespace cvflann { -struct CV_EXPORTS LinearIndexParams : public IndexParams { - LinearIndexParams() : IndexParams(FLANN_INDEX_LINEAR) {}; - - void print() const - { - logger().info("Index type: %d\n",(int)algorithm); - } +struct LinearIndexParams : public IndexParams +{ + LinearIndexParams() + { + (* this)["algorithm"] = FLANN_INDEX_LINEAR; + } }; - -template ::type > -class LinearIndex : public NNIndex +template +class LinearIndex : public NNIndex { - const Matrix dataset; - const LinearIndexParams& index_params; - - LinearIndex(const LinearIndex&); - LinearIndex& operator=(const LinearIndex&); - public: - LinearIndex(const Matrix& inputData, const LinearIndexParams& params = LinearIndexParams() ) : - dataset(inputData), index_params(params) - { - } + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + + + LinearIndex(const Matrix& inputData, const IndexParams& params = LinearIndexParams(), + Distance d = Distance()) : + dataset_(inputData), index_params_(params), distance_(d) + { + } + + LinearIndex(const LinearIndex&); + LinearIndex& operator=(const LinearIndex&); flann_algorithm_t getType() const { @@ -70,52 +69,64 @@ public: } - size_t size() const - { - return dataset.rows; - } + size_t size() const + { + return dataset_.rows; + } - size_t veclen() const - { - return dataset.cols; - } + size_t veclen() const + { + return dataset_.cols; + } - int usedMemory() const - { - return 0; - } + int usedMemory() const + { + return 0; + } - void buildIndex() - { - /* nothing to do here for linear search */ - } + void buildIndex() + { + /* nothing to do here for linear search */ + } void saveIndex(FILE*) { - /* nothing to do here for linear search */ + /* nothing to do here for linear search */ } void loadIndex(FILE*) { - /* nothing to do here for linear search */ + /* nothing to do here for linear search */ + + index_params_["algorithm"] = getType(); } - void findNeighbors(ResultSet& resultSet, const ELEM_TYPE*, const SearchParams&) - { - for (size_t i=0;i& resultSet, const ElementType* vec, const SearchParams& /*searchParams*/) + { + ElementType* data = dataset_.data; + for (size_t i = 0; i < dataset_.rows; ++i, data += dataset_.cols) { + DistanceType dist = distance_(data, vec, dataset_.cols); + resultSet.addPoint(dist, i); + } + } - const IndexParams* getParameters() const - { - return &index_params; - } + IndexParams getParameters() const + { + return index_params_; + } + +private: + /** The dataset */ + const Matrix dataset_; + /** Index parameters */ + IndexParams index_params_; + /** Index distance */ + Distance distance_; }; -} // namespace cvflann +} -#endif // _OPENCV_LINEARSEARCH_H_ +#endif // OPENCV_FLANN_LINEAR_INDEX_H_ diff --git a/modules/flann/include/opencv2/flann/logger.h b/modules/flann/include/opencv2/flann/logger.h index 979756d305..303f0c99fc 100644 --- a/modules/flann/include/opencv2/flann/logger.h +++ b/modules/flann/include/opencv2/flann/logger.h @@ -28,40 +28,36 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_LOGGER_H_ -#define _OPENCV_LOGGER_H_ +#ifndef FLANN_LOGGER_H +#define FLANN_LOGGER_H -#include +#include #include +#include "defines.h" + + namespace cvflann { - -enum flann_log_level_t { - FLANN_LOG_NONE = 0, - FLANN_LOG_FATAL = 1, - FLANN_LOG_ERROR = 2, - FLANN_LOG_WARN = 3, - FLANN_LOG_INFO = 4 -}; - -class CV_EXPORTS Logger + +class Logger { - FILE* stream; - int logLevel; - -public: - - Logger() : stream(stdout), logLevel(FLANN_LOG_WARN) {}; + Logger() : stream(stdout), logLevel(FLANN_LOG_WARN) {} ~Logger() { - if (stream!=NULL && stream!=stdout) { + if ((stream!=NULL)&&(stream!=stdout)) { fclose(stream); } } - void setDestination(const char* name) + static Logger& instance() + { + static Logger logger; + return logger; + } + + void _setDestination(const char* name) { if (name==NULL) { stream = stdout; @@ -74,23 +70,61 @@ public: } } - void setLevel(int level) { logLevel = level; } + int _log(int level, const char* fmt, va_list arglist) + { + if (level > logLevel ) return -1; + int ret = vfprintf(stream, fmt, arglist); + return ret; + } - int log(int level, const char* fmt, ...); +public: + /** + * Sets the logging level. All messages with lower priority will be ignored. + * @param level Logging level + */ + static void setLevel(int level) { instance().logLevel = level; } - int log(int level, const char* fmt, va_list arglist); + /** + * Sets the logging destination + * @param name Filename or NULL for console + */ + static void setDestination(const char* name) { instance()._setDestination(name); } - int fatal(const char* fmt, ...); + /** + * Print log message + * @param level Log level + * @param fmt Message format + * @return + */ + static int log(int level, const char* fmt, ...) + { + va_list arglist; + va_start(arglist, fmt); + int ret = instance()._log(level,fmt,arglist); + va_end(arglist); + return ret; + } - int error(const char* fmt, ...); +#define LOG_METHOD(NAME,LEVEL) \ + static int NAME(const char* fmt, ...) \ + { \ + va_list ap; \ + va_start(ap, fmt); \ + int ret = instance()._log(LEVEL, fmt, ap); \ + va_end(ap); \ + return ret; \ + } - int warn(const char* fmt, ...); + LOG_METHOD(fatal, FLANN_LOG_FATAL) + LOG_METHOD(error, FLANN_LOG_ERROR) + LOG_METHOD(warn, FLANN_LOG_WARN) + LOG_METHOD(info, FLANN_LOG_INFO) - int info(const char* fmt, ...); +private: + FILE* stream; + int logLevel; }; -CV_EXPORTS Logger& logger(); +} -} // namespace cvflann - -#endif //_OPENCV_LOGGER_H_ +#endif //FLANN_LOGGER_H diff --git a/modules/flann/include/opencv2/flann/lsh_index.h b/modules/flann/include/opencv2/flann/lsh_index.h new file mode 100644 index 0000000000..a777990934 --- /dev/null +++ b/modules/flann/include/opencv2/flann/lsh_index.h @@ -0,0 +1,388 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +/*********************************************************************** + * Author: Vincent Rabaud + *************************************************************************/ + +#ifndef OPENCV_FLANN_LSH_INDEX_H_ +#define OPENCV_FLANN_LSH_INDEX_H_ + +#include +#include +#include +#include +#include + +#include "general.h" +#include "nn_index.h" +#include "matrix.h" +#include "result_set.h" +#include "heap.h" +#include "lsh_table.h" +#include "allocator.h" +#include "random.h" +#include "saving.h" + +namespace cvflann +{ + +struct LshIndexParams : public IndexParams +{ + LshIndexParams(unsigned int table_number, unsigned int key_size, unsigned int multi_probe_level) + { + (* this)["algorithm"] = FLANN_INDEX_LSH; + // The number of hash tables to use + (*this)["table_number"] = table_number; + // The length of the key in the hash tables + (*this)["key_size"] = key_size; + // Number of levels to use in multi-probe (0 for standard LSH) + (*this)["multi_probe_level"] = multi_probe_level; + } +}; + +/** + * Randomized kd-tree index + * + * Contains the k-d trees and other information for indexing a set of points + * for nearest-neighbor matching. + */ +template +class LshIndex : public NNIndex +{ +public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + + /** Constructor + * @param input_data dataset with the input features + * @param params parameters passed to the LSH algorithm + * @param d the distance used + */ + LshIndex(const Matrix& input_data, const IndexParams& params = LshIndexParams(), + Distance d = Distance()) : + dataset_(input_data), index_params_(params), distance_(d) + { + table_number_ = get_param(index_params_,"table_number",12); + key_size_ = get_param(index_params_,"key_size",20); + multi_probe_level_ = get_param(index_params_,"multi_probe_level",2); + + feature_size_ = dataset_.cols; + fill_xor_mask(0, key_size_, multi_probe_level_, xor_masks_); + } + + + LshIndex(const LshIndex&); + LshIndex& operator=(const LshIndex&); + + /** + * Builds the index + */ + void buildIndex() + { + tables_.resize(table_number_); + for (unsigned int i = 0; i < table_number_; ++i) { + lsh::LshTable& table = tables_[i]; + table = lsh::LshTable(feature_size_, key_size_); + + // Add the features to the table + table.add(dataset_); + } + } + + flann_algorithm_t getType() const + { + return FLANN_INDEX_LSH; + } + + + void saveIndex(FILE* stream) + { + save_value(stream,table_number_); + save_value(stream,key_size_); + save_value(stream,multi_probe_level_); + save_value(stream, dataset_); + } + + void loadIndex(FILE* stream) + { + load_value(stream, table_number_); + load_value(stream, key_size_); + load_value(stream, multi_probe_level_); + load_value(stream, dataset_); + // Building the index is so fast we can afford not storing it + buildIndex(); + + index_params_["algorithm"] = getType(); + index_params_["table_number"] = table_number_; + index_params_["key_size"] = key_size_; + index_params_["multi_probe_level"] = multi_probe_level_; + } + + /** + * Returns size of index. + */ + size_t size() const + { + return dataset_.rows; + } + + /** + * Returns the length of an index feature. + */ + size_t veclen() const + { + return feature_size_; + } + + /** + * Computes the index memory usage + * Returns: memory used by the index + */ + int usedMemory() const + { + return dataset_.rows * sizeof(int); + } + + + IndexParams getParameters() const + { + return index_params_; + } + + /** + * \brief Perform k-nearest neighbor search + * \param[in] queries The query points for which to find the nearest neighbors + * \param[out] indices The indices of the nearest neighbors found + * \param[out] dists Distances to the nearest neighbors found + * \param[in] knn Number of nearest neighbors to return + * \param[in] params Search parameters + */ + virtual void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + { + assert(queries.cols == veclen()); + assert(indices.rows >= queries.rows); + assert(dists.rows >= queries.rows); + assert(int(indices.cols) >= knn); + assert(int(dists.cols) >= knn); + + + KNNUniqueResultSet resultSet(knn); + for (size_t i = 0; i < queries.rows; i++) { + resultSet.clear(); + findNeighbors(resultSet, queries[i], params); + if (get_param(params,"sorted",true)) resultSet.sortAndCopy(indices[i], dists[i], knn); + else resultSet.copy(indices[i], dists[i], knn); + } + } + + + /** + * Find set of nearest neighbors to vec. Their indices are stored inside + * the result object. + * + * Params: + * result = the result object in which the indices of the nearest-neighbors are stored + * vec = the vector for which to search the nearest neighbors + * maxCheck = the maximum number of restarts (in a best-bin-first manner) + */ + void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& /*searchParams*/) + { + getNeighbors(vec, result); + } + +private: + /** Defines the comparator on score and index + */ + typedef std::pair ScoreIndexPair; + struct SortScoreIndexPairOnSecond + { + bool operator()(const ScoreIndexPair& left, const ScoreIndexPair& right) const + { + return left.second < right.second; + } + }; + + /** Fills the different xor masks to use when getting the neighbors in multi-probe LSH + * @param key the key we build neighbors from + * @param lowest_index the lowest index of the bit set + * @param level the multi-probe level we are at + * @param xor_masks all the xor mask + */ + void fill_xor_mask(lsh::BucketKey key, int lowest_index, unsigned int level, + std::vector& xor_masks) + { + xor_masks.push_back(key); + if (level == 0) return; + for (int index = lowest_index - 1; index >= 0; --index) { + // Create a new key + lsh::BucketKey new_key = key | (1 << index); + fill_xor_mask(new_key, index, level - 1, xor_masks); + } + } + + /** Performs the approximate nearest-neighbor search. + * @param vec the feature to analyze + * @param do_radius flag indicating if we check the radius too + * @param radius the radius if it is a radius search + * @param do_k flag indicating if we limit the number of nn + * @param k_nn the number of nearest neighbors + * @param checked_average used for debugging + */ + void getNeighbors(const ElementType* vec, bool do_radius, float radius, bool do_k, unsigned int k_nn, + float& checked_average) + { + static std::vector score_index_heap; + + if (do_k) { + unsigned int worst_score = std::numeric_limits::max(); + typename std::vector >::const_iterator table = tables_.begin(); + typename std::vector >::const_iterator table_end = tables_.end(); + for (; table != table_end; ++table) { + size_t key = table->getKey(vec); + std::vector::const_iterator xor_mask = xor_masks_.begin(); + std::vector::const_iterator xor_mask_end = xor_masks_.end(); + for (; xor_mask != xor_mask_end; ++xor_mask) { + size_t sub_key = key ^ (*xor_mask); + const lsh::Bucket* bucket = table->getBucketFromKey(sub_key); + if (bucket == 0) continue; + + // Go over each descriptor index + std::vector::const_iterator training_index = bucket->begin(); + std::vector::const_iterator last_training_index = bucket->end(); + DistanceType hamming_distance; + + // Process the rest of the candidates + for (; training_index < last_training_index; ++training_index) { + hamming_distance = distance_(vec, dataset_[*training_index], dataset_.cols); + + if (hamming_distance < worst_score) { + // Insert the new element + score_index_heap.push_back(ScoreIndexPair(hamming_distance, training_index)); + std::push_heap(score_index_heap.begin(), score_index_heap.end()); + + if (score_index_heap.size() > (unsigned int)k_nn) { + // Remove the highest distance value as we have too many elements + std::pop_heap(score_index_heap.begin(), score_index_heap.end()); + score_index_heap.pop_back(); + // Keep track of the worst score + worst_score = score_index_heap.front().first; + } + } + } + } + } + } + else { + typename std::vector >::const_iterator table = tables_.begin(); + typename std::vector >::const_iterator table_end = tables_.end(); + for (; table != table_end; ++table) { + size_t key = table->getKey(vec); + std::vector::const_iterator xor_mask = xor_masks_.begin(); + std::vector::const_iterator xor_mask_end = xor_masks_.end(); + for (; xor_mask != xor_mask_end; ++xor_mask) { + size_t sub_key = key ^ (*xor_mask); + const lsh::Bucket* bucket = table->getBucketFromKey(sub_key); + if (bucket == 0) continue; + + // Go over each descriptor index + std::vector::const_iterator training_index = bucket->begin(); + std::vector::const_iterator last_training_index = bucket->end(); + DistanceType hamming_distance; + + // Process the rest of the candidates + for (; training_index < last_training_index; ++training_index) { + // Compute the Hamming distance + hamming_distance = distance_(vec, dataset_[*training_index], dataset_.cols); + if (hamming_distance < radius) score_index_heap.push_back(ScoreIndexPair(hamming_distance, training_index)); + } + } + } + } + } + + /** Performs the approximate nearest-neighbor search. + * This is a slower version than the above as it uses the ResultSet + * @param vec the feature to analyze + */ + void getNeighbors(const ElementType* vec, ResultSet& result) + { + typename std::vector >::const_iterator table = tables_.begin(); + typename std::vector >::const_iterator table_end = tables_.end(); + for (; table != table_end; ++table) { + size_t key = table->getKey(vec); + std::vector::const_iterator xor_mask = xor_masks_.begin(); + std::vector::const_iterator xor_mask_end = xor_masks_.end(); + for (; xor_mask != xor_mask_end; ++xor_mask) { + size_t sub_key = key ^ (*xor_mask); + const lsh::Bucket* bucket = table->getBucketFromKey(sub_key); + if (bucket == 0) continue; + + // Go over each descriptor index + std::vector::const_iterator training_index = bucket->begin(); + std::vector::const_iterator last_training_index = bucket->end(); + DistanceType hamming_distance; + + // Process the rest of the candidates + for (; training_index < last_training_index; ++training_index) { + // Compute the Hamming distance + hamming_distance = distance_(vec, dataset_[*training_index], dataset_.cols); + result.addPoint(hamming_distance, *training_index); + } + } + } + } + + /** The different hash tables */ + std::vector > tables_; + + /** The data the LSH tables where built from */ + Matrix dataset_; + + /** The size of the features (as ElementType[]) */ + unsigned int feature_size_; + + IndexParams index_params_; + + /** table number */ + unsigned int table_number_; + /** key size */ + unsigned int key_size_; + /** How far should we look for neighbors in multi-probe LSH */ + unsigned int multi_probe_level_; + + /** The XOR masks to apply to a key to get the neighboring buckets */ + std::vector xor_masks_; + + Distance distance_; +}; +} + +#endif //OPENCV_FLANN_LSH_INDEX_H_ diff --git a/modules/flann/include/opencv2/flann/lsh_table.h b/modules/flann/include/opencv2/flann/lsh_table.h new file mode 100644 index 0000000000..f52d5bd9ea --- /dev/null +++ b/modules/flann/include/opencv2/flann/lsh_table.h @@ -0,0 +1,477 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +/*********************************************************************** + * Author: Vincent Rabaud + *************************************************************************/ + +#ifndef OPENCV_FLANN_LSH_TABLE_H_ +#define OPENCV_FLANN_LSH_TABLE_H_ + +#include +#include +#include +#include +// TODO as soon as we use C++0x, use the code in USE_UNORDERED_MAP +#if USE_UNORDERED_MAP +#include +#else +#include +#endif +#include +#include + +#include "dynamic_bitset.h" +#include "matrix.h" + +namespace cvflann +{ + +namespace lsh +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** What is stored in an LSH bucket + */ +typedef uint32_t FeatureIndex; +/** The id from which we can get a bucket back in an LSH table + */ +typedef unsigned int BucketKey; + +/** A bucket in an LSH table + */ +typedef std::vector Bucket; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** POD for stats about an LSH table + */ +struct LshStats +{ + std::vector bucket_sizes_; + size_t n_buckets_; + size_t bucket_size_mean_; + size_t bucket_size_median_; + size_t bucket_size_min_; + size_t bucket_size_max_; + size_t bucket_size_std_dev; + /** Each contained vector contains three value: beginning/end for interval, number of elements in the bin + */ + std::vector > size_histogram_; +}; + +/** Overload the << operator for LshStats + * @param out the streams + * @param stats the stats to display + * @return the streams + */ +inline std::ostream& operator <<(std::ostream& out, const LshStats& stats) +{ + size_t w = 20; + out << "Lsh Table Stats:\n" << std::setw(w) << std::setiosflags(std::ios::right) << "N buckets : " + << stats.n_buckets_ << "\n" << std::setw(w) << std::setiosflags(std::ios::right) << "mean size : " + << std::setiosflags(std::ios::left) << stats.bucket_size_mean_ << "\n" << std::setw(w) + << std::setiosflags(std::ios::right) << "median size : " << stats.bucket_size_median_ << "\n" << std::setw(w) + << std::setiosflags(std::ios::right) << "min size : " << std::setiosflags(std::ios::left) + << stats.bucket_size_min_ << "\n" << std::setw(w) << std::setiosflags(std::ios::right) << "max size : " + << std::setiosflags(std::ios::left) << stats.bucket_size_max_; + + // Display the histogram + out << std::endl << std::setw(w) << std::setiosflags(std::ios::right) << "histogram : " + << std::setiosflags(std::ios::left); + for (std::vector >::const_iterator iterator = stats.size_histogram_.begin(), end = + stats.size_histogram_.end(); iterator != end; ++iterator) out << (*iterator)[0] << "-" << (*iterator)[1] << ": " << (*iterator)[2] << ", "; + + return out; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** Lsh hash table. As its key is a sub-feature, and as usually + * the size of it is pretty small, we keep it as a continuous memory array. + * The value is an index in the corpus of features (we keep it as an unsigned + * int for pure memory reasons, it could be a size_t) + */ +template +class LshTable +{ +public: + /** A container of all the feature indices. Optimized for space + */ +#if USE_UNORDERED_MAP + typedef std::unordered_map BucketsSpace; +#else + typedef std::map BucketsSpace; +#endif + + /** A container of all the feature indices. Optimized for speed + */ + typedef std::vector BucketsSpeed; + + /** Default constructor + */ + LshTable() + { + } + + /** Default constructor + * Create the mask and allocate the memory + * @param feature_size is the size of the feature (considered as a ElementType[]) + * @param key_size is the number of bits that are turned on in the feature + */ + LshTable(unsigned int /*feature_size*/, unsigned int /*key_size*/) + { + std::cerr << "LSH is not implemented for that type" << std::endl; + throw; + } + + /** Add a feature to the table + * @param value the value to store for that feature + * @param feature the feature itself + */ + void add(unsigned int value, const ElementType* feature) + { + // Add the value to the corresponding bucket + BucketKey key = getKey(feature); + + switch (speed_level_) { + case kArray: + // That means we get the buckets from an array + buckets_speed_[key].push_back(value); + break; + case kBitsetHash: + // That means we can check the bitset for the presence of a key + key_bitset_.set(key); + buckets_space_[key].push_back(value); + break; + case kHash: + { + // That means we have to check for the hash table for the presence of a key + buckets_space_[key].push_back(value); + break; + } + } + } + + /** Add a set of features to the table + * @param dataset the values to store + */ + void add(Matrix dataset) + { +#if USE_UNORDERED_MAP + if (!use_speed_) buckets_space_.rehash((buckets_space_.size() + dataset.rows) * 1.2); +#endif + // Add the features to the table + for (unsigned int i = 0; i < dataset.rows; ++i) add(i, dataset[i]); + // Now that the table is full, optimize it for speed/space + optimize(); + } + + /** Get a bucket given the key + * @param key + * @return + */ + inline const Bucket* getBucketFromKey(BucketKey key) const + { + // Generate other buckets + switch (speed_level_) { + case kArray: + // That means we get the buckets from an array + return &buckets_speed_[key]; + break; + case kBitsetHash: + // That means we can check the bitset for the presence of a key + if (key_bitset_.test(key)) return &buckets_space_.find(key)->second; + else return 0; + break; + case kHash: + { + // That means we have to check for the hash table for the presence of a key + BucketsSpace::const_iterator bucket_it, bucket_end = buckets_space_.end(); + bucket_it = buckets_space_.find(key); + // Stop here if that bucket does not exist + if (bucket_it == bucket_end) return 0; + else return &bucket_it->second; + break; + } + } + return 0; + } + + /** Compute the sub-signature of a feature + */ + size_t getKey(const ElementType* /*feature*/) const + { + std::cerr << "LSH is not implemented for that type" << std::endl; + throw; + return 1; + } + + /** Get statistics about the table + * @return + */ + LshStats getStats() const; + +private: + /** defines the speed fo the implementation + * kArray uses a vector for storing data + * kBitsetHash uses a hash map but checks for the validity of a key with a bitset + * kHash uses a hash map only + */ + enum SpeedLevel + { + kArray, kBitsetHash, kHash + }; + + /** Initialize some variables + */ + void initialize(size_t key_size) + { + speed_level_ = kHash; + key_size_ = key_size; + } + + /** Optimize the table for speed/space + */ + void optimize() + { + // If we are already using the fast storage, no need to do anything + if (speed_level_ == kArray) return; + + // Use an array if it will be more than half full + if (buckets_space_.size() > (unsigned int)((1 << key_size_) / 2)) { + speed_level_ = kArray; + // Fill the array version of it + buckets_speed_.resize(1 << key_size_); + for (BucketsSpace::const_iterator key_bucket = buckets_space_.begin(); key_bucket != buckets_space_.end(); ++key_bucket) buckets_speed_[key_bucket->first] = key_bucket->second; + + // Empty the hash table + buckets_space_.clear(); + return; + } + + // If the bitset is going to use less than 10% of the RAM of the hash map (at least 1 size_t for the key and two + // for the vector) or less than 512MB (key_size_ <= 30) + if (((std::max(buckets_space_.size(), buckets_speed_.size()) * CHAR_BIT * 3 * sizeof(BucketKey)) / 10 + >= size_t(1 << key_size_)) || (key_size_ <= 32)) { + speed_level_ = kBitsetHash; + key_bitset_.resize(1 << key_size_); + key_bitset_.reset(); + // Try with the BucketsSpace + for (BucketsSpace::const_iterator key_bucket = buckets_space_.begin(); key_bucket != buckets_space_.end(); ++key_bucket) key_bitset_.set(key_bucket->first); + } + else { + speed_level_ = kHash; + key_bitset_.clear(); + } + } + + /** The vector of all the buckets if they are held for speed + */ + BucketsSpeed buckets_speed_; + + /** The hash table of all the buckets in case we cannot use the speed version + */ + BucketsSpace buckets_space_; + + /** What is used to store the data */ + SpeedLevel speed_level_; + + /** If the subkey is small enough, it will keep track of which subkeys are set through that bitset + * That is just a speedup so that we don't look in the hash table (which can be mush slower that checking a bitset) + */ + DynamicBitset key_bitset_; + + /** The size of the sub-signature in bits + */ + unsigned int key_size_; + + // Members only used for the unsigned char specialization + /** The mask to apply to a feature to get the hash key + * Only used in the unsigned char case + */ + std::vector mask_; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Specialization for unsigned char + +template<> +inline LshTable::LshTable(unsigned int feature_size, unsigned int subsignature_size) +{ + initialize(subsignature_size); + // Allocate the mask + mask_ = std::vector((size_t)ceil((float)(feature_size * sizeof(char)) / (float)sizeof(size_t)), 0); + + // A bit brutal but fast to code + std::vector indices(feature_size * CHAR_BIT); + for (size_t i = 0; i < feature_size * CHAR_BIT; ++i) indices[i] = i; + std::random_shuffle(indices.begin(), indices.end()); + + // Generate a random set of order of subsignature_size_ bits + for (unsigned int i = 0; i < key_size_; ++i) { + size_t index = indices[i]; + + // Set that bit in the mask + size_t divisor = CHAR_BIT * sizeof(size_t); + size_t idx = index / divisor; //pick the right size_t index + mask_[idx] |= size_t(1) << (index % divisor); //use modulo to find the bit offset + } + + // Set to 1 if you want to display the mask for debug +#if 0 + { + size_t bcount = 0; + BOOST_FOREACH(size_t mask_block, mask_){ + out << std::setw(sizeof(size_t) * CHAR_BIT / 4) << std::setfill('0') << std::hex << mask_block + << std::endl; + bcount += __builtin_popcountll(mask_block); + } + out << "bit count : " << std::dec << bcount << std::endl; + out << "mask size : " << mask_.size() << std::endl; + return out; + } +#endif +} + +/** Return the Subsignature of a feature + * @param feature the feature to analyze + */ +template<> +inline size_t LshTable::getKey(const unsigned char* feature) const +{ + // no need to check if T is dividable by sizeof(size_t) like in the Hamming + // distance computation as we have a mask + const size_t* feature_block_ptr = reinterpret_cast (feature); + + // Figure out the subsignature of the feature + // Given the feature ABCDEF, and the mask 001011, the output will be + // 000CEF + size_t subsignature = 0; + size_t bit_index = 1; + + for (std::vector::const_iterator pmask_block = mask_.begin(); pmask_block != mask_.end(); ++pmask_block) { + // get the mask and signature blocks + size_t feature_block = *feature_block_ptr; + size_t mask_block = *pmask_block; + while (mask_block) { + // Get the lowest set bit in the mask block + size_t lowest_bit = mask_block & (-(ptrdiff_t)mask_block); + // Add it to the current subsignature if necessary + subsignature += (feature_block & lowest_bit) ? bit_index : 0; + // Reset the bit in the mask block + mask_block ^= lowest_bit; + // increment the bit index for the subsignature + bit_index <<= 1; + } + // Check the next feature block + ++feature_block_ptr; + } + return subsignature; +} + +template<> +inline LshStats LshTable::getStats() const +{ + LshStats stats; + stats.bucket_size_mean_ = 0; + if ((buckets_speed_.empty()) && (buckets_space_.empty())) { + stats.n_buckets_ = 0; + stats.bucket_size_median_ = 0; + stats.bucket_size_min_ = 0; + stats.bucket_size_max_ = 0; + return stats; + } + + if (!buckets_speed_.empty()) { + for (BucketsSpeed::const_iterator pbucket = buckets_speed_.begin(); pbucket != buckets_speed_.end(); ++pbucket) { + stats.bucket_sizes_.push_back(pbucket->size()); + stats.bucket_size_mean_ += pbucket->size(); + } + stats.bucket_size_mean_ /= buckets_speed_.size(); + stats.n_buckets_ = buckets_speed_.size(); + } + else { + for (BucketsSpace::const_iterator x = buckets_space_.begin(); x != buckets_space_.end(); ++x) { + stats.bucket_sizes_.push_back(x->second.size()); + stats.bucket_size_mean_ += x->second.size(); + } + stats.bucket_size_mean_ /= buckets_space_.size(); + stats.n_buckets_ = buckets_space_.size(); + } + + std::sort(stats.bucket_sizes_.begin(), stats.bucket_sizes_.end()); + + // BOOST_FOREACH(int size, stats.bucket_sizes_) + // std::cout << size << " "; + // std::cout << std::endl; + stats.bucket_size_median_ = stats.bucket_sizes_[stats.bucket_sizes_.size() / 2]; + stats.bucket_size_min_ = stats.bucket_sizes_.front(); + stats.bucket_size_max_ = stats.bucket_sizes_.back(); + + // TODO compute mean and std + /*float mean, stddev; + stats.bucket_size_mean_ = mean; + stats.bucket_size_std_dev = stddev;*/ + + // Include a histogram of the buckets + unsigned int bin_start = 0; + unsigned int bin_end = 20; + bool is_new_bin = true; + for (std::vector::iterator iterator = stats.bucket_sizes_.begin(), end = stats.bucket_sizes_.end(); iterator + != end; ) + if (*iterator < bin_end) { + if (is_new_bin) { + stats.size_histogram_.push_back(std::vector(3, 0)); + stats.size_histogram_.back()[0] = bin_start; + stats.size_histogram_.back()[1] = bin_end - 1; + is_new_bin = false; + } + ++stats.size_histogram_.back()[2]; + ++iterator; + } + else { + bin_start += 20; + bin_end += 20; + is_new_bin = true; + } + + return stats; +} + +// End the two namespaces +} +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif /* OPENCV_FLANN_LSH_TABLE_H_ */ diff --git a/modules/flann/include/opencv2/flann/matrix.h b/modules/flann/include/opencv2/flann/matrix.h index 170dc6ddc1..51b6c6352c 100644 --- a/modules/flann/include/opencv2/flann/matrix.h +++ b/modules/flann/include/opencv2/flann/matrix.h @@ -28,60 +28,58 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_DATASET_H_ -#define _OPENCV_DATASET_H_ +#ifndef OPENCV_FLANN_DATASET_H_ +#define OPENCV_FLANN_DATASET_H_ #include -#include "opencv2/flann/general.h" +#include "general.h" - -namespace cvflann +namespace cvflann { /** -* Class that implements a simple rectangular matrix stored in a memory buffer and -* provides convenient matrix-like access using the [] operators. -*/ + * Class that implements a simple rectangular matrix stored in a memory buffer and + * provides convenient matrix-like access using the [] operators. + */ template -class Matrix { +class Matrix +{ public: + typedef T type; + size_t rows; size_t cols; + size_t stride; T* data; - Matrix() : rows(0), cols(0), data(NULL) + Matrix() : rows(0), cols(0), stride(0), data(NULL) { } - Matrix(T* data_, long rows_, long cols_) : - rows(rows_), cols(cols_), data(data_) - { - } + Matrix(T* data_, size_t rows_, size_t cols_, size_t stride_ = 0) : + rows(rows_), cols(cols_), stride(stride_), data(data_) + { + if (stride==0) stride = cols; + } /** * Convenience function for deallocating the storage data. */ - void release() + FLANN_DEPRECATED void free() { - if (data!=NULL) delete[] data; + fprintf(stderr, "The cvflann::Matrix::free() method is deprecated " + "and it does not do any memory deallocation any more. You are" + "responsible for deallocating the matrix memory (by doing" + "'delete[] matrix.data' for example)"); } - ~Matrix() - { - } - /** - * Operator that return a (pointer to a) row of the data. - */ - T* operator[](size_t index) - { - return data+index*cols; - } - + * Operator that return a (pointer to a) row of the data. + */ T* operator[](size_t index) const { - return data+index*cols; + return data+index*stride; } }; @@ -95,7 +93,7 @@ public: flann_datatype_t type; UntypedMatrix(void* data_, long rows_, long cols_) : - rows(rows_), cols(cols_), data(data_) + rows(rows_), cols(cols_), data(data_) { } @@ -113,6 +111,6 @@ public: -} // namespace cvflann +} -#endif //_OPENCV_DATASET_H_ +#endif //OPENCV_FLANN_DATASET_H_ diff --git a/modules/flann/include/opencv2/flann/miniflann.hpp b/modules/flann/include/opencv2/flann/miniflann.hpp new file mode 100644 index 0000000000..b36cba1326 --- /dev/null +++ b/modules/flann/include/opencv2/flann/miniflann.hpp @@ -0,0 +1,158 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef _OPENCV_MINIFLANN_HPP_ +#define _OPENCV_MINIFLANN_HPP_ + +#ifdef __cplusplus + +#include "opencv2/core/core.hpp" +#include "opencv2/flann/defines.h" + +namespace cv +{ + +namespace flann +{ + using namespace cvflann; + + +struct CV_EXPORTS IndexParams +{ + IndexParams(); + ~IndexParams(); + + std::string getString(const std::string& key, const std::string& defaultVal=std::string()) const; + int getInt(const std::string& key, int defaultVal=-1) const; + double getDouble(const std::string& key, double defaultVal=-1) const; + + void setString(const std::string& key, const std::string& value); + void setInt(const std::string& key, int value); + void setDouble(const std::string& key, double value); + void setFloat(const std::string& key, float value); + void setBool(const std::string& key, bool value); + void setAlgorithm(const std::string& key, int value); + + void getAll(std::vector& names, + std::vector& types, + std::vector& strValues, + std::vector& numValues) const; + + void* params; +}; + +struct CV_EXPORTS KDTreeIndexParams : public IndexParams +{ + KDTreeIndexParams(int trees=4); +}; + +struct CV_EXPORTS LinearIndexParams : public IndexParams +{ + LinearIndexParams(); +}; + +struct CV_EXPORTS CompositeIndexParams : public IndexParams +{ + CompositeIndexParams(int trees = 4, int branching = 32, int iterations = 11, + cvflann::flann_centers_init_t centers_init = cvflann::FLANN_CENTERS_RANDOM, float cb_index = 0.2 ); +}; + +struct CV_EXPORTS AutotunedIndexParams : public IndexParams +{ + AutotunedIndexParams(float target_precision = 0.8, float build_weight = 0.01, + float memory_weight = 0, float sample_fraction = 0.1); +}; + +struct CV_EXPORTS KMeansIndexParams : public IndexParams +{ + KMeansIndexParams(int branching = 32, int iterations = 11, + cvflann::flann_centers_init_t centers_init = cvflann::FLANN_CENTERS_RANDOM, float cb_index = 0.2 ); +}; + +struct CV_EXPORTS LshIndexParams : public IndexParams +{ + LshIndexParams(int table_number, int key_size, int multi_probe_level); +}; + +struct CV_EXPORTS SavedIndexParams : public IndexParams +{ + SavedIndexParams(const std::string& filename); +}; + +struct CV_EXPORTS SearchParams : public IndexParams +{ + SearchParams( int checks = 32, float eps = 0, bool sorted = true ); +}; + +class CV_EXPORTS_W Index +{ +public: + CV_WRAP Index(); + CV_WRAP Index(InputArray features, const IndexParams& params, cvflann::flann_distance_t distType=cvflann::FLANN_DIST_L2); + virtual ~Index(); + + CV_WRAP virtual void build(InputArray features, const IndexParams& params, cvflann::flann_distance_t distType=cvflann::FLANN_DIST_L2); + CV_WRAP virtual void knnSearch(InputArray query, OutputArray indices, + OutputArray dists, int knn, const SearchParams& params=SearchParams()); + + CV_WRAP virtual int radiusSearch(InputArray query, OutputArray indices, + OutputArray dists, double radius, int maxResults, + const SearchParams& params=SearchParams()); + + CV_WRAP virtual void save(const std::string& filename) const; + CV_WRAP virtual bool load(InputArray features, const std::string& filename); + CV_WRAP virtual void release(); + CV_WRAP cvflann::flann_distance_t getDistance() const; + CV_WRAP cvflann::flann_algorithm_t getAlgorithm() const; + +protected: + cvflann::flann_distance_t distType; + cvflann::flann_algorithm_t algo; + int featureType; + void* index; +}; + +} } // namespace cv::flann + +#endif // __cplusplus + +#endif diff --git a/modules/flann/include/opencv2/flann/nn_index.h b/modules/flann/include/opencv2/flann/nn_index.h index 081f9aff6b..da4dd7f0d8 100644 --- a/modules/flann/include/opencv2/flann/nn_index.h +++ b/modules/flann/include/opencv2/flann/nn_index.h @@ -28,79 +28,152 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_NNINDEX_H_ -#define _OPENCV_NNINDEX_H_ +#ifndef FLANN_NNINDEX_H +#define FLANN_NNINDEX_H #include -#include "opencv2/flann/general.h" -#include "opencv2/flann/matrix.h" +#include "general.h" +#include "matrix.h" +#include "result_set.h" +#include "params.h" namespace cvflann { - -template -class ResultSet; - /** -* Nearest-neighbour index base class -*/ -template + * Nearest-neighbour index base class + */ +template class NNIndex { + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + public: - virtual ~NNIndex() {}; + virtual ~NNIndex() {} - /** - Method responsible with building the index. - */ - virtual void buildIndex() = 0; + /** + * \brief Builds the index + */ + virtual void buildIndex() = 0; - /** - Saves the index to a stream - */ - virtual void saveIndex(FILE* stream) = 0; + /** + * \brief Perform k-nearest neighbor search + * \param[in] queries The query points for which to find the nearest neighbors + * \param[out] indices The indices of the nearest neighbors found + * \param[out] dists Distances to the nearest neighbors found + * \param[in] knn Number of nearest neighbors to return + * \param[in] params Search parameters + */ + virtual void knnSearch(const Matrix& queries, Matrix& indices, Matrix& dists, int knn, const SearchParams& params) + { + assert(queries.cols == veclen()); + assert(indices.rows >= queries.rows); + assert(dists.rows >= queries.rows); + assert(int(indices.cols) >= knn); + assert(int(dists.cols) >= knn); - /** - Loads the index from a stream - */ - virtual void loadIndex(FILE* stream) = 0; +#if 0 + KNNResultSet resultSet(knn); + for (size_t i = 0; i < queries.rows; i++) { + resultSet.init(indices[i], dists[i]); + findNeighbors(resultSet, queries[i], params); + } +#else + KNNUniqueResultSet resultSet(knn); + for (size_t i = 0; i < queries.rows; i++) { + resultSet.clear(); + findNeighbors(resultSet, queries[i], params); + if (get_param(params,"sorted",true)) resultSet.sortAndCopy(indices[i], dists[i], knn); + else resultSet.copy(indices[i], dists[i], knn); + } +#endif + } - /** - Method that searches for nearest-neighbors - */ - virtual void findNeighbors(ResultSet& result, const ELEM_TYPE* vec, const SearchParams& searchParams) = 0; + /** + * \brief Perform radius search + * \param[in] query The query point + * \param[out] indices The indinces of the neighbors found within the given radius + * \param[out] dists The distances to the nearest neighbors found + * \param[in] radius The radius used for search + * \param[in] params Search parameters + * \returns Number of neighbors found + */ + virtual int radiusSearch(const Matrix& query, Matrix& indices, Matrix& dists, float radius, const SearchParams& params) + { + if (query.rows != 1) { + fprintf(stderr, "I can only search one feature at a time for range search\n"); + return -1; + } + assert(query.cols == veclen()); + assert(indices.cols == dists.cols); - /** - Number of features in this index. - */ - virtual size_t size() const = 0; + int n = 0; + int* indices_ptr = NULL; + DistanceType* dists_ptr = NULL; + if (indices.cols > 0) { + n = indices.cols; + indices_ptr = indices[0]; + dists_ptr = dists[0]; + } - /** - The length of each vector in this index. - */ - virtual size_t veclen() const = 0; + RadiusUniqueResultSet resultSet(radius); + resultSet.clear(); + findNeighbors(resultSet, query[0], params); + if (n>0) { + if (get_param(params,"sorted",true)) resultSet.sortAndCopy(indices_ptr, dists_ptr, n); + else resultSet.copy(indices_ptr, dists_ptr, n); + } - /** - The amount of memory (in bytes) this index uses. - */ - virtual int usedMemory() const = 0; + return resultSet.size(); + } - /** - * Algorithm name - */ - virtual flann_algorithm_t getType() const = 0; + /** + * \brief Saves the index to a stream + * \param stream The stream to save the index to + */ + virtual void saveIndex(FILE* stream) = 0; - /** - * Returns the parameters used for the index - */ - virtual const IndexParams* getParameters() const = 0; + /** + * \brief Loads the index from a stream + * \param stream The stream from which the index is loaded + */ + virtual void loadIndex(FILE* stream) = 0; + /** + * \returns number of features in this index. + */ + virtual size_t size() const = 0; + + /** + * \returns The dimensionality of the features in this index. + */ + virtual size_t veclen() const = 0; + + /** + * \returns The amount of memory (in bytes) used by the index. + */ + virtual int usedMemory() const = 0; + + /** + * \returns The index type (kdtree, kmeans,...) + */ + virtual flann_algorithm_t getType() const = 0; + + /** + * \returns The index parameters + */ + virtual IndexParams getParameters() const = 0; + + + /** + * \brief Method that searches for nearest-neighbours + */ + virtual void findNeighbors(ResultSet& result, const ElementType* vec, const SearchParams& searchParams) = 0; }; +} -} // namespace cvflann - -#endif //_OPENCV_NNINDEX_H_ +#endif //FLANN_NNINDEX_H diff --git a/modules/flann/include/opencv2/flann/object_factory.h b/modules/flann/include/opencv2/flann/object_factory.h index 5c51e0db90..7f971c5a31 100644 --- a/modules/flann/include/opencv2/flann/object_factory.h +++ b/modules/flann/include/opencv2/flann/object_factory.h @@ -28,67 +28,64 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_OBJECT_FACTORY_H_ -#define _OPENCV_OBJECT_FACTORY_H_ +#ifndef OPENCV_FLANN_OBJECT_FACTORY_H_ +#define OPENCV_FLANN_OBJECT_FACTORY_H_ -#include "opencv2/core/types_c.h" #include namespace cvflann { -template -BaseClass* createObject() +class CreatorNotFound { - return new DerivedClass(); -} - -template -class ObjectFactory -{ - typedef BaseClass* (*CreateObjectFunc)(); - std::map object_registry; - - // singleton class, private constructor - //ObjectFactory() {}; - -public: - typedef typename std::map::iterator Iterator; - - - template - bool register_(UniqueIdType id) - { - if (object_registry.find(id) != object_registry.end()) - return false; - - object_registry[id] = &createObject; - return true; - } - - bool unregister(UniqueIdType id) - { - return (object_registry.erase(id) == 1); - } - - BaseClass* create(UniqueIdType id) - { - Iterator iter = object_registry.find(id); - - if (iter == object_registry.end()) - return NULL; - - return ((*iter).second)(); - } - - /*static ObjectFactory& instance() - { - static ObjectFactory the_factory; - return the_factory; - }*/ - }; -} // namespace cvflann +template +class ObjectFactory +{ + typedef ObjectFactory ThisClass; + typedef std::map ObjectRegistry; -#endif /* OBJECT_FACTORY_H_ */ + // singleton class, private constructor + ObjectFactory() {} + +public: + + bool subscribe(UniqueIdType id, ObjectCreator creator) + { + if (object_registry.find(id) != object_registry.end()) return false; + + object_registry[id] = creator; + return true; + } + + bool unregister(UniqueIdType id) + { + return object_registry.erase(id) == 1; + } + + ObjectCreator create(UniqueIdType id) + { + typename ObjectRegistry::const_iterator iter = object_registry.find(id); + + if (iter == object_registry.end()) { + throw CreatorNotFound(); + } + + return iter->second; + } + + static ThisClass& instance() + { + static ThisClass the_factory; + return the_factory; + } +private: + ObjectRegistry object_registry; +}; + +} + +#endif /* OPENCV_FLANN_OBJECT_FACTORY_H_ */ diff --git a/modules/flann/include/opencv2/flann/params.h b/modules/flann/include/opencv2/flann/params.h new file mode 100644 index 0000000000..9f3a468c85 --- /dev/null +++ b/modules/flann/include/opencv2/flann/params.h @@ -0,0 +1,97 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2011 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2011 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + + +#ifndef OPENCV_FLANN_PARAMS_H_ +#define OPENCV_FLANN_PARAMS_H_ + +#include "any.h" +#include "general.h" +#include +#include + + +namespace cvflann +{ + +typedef cdiggins::any any; +typedef std::map IndexParams; + +struct SearchParams : public IndexParams +{ + SearchParams(int checks = 32, float eps = 0, bool sorted = true ) + { + // how many leafs to visit when searching for neighbours (-1 for unlimited) + (*this)["checks"] = checks; + // search for eps-approximate neighbours (default: 0) + (*this)["eps"] = eps; + // only for radius search, require neighbours sorted by distance (default: true) + (*this)["sorted"] = sorted; + } +}; + + +template +T get_param(const IndexParams& params, std::string name, const T& default_value) +{ + IndexParams::const_iterator it = params.find(name); + if (it != params.end()) { + return it->second.cast(); + } + else { + return default_value; + } +} + +template +T get_param(const IndexParams& params, std::string name) +{ + IndexParams::const_iterator it = params.find(name); + if (it != params.end()) { + return it->second.cast(); + } + else { + throw FLANNException(std::string("Missing parameter '")+name+std::string("' in the parameters given")); + } +} + +inline void print_params(const IndexParams& params) +{ + IndexParams::const_iterator it; + + for(it=params.begin(); it!=params.end(); ++it) { + std::cout << it->first << " : " << it->second << std::endl; + } +} + + + +} + + +#endif /* OPENCV_FLANN_PARAMS_H_ */ diff --git a/modules/flann/include/opencv2/flann/random.h b/modules/flann/include/opencv2/flann/random.h index d29a123963..b702807425 100644 --- a/modules/flann/include/opencv2/flann/random.h +++ b/modules/flann/include/opencv2/flann/random.h @@ -28,106 +28,108 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_RANDOM_H_ -#define _OPENCV_RANDOM_H_ +#ifndef FLANN_RANDOM_H +#define FLANN_RANDOM_H #include #include -#include +#include +#include "general.h" namespace cvflann { /** * Seeds the random number generator + * @param seed Random seed */ -CV_EXPORTS void seed_random(unsigned int seed); +inline void seed_random(unsigned int seed) +{ + srand(seed); +} /* * Generates a random double value. */ -CV_EXPORTS double rand_double(double high = 1.0, double low=0); - -/* - * Generates a random integer value. +/** + * Generates a random double value. + * @param high Upper limit + * @param low Lower limit + * @return Random double value */ -CV_EXPORTS int rand_int(int high = RAND_MAX, int low = 0); +inline double rand_double(double high = 1.0, double low = 0) +{ + return low + ((high-low) * (std::rand() / (RAND_MAX + 1.0))); +} +/** + * Generates a random integer value. + * @param high Upper limit + * @param low Lower limit + * @return Random integer value + */ +inline int rand_int(int high = RAND_MAX, int low = 0) +{ + return low + (int) ( double(high-low) * (std::rand() / (RAND_MAX + 1.0))); +} /** * Random number generator that returns a distinct number from * the [0,n) interval each time. - * - * TODO: improve on this to use a generator function instead of an - * array of randomly permuted numbers */ -class CV_EXPORTS UniqueRandom +class UniqueRandom { - int* vals; - int size; - int counter; + std::vector vals_; + int size_; + int counter_; public: - /** - * Constructor. - * Params: - * n = the size of the interval from which to generate - * random numbers. - */ - UniqueRandom(int n) : vals(NULL) { - init(n); - } + /** + * Constructor. + * @param n Size of the interval from which to generate + * @return + */ + UniqueRandom(int n) + { + init(n); + } - ~UniqueRandom() - { - delete[] vals; - } + /** + * Initializes the number generator. + * @param n the size of the interval from which to generate random numbers. + */ + void init(int n) + { + // create and initialize an array of size n + vals_.resize(n); + size_ = n; + for (int i = 0; i < size_; ++i) vals_[i] = i; - /** - * Initializes the number generator. - * Params: - * n = the size of the interval from which to generate - * random numbers. - */ - void init(int n) - { - // create and initialize an array of size n - if (vals == NULL || n!=size) { - delete[] vals; - size = n; - vals = new int[size]; - } - for(int i=0;i0;--i) { -// int rand = cast(int) (drand48() * n); - int rnd = rand_int(i); - assert(rnd >=0 && rnd < i); - std::swap(vals[i-1], vals[rnd]); - } + counter_ = 0; + } - counter = 0; - } - - /** - * Return a distinct random integer in greater or equal to 0 and less - * than 'n' on each call. It should be called maximum 'n' times. - * Returns: a random integer - */ - int next() { - if (counter==size) { - return -1; - } else { - return vals[counter++]; - } - } + /** + * Return a distinct random integer in greater or equal to 0 and less + * than 'n' on each call. It should be called maximum 'n' times. + * Returns: a random integer + */ + int next() + { + if (counter_ == size_) { + return -1; + } + else { + return vals_[counter_++]; + } + } }; -} // namespace cvflann +} + +#endif //FLANN_RANDOM_H + -#endif //_OPENCV_RANDOM_H_ diff --git a/modules/flann/include/opencv2/flann/result_set.h b/modules/flann/include/opencv2/flann/result_set.h index 5b1a8e2adb..047466faa7 100644 --- a/modules/flann/include/opencv2/flann/result_set.h +++ b/modules/flann/include/opencv2/flann/result_set.h @@ -28,291 +28,516 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_RESULTSET_H_ -#define _OPENCV_RESULTSET_H_ - +#ifndef FLANN_RESULTSET_H +#define FLANN_RESULTSET_H #include +#include +#include #include +#include #include -#include "opencv2/flann/dist.h" - namespace cvflann { /* This record represents a branch point when finding neighbors in - the tree. It contains a record of the minimum distance to the query - point, as well as the node at which the search resumes. -*/ + the tree. It contains a record of the minimum distance to the query + point, as well as the node at which the search resumes. + */ -template -struct BranchStruct { - T node; /* Tree node at which search resumes */ - float mindistsq; /* Minimum distance to query for all nodes below. */ +template +struct BranchStruct +{ + T node; /* Tree node at which search resumes */ + DistanceType mindist; /* Minimum distance to query for all nodes below. */ - bool operator<(const BranchStruct& rhs) - { - return mindistsq make_branch(const T& aNode, float dist) + bool operator<(const BranchStruct& rhs) const { - BranchStruct branch; - branch.node = aNode; - branch.mindistsq = dist; - return branch; + return mindist +template class ResultSet { -protected: - public: + virtual ~ResultSet() {} - virtual ~ResultSet() {}; + virtual bool full() const = 0; - virtual void init(const ELEM_TYPE* target_, int veclen_) = 0; + virtual void addPoint(DistanceType dist, int index) = 0; - virtual int* getNeighbors() = 0; - - virtual float* getDistances() = 0; - - virtual size_t size() const = 0; - - virtual bool full() const = 0; - - virtual bool addPoint(const ELEM_TYPE* point, int index) = 0; - - virtual float worstDist() const = 0; + virtual DistanceType worstDist() const = 0; }; - -template -class KNNResultSet : public ResultSet +/** + * KNNSimpleResultSet does not ensure that the element it holds are unique. + * Is used in those cases where the nearest neighbour algorithm used does not + * attempt to insert the same element multiple times. + */ +template +class KNNSimpleResultSet : public ResultSet { - const ELEM_TYPE* target; - const ELEM_TYPE* target_end; - int veclen; - - int* indices; - float* dists; + int* indices; + DistanceType* dists; int capacity; - - int count; + int count; + DistanceType worst_distance_; public: - KNNResultSet(int capacity_, ELEM_TYPE* target_ = NULL, int veclen_ = 0 ) : - target(target_), veclen(veclen_), capacity(capacity_), count(0) - { - target_end = target + veclen; - - indices = new int[capacity_]; - dists = new float[capacity_]; - } - - ~KNNResultSet() - { - delete[] indices; - delete[] dists; - } - - void init(const ELEM_TYPE* target_, int veclen_) - { - target = target_; - veclen = veclen_; - target_end = target + veclen; - count = 0; - } - - - int* getNeighbors() - { - return indices; - } - - float* getDistances() + KNNSimpleResultSet(int capacity_) : capacity(capacity_), count(0) { - return dists; + } + + void init(int* indices_, DistanceType* dists_) + { + indices = indices_; + dists = dists_; + count = 0; + worst_distance_ = (std::numeric_limits::max)(); + dists[capacity-1] = worst_distance_; } size_t size() const { - return count; + return count; } - bool full() const - { - return count == capacity; - } + bool full() const + { + return count == capacity; + } - bool addPoint(const ELEM_TYPE* point, int index) - { - for (int i=0;i= worst_distance_) return; + int i; + for (i=count; i>0; --i) { +#ifdef FLANN_FIRST_MATCH + if ( (dists[i-1]>dist) || ((dist==dists[i-1])&&(indices[i-1]>index)) ) +#else + if (dists[i-1]>dist) +#endif + { + if (i=1 && (dists[i]=1 && (dists[i] +class KNNResultSet : public ResultSet +{ + int* indices; + DistanceType* dists; + int capacity; + int count; + DistanceType worst_distance_; - return true; - } +public: + KNNResultSet(int capacity_) : capacity(capacity_), count(0) + { + } - float worstDist() const - { - return (count::max)() : dists[count-1]; - } + void init(int* indices_, DistanceType* dists_) + { + indices = indices_; + dists = dists_; + count = 0; + worst_distance_ = (std::numeric_limits::max)(); + dists[capacity-1] = worst_distance_; + } + + size_t size() const + { + return count; + } + + bool full() const + { + return count == capacity; + } + + + void addPoint(DistanceType dist, int index) + { + if (dist >= worst_distance_) return; + int i; + for (i = count; i > 0; --i) { +#ifdef FLANN_FIRST_MATCH + if ( (dists[i-1]<=dist) && ((dist!=dists[i-1])||(indices[i-1]<=index)) ) +#else + if (dists[i-1]<=dist) +#endif + { + // Check for duplicate indices + int j = i - 1; + while ((j >= 0) && (dists[j] == dist)) { + if (indices[j] == index) { + return; + } + --j; + } + break; + } + } + + if (count < capacity) ++count; + for (int j = count-1; j > i; --j) { + dists[j] = dists[j-1]; + indices[j] = indices[j-1]; + } + dists[i] = dist; + indices[i] = index; + worst_distance_ = dists[capacity-1]; + } + + DistanceType worstDist() const + { + return worst_distance_; + } }; /** * A result-set class used when performing a radius based search. */ -template -class RadiusResultSet : public ResultSet +template +class RadiusResultSet : public ResultSet { - const ELEM_TYPE* target; - const ELEM_TYPE* target_end; - int veclen; - - struct Item { - int index; - float dist; - - bool operator<(Item rhs) { - return dist items; - float radius; - - bool sorted; - int* indices; - float* dists; - size_t count; - -private: - void resize_vecs() - { - if (items.size()>count) { - if (indices!=NULL) delete[] indices; - if (dists!=NULL) delete[] dists; - count = items.size(); - indices = new int[count]; - dists = new float[count]; - } - } + DistanceType radius; + int* indices; + DistanceType* dists; + size_t capacity; + size_t count; public: - RadiusResultSet(float radius_) : - radius(radius_), indices(NULL), dists(NULL) - { - sorted = false; - items.reserve(16); - count = 0; - } - - ~RadiusResultSet() - { - if (indices!=NULL) delete[] indices; - if (dists!=NULL) delete[] dists; - } - - void init(const ELEM_TYPE* target_, int veclen_) - { - target = target_; - veclen = veclen_; - target_end = target + veclen; - items.clear(); - sorted = false; - } - - int* getNeighbors() - { - if (!sorted) { - sorted = true; - sort_heap(items.begin(), items.end()); - } - resize_vecs(); - for (size_t i=0;i0)&&(count < capacity)) { + dists[count] = dist; + indices[count] = index; + } + count++; + } + } - float worstDist() const - { - return radius; - } + DistanceType worstDist() const + { + return radius; + } }; -} // namespace cvflann +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** Class that holds the k NN neighbors + * Faster than KNNResultSet as it uses a binary heap and does not maintain two arrays + */ +template +class UniqueResultSet : public ResultSet +{ +public: + struct DistIndex + { + DistIndex(DistanceType dist, unsigned int index) : + dist_(dist), index_(index) + { + } + bool operator<(const DistIndex dist_index) const + { + return (dist_ < dist_index.dist_) || ((dist_ == dist_index.dist_) && index_ < dist_index.index_); + } + DistanceType dist_; + unsigned int index_; + }; + + /** Default cosntructor */ + UniqueResultSet() : + worst_distance_(std::numeric_limits::max()) + { + } + + /** Check the status of the set + * @return true if we have k NN + */ + inline bool full() const + { + return is_full_; + } + + /** Remove all elements in the set + */ + virtual void clear() = 0; + + /** Copy the set to two C arrays + * @param indices pointer to a C array of indices + * @param dist pointer to a C array of distances + * @param n_neighbors the number of neighbors to copy + */ + virtual void copy(int* indices, DistanceType* dist, int n_neighbors = -1) const + { + if (n_neighbors < 0) { + for (typename std::set::const_iterator dist_index = dist_indices_.begin(), dist_index_end = + dist_indices_.end(); dist_index != dist_index_end; ++dist_index, ++indices, ++dist) { + *indices = dist_index->index_; + *dist = dist_index->dist_; + } + } + else { + int i = 0; + for (typename std::set::const_iterator dist_index = dist_indices_.begin(), dist_index_end = + dist_indices_.end(); (dist_index != dist_index_end) && (i < n_neighbors); ++dist_index, ++indices, ++dist, ++i) { + *indices = dist_index->index_; + *dist = dist_index->dist_; + } + } + } + + /** Copy the set to two C arrays but sort it according to the distance first + * @param indices pointer to a C array of indices + * @param dist pointer to a C array of distances + * @param n_neighbors the number of neighbors to copy + */ + virtual void sortAndCopy(int* indices, DistanceType* dist, int n_neighbors = -1) const + { + copy(indices, dist, n_neighbors); + } + + /** The number of neighbors in the set + * @return + */ + size_t size() const + { + return dist_indices_.size(); + } + + /** The distance of the furthest neighbor + * If we don't have enough neighbors, it returns the max possible value + * @return + */ + inline DistanceType worstDist() const + { + return worst_distance_; + } +protected: + /** Flag to say if the set is full */ + bool is_full_; + + /** The worst distance found so far */ + DistanceType worst_distance_; + + /** The best candidates so far */ + std::set dist_indices_; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** Class that holds the k NN neighbors + * Faster than KNNResultSet as it uses a binary heap and does not maintain two arrays + */ +template +class KNNUniqueResultSet : public UniqueResultSet +{ +public: + /** Constructor + * @param capacity the number of neighbors to store at max + */ + KNNUniqueResultSet(unsigned int capacity) : capacity_(capacity) + { + this->is_full_ = false; + this->clear(); + } + + /** Add a possible candidate to the best neighbors + * @param dist distance for that neighbor + * @param index index of that neighbor + */ + inline void addPoint(DistanceType dist, int index) + { + // Don't do anything if we are worse than the worst + if (dist >= worst_distance_) return; + dist_indices_.insert(DistIndex(dist, index)); + + if (is_full_) { + if (dist_indices_.size() > capacity_) { + dist_indices_.erase(*dist_indices_.rbegin()); + worst_distance_ = dist_indices_.rbegin()->dist_; + } + } + else if (dist_indices_.size() == capacity_) { + is_full_ = true; + worst_distance_ = dist_indices_.rbegin()->dist_; + } + } + + /** Remove all elements in the set + */ + void clear() + { + dist_indices_.clear(); + worst_distance_ = std::numeric_limits::max(); + is_full_ = false; + } + +protected: + typedef typename UniqueResultSet::DistIndex DistIndex; + using UniqueResultSet::is_full_; + using UniqueResultSet::worst_distance_; + using UniqueResultSet::dist_indices_; + + /** The number of neighbors to keep */ + unsigned int capacity_; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** Class that holds the radius nearest neighbors + * It is more accurate than RadiusResult as it is not limited in the number of neighbors + */ +template +class RadiusUniqueResultSet : public UniqueResultSet +{ +public: + /** Constructor + * @param capacity the number of neighbors to store at max + */ + RadiusUniqueResultSet(DistanceType radius) : + radius_(radius) + { + is_full_ = true; + } + + /** Add a possible candidate to the best neighbors + * @param dist distance for that neighbor + * @param index index of that neighbor + */ + void addPoint(DistanceType dist, int index) + { + if (dist <= radius_) dist_indices_.insert(DistIndex(dist, index)); + } + + /** Remove all elements in the set + */ + inline void clear() + { + dist_indices_.clear(); + } + + + /** Check the status of the set + * @return alwys false + */ + inline bool full() const + { + return true; + } + + /** The distance of the furthest neighbor + * If we don't have enough neighbors, it returns the max possible value + * @return + */ + inline DistanceType worstDist() const + { + return radius_; + } +private: + typedef typename UniqueResultSet::DistIndex DistIndex; + using UniqueResultSet::dist_indices_; + using UniqueResultSet::is_full_; + + /** The furthest distance a neighbor can be */ + DistanceType radius_; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** Class that holds the k NN neighbors within a radius distance + */ +template +class KNNRadiusUniqueResultSet : public KNNUniqueResultSet +{ +public: + /** Constructor + * @param capacity the number of neighbors to store at max + */ + KNNRadiusUniqueResultSet(unsigned int capacity, DistanceType radius) + { + this->capacity_ = capacity; + this->radius_ = radius; + this->dist_indices_.reserve(capacity_); + this->clear(); + } + + /** Remove all elements in the set + */ + void clear() + { + dist_indices_.clear(); + worst_distance_ = radius_; + is_full_ = false; + } +private: + using KNNUniqueResultSet::dist_indices_; + using KNNUniqueResultSet::is_full_; + using KNNUniqueResultSet::worst_distance_; + + /** The maximum number of neighbors to consider */ + unsigned int capacity_; + + /** The maximum distance of a neighbor */ + DistanceType radius_; +}; +} + +#endif //FLANN_RESULTSET_H -#endif //_OPENCV_RESULTSET_H_ diff --git a/modules/flann/include/opencv2/flann/sampling.h b/modules/flann/include/opencv2/flann/sampling.h index 95f6e150ce..fd651505a0 100644 --- a/modules/flann/include/opencv2/flann/sampling.h +++ b/modules/flann/include/opencv2/flann/sampling.h @@ -27,13 +27,11 @@ *************************************************************************/ -#ifndef _OPENCV_SAMPLING_H_ -#define _OPENCV_SAMPLING_H_ - - -#include "opencv2/flann/matrix.h" -#include "opencv2/flann/random.h" +#ifndef OPENCV_FLANN_SAMPLING_H_ +#define OPENCV_FLANN_SAMPLING_H_ +#include "matrix.h" +#include "random.h" namespace cvflann { @@ -41,54 +39,43 @@ namespace cvflann template Matrix random_sample(Matrix& srcMatrix, long size, bool remove = false) { - UniqueRandom rand((int)srcMatrix.rows); - Matrix newSet(new T[size * srcMatrix.cols], size, (long)srcMatrix.cols); + Matrix newSet(new T[size * srcMatrix.cols], size,srcMatrix.cols); - T *src,*dest; - for (long i=0;i Matrix random_sample(const Matrix& srcMatrix, size_t size) { - UniqueRandom rand((int)srcMatrix.rows); - Matrix newSet(new T[size * srcMatrix.cols], (long)size, (long)srcMatrix.cols); + UniqueRandom rand(srcMatrix.rows); + Matrix newSet(new T[size * srcMatrix.cols], size,srcMatrix.cols); - T *src,*dest; - for (size_t i=0;i #include +#include + +#include "general.h" +#include "nn_index.h" + +#ifdef FLANN_SIGNATURE_ +#undef FLANN_SIGNATURE_ +#endif +#define FLANN_SIGNATURE_ "FLANN_INDEX" namespace cvflann { -template struct Datatype {}; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_INT8; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_INT16; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_INT32; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_UINT8; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_UINT16; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_UINT32; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_FLOAT32; } }; -template<> struct Datatype { static flann_datatype_t type() { return FLANN_FLOAT64; } }; +template +struct Datatype {}; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_INT8; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_INT16; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_INT32; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_UINT8; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_UINT16; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_UINT32; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_FLOAT32; } }; +template<> +struct Datatype { static flann_datatype_t type() { return FLANN_FLOAT64; } }; -CV_EXPORTS const char* FLANN_SIGNATURE(); -CV_EXPORTS const char* FLANN_VERSION(); /** * Structure representing the index header. */ -struct CV_EXPORTS IndexHeader +struct IndexHeader { - char signature[16]; - char version[16]; - flann_datatype_t data_type; - flann_algorithm_t index_type; - int rows; - int cols; + char signature[16]; + char version[16]; + flann_datatype_t data_type; + flann_algorithm_t index_type; + size_t rows; + size_t cols; }; /** @@ -69,20 +82,20 @@ struct CV_EXPORTS IndexHeader * @param stream - Stream to save to * @param index - The index to save */ -template -void save_header(FILE* stream, const NNIndex& index) +template +void save_header(FILE* stream, const NNIndex& index) { - IndexHeader header; - memset(header.signature, 0 , sizeof(header.signature)); - strcpy(header.signature, FLANN_SIGNATURE()); - memset(header.version, 0 , sizeof(header.version)); - strcpy(header.version, FLANN_VERSION()); - header.data_type = Datatype::type(); - header.index_type = index.getType(); - header.rows = (int)index.size(); - header.cols = index.veclen(); + IndexHeader header; + memset(header.signature, 0, sizeof(header.signature)); + strcpy(header.signature, FLANN_SIGNATURE_); + memset(header.version, 0, sizeof(header.version)); + strcpy(header.version, FLANN_VERSION_); + header.data_type = Datatype::type(); + header.index_type = index.getType(); + header.rows = index.size(); + header.cols = index.veclen(); - std::fwrite(&header, sizeof(header),1,stream); + std::fwrite(&header, sizeof(header),1,stream); } @@ -91,25 +104,84 @@ void save_header(FILE* stream, const NNIndex& index) * @param stream - Stream to load from * @return Index header */ -CV_EXPORTS IndexHeader load_header(FILE* stream); - - -template -void save_value(FILE* stream, const T& value, int count = 1) +inline IndexHeader load_header(FILE* stream) { - fwrite(&value, 1, sizeof(value)*count, stream); + IndexHeader header; + size_t read_size = fread(&header,sizeof(header),1,stream); + + if (read_size!=(size_t)1) { + throw FLANNException("Invalid index file, cannot read"); + } + + if (strcmp(header.signature,FLANN_SIGNATURE_)!=0) { + throw FLANNException("Invalid index file, wrong signature"); + } + + return header; + } template -void load_value(FILE* stream, T& value, int count = 1) +void save_value(FILE* stream, const T& value, size_t count = 1) { - int read_cnt = (int)fread(&value, sizeof(value),count, stream); - if (read_cnt!=count) { - throw FLANNException("Cannot read from file"); - } + fwrite(&value, sizeof(value),count, stream); } -} // namespace cvflann +template +void save_value(FILE* stream, const cvflann::Matrix& value) +{ + fwrite(&value, sizeof(value),1, stream); + fwrite(value.data, sizeof(T),value.rows*value.cols, stream); +} -#endif /* _OPENCV_SAVING_H_ */ +template +void save_value(FILE* stream, const std::vector& value) +{ + size_t size = value.size(); + fwrite(&size, sizeof(size_t), 1, stream); + fwrite(&value[0], sizeof(T), size, stream); +} + +template +void load_value(FILE* stream, T& value, size_t count = 1) +{ + size_t read_cnt = fread(&value, sizeof(value), count, stream); + if (read_cnt != count) { + throw FLANNException("Cannot read from file"); + } +} + +template +void load_value(FILE* stream, cvflann::Matrix& value) +{ + size_t read_cnt = fread(&value, sizeof(value), 1, stream); + if (read_cnt != 1) { + throw FLANNException("Cannot read from file"); + } + value.data = new T[value.rows*value.cols]; + read_cnt = fread(value.data, sizeof(T), value.rows*value.cols, stream); + if (read_cnt != (size_t)(value.rows*value.cols)) { + throw FLANNException("Cannot read from file"); + } +} + + +template +void load_value(FILE* stream, std::vector& value) +{ + size_t size; + size_t read_cnt = fread(&size, sizeof(size_t), 1, stream); + if (read_cnt!=1) { + throw FLANNException("Cannot read from file"); + } + value.resize(size); + read_cnt = fread(&value[0], sizeof(T), size, stream); + if (read_cnt != size) { + throw FLANNException("Cannot read from file"); + } +} + +} + +#endif /* OPENCV_FLANN_SAVING_H_ */ diff --git a/modules/flann/include/opencv2/flann/simplex_downhill.h b/modules/flann/include/opencv2/flann/simplex_downhill.h index 21d3e944b1..145901ab0d 100644 --- a/modules/flann/include/opencv2/flann/simplex_downhill.h +++ b/modules/flann/include/opencv2/flann/simplex_downhill.h @@ -28,20 +28,20 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ -#ifndef _OPENCV_SIMPLEX_DOWNHILL_H_ -#define _OPENCV_SIMPLEX_DOWNHILL_H_ +#ifndef OPENCV_FLANN_SIMPLEX_DOWNHILL_H_ +#define OPENCV_FLANN_SIMPLEX_DOWNHILL_H_ namespace cvflann { /** Adds val to array vals (and point to array points) and keeping the arrays sorted by vals. -*/ + */ template void addValue(int pos, float val, float* vals, T* point, T* points, int n) { vals[pos] = val; - for (int i=0;i0 && vals[j] float optimizeSimplexDownhill(T* points, int n, F func, float* vals = NULL ) { @@ -84,7 +84,7 @@ float optimizeSimplexDownhill(T* points, int n, F func, float* vals = NULL ) if (vals == NULL) { ownVals = true; vals = new float[n+1]; - for (int i=0;i MAX_ITERATIONS) break; // compute average of simplex points (except the highest point) - for (int j=0;j=vals[0] && val_r=vals[0])&&(val_r=vals[n]) { - for (int i=0;i @@ -42,7 +42,7 @@ namespace cvflann * * Can be used to time portions of code. */ -class CV_EXPORTS StartStopTimer +class StartStopTimer { clock_t startTime; @@ -64,14 +64,16 @@ public: /** * Starts the timer. */ - void start() { + void start() + { startTime = clock(); } /** * Stops the timer and updates timer value. */ - void stop() { + void stop() + { clock_t stopTime = clock(); value += ( (double)stopTime - startTime) / CLOCKS_PER_SEC; } @@ -79,12 +81,13 @@ public: /** * Resets the timer value to 0. */ - void reset() { + void reset() + { value = 0; } }; -}// namespace cvflann +} -#endif // _OPENCV_TIMER_H_ +#endif // FLANN_TIMER_H diff --git a/modules/flann/src/flann.cpp b/modules/flann/src/flann.cpp index 30a82ea6f4..36ee6694a3 100644 --- a/modules/flann/src/flann.cpp +++ b/modules/flann/src/flann.cpp @@ -27,199 +27,31 @@ *************************************************************************/ #include "precomp.hpp" +#include "opencv2/flann/flann.hpp" namespace cvflann { -// ----------------------- dist.cpp --------------------------- - -/** Global variable indicating the distance metric - * to be used. - */ -flann_distance_t flann_distance_type_ = FLANN_DIST_EUCLIDEAN; -flann_distance_t flann_distance_type() { return flann_distance_type_; } - -/** - * Zero iterator that emulates a zero feature. - */ -ZeroIterator zero_; -ZeroIterator& zero() { return zero_; } - -/** - * Order of Minkowski distance to use. - */ -int flann_minkowski_order_; -int flann_minkowski_order() { return flann_minkowski_order_; } - - -double euclidean_dist(const unsigned char* first1, const unsigned char* last1, unsigned char* first2, double acc) -{ - double distsq = acc; - double diff0, diff1, diff2, diff3; - const unsigned char* lastgroup = last1 - 3; - - while (first1 < lastgroup) { - diff0 = first1[0] - first2[0]; - diff1 = first1[1] - first2[1]; - diff2 = first1[2] - first2[2]; - diff3 = first1[3] - first2[3]; - distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; - first1 += 4; - first2 += 4; - } - while (first1 < last1) { - diff0 = *first1++ - *first2++; - distsq += diff0 * diff0; - } - return distsq; -} - -// ----------------------- index_testing.cpp --------------------------- - -int countCorrectMatches(int* neighbors, int* groundTruth, int n) -{ - int count = 0; - for (int i=0;i instead.\n"); + if (distance_type != FLANN_DIST_L1 && distance_type != FLANN_DIST_L2) { + printf("[ERROR] cvflann::set_distance_type only provides backwards compatibility " + "for the L1 and L2 distances. " + "For other distance types you must use cv::flann::GenericIndex\n"); } + flann_distance_type_ = distance_type; } - return count; -} - -// ----------------------- logger.cpp --------------------------- - -Logger logger_; - -Logger& logger() { return logger_; } - -int Logger::log(int level, const char* fmt, ...) -{ - if (level > logLevel ) return -1; - - int ret; - va_list arglist; - va_start(arglist, fmt); - ret = vfprintf(stream, fmt, arglist); - va_end(arglist); - - return ret; -} - -int Logger::log(int level, const char* fmt, va_list arglist) -{ - if (level > logLevel ) return -1; - - int ret; - ret = vfprintf(stream, fmt, arglist); - - return ret; -} - - -#define LOG_METHOD(NAME,LEVEL) \ - int Logger::NAME(const char* fmt, ...) \ - { \ - int ret; \ - va_list ap; \ - va_start(ap, fmt); \ - ret = log(LEVEL, fmt, ap); \ - va_end(ap); \ - return ret; \ - } - - -LOG_METHOD(fatal, FLANN_LOG_FATAL) -LOG_METHOD(error, FLANN_LOG_ERROR) -LOG_METHOD(warn, FLANN_LOG_WARN) -LOG_METHOD(info, FLANN_LOG_INFO) - -// ----------------------- random.cpp --------------------------- - -void seed_random(unsigned int seed) -{ - srand(seed); -} - -double rand_double(double high, double low) -{ - return low + ((high-low) * (std::rand() / (RAND_MAX + 1.0))); -} - - -int rand_int(int high, int low) -{ - return low + (int) ( double(high-low) * (std::rand() / (RAND_MAX + 1.0))); -} - -// ----------------------- saving.cpp --------------------------- - -const char FLANN_SIGNATURE_[] = "FLANN_INDEX"; -const char FLANN_VERSION_[] = "1.5.0"; - -const char* FLANN_SIGNATURE() { return FLANN_SIGNATURE_; } -const char* FLANN_VERSION() { return FLANN_VERSION_; } - -IndexHeader load_header(FILE* stream) -{ - IndexHeader header; - size_t read_size = fread(&header,sizeof(header),1,stream); - - if (read_size!=1) { - throw FLANNException("Invalid index file, cannot read"); - } - - if (strcmp(header.signature,FLANN_SIGNATURE())!=0) { - throw FLANNException("Invalid index file, wrong signature"); - } - - return header; - -} - -// ----------------------- flann.cpp --------------------------- - - -void log_verbosity(int level) -{ - if (level>=0) { - logger().setLevel(level); - } -} - -void set_distance_type(flann_distance_t distance_type, int order) -{ - flann_distance_type_ = distance_type; - flann_minkowski_order_ = order; -} - - -static ParamsFactory the_factory; - -ParamsFactory& ParamsFactory_instance() -{ - return the_factory; -} - -class StaticInit -{ -public: - StaticInit() - { - ParamsFactory_instance().register_(FLANN_INDEX_LINEAR); - ParamsFactory_instance().register_(FLANN_INDEX_KDTREE); - ParamsFactory_instance().register_(FLANN_INDEX_KMEANS); - ParamsFactory_instance().register_(FLANN_INDEX_COMPOSITE); - ParamsFactory_instance().register_(FLANN_INDEX_AUTOTUNED); -// ParamsFactory::instance().register_(FLANN_INDEX_SAVED); - } -}; -StaticInit __init; - - -} // namespace cvflann - - - + + void dummyfunc() {} +} \ No newline at end of file diff --git a/modules/flann/src/miniflann.cpp b/modules/flann/src/miniflann.cpp new file mode 100644 index 0000000000..54f3c9faac --- /dev/null +++ b/modules/flann/src/miniflann.cpp @@ -0,0 +1,787 @@ +#include "precomp.hpp" + +#define MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 0 + +static cvflann::IndexParams& get_params(const cv::flann::IndexParams& p) +{ + return *(cvflann::IndexParams*)(p.params); +} + +namespace cv +{ + +namespace flann +{ + +IndexParams::IndexParams() +{ + params = new ::cvflann::IndexParams(); +} + +IndexParams::~IndexParams() +{ + delete &get_params(*this); +} + +template +T getParam(const IndexParams& _p, const std::string& key, const T& defaultVal=T()) +{ + ::cvflann::IndexParams& p = get_params(_p); + ::cvflann::IndexParams::const_iterator it = p.find(key); + if( it == p.end() ) + return defaultVal; + return it->second.cast(); +} + +template +void setParam(IndexParams& _p, const std::string& key, const T& value) +{ + ::cvflann::IndexParams& p = get_params(_p); + p[key] = value; +} + +std::string IndexParams::getString(const std::string& key, const std::string& defaultVal) const +{ + return getParam(*this, key, defaultVal); +} + +int IndexParams::getInt(const std::string& key, int defaultVal) const +{ + return getParam(*this, key, defaultVal); +} + +double IndexParams::getDouble(const std::string& key, double defaultVal) const +{ + return getParam(*this, key, defaultVal); +} + + +void IndexParams::setString(const std::string& key, const std::string& value) +{ + setParam(*this, key, value); +} + +void IndexParams::setInt(const std::string& key, int value) +{ + setParam(*this, key, value); +} + +void IndexParams::setDouble(const std::string& key, double value) +{ + setParam(*this, key, value); +} + +void IndexParams::setFloat(const std::string& key, float value) +{ + setParam(*this, key, value); +} + +void IndexParams::setBool(const std::string& key, bool value) +{ + setParam(*this, key, value); +} + +void IndexParams::setAlgorithm(const std::string& key, int value) +{ + setParam(*this, key, (cvflann::flann_algorithm_t)value); +} + +void IndexParams::getAll(std::vector& names, + std::vector& types, + std::vector& strValues, + std::vector& numValues) const +{ + names.clear(); + types.clear(); + strValues.clear(); + numValues.clear(); + + ::cvflann::IndexParams& p = get_params(*this); + ::cvflann::IndexParams::const_iterator it = p.begin(), it_end = p.end(); + + for( ; it != it_end; ++it ) + { + names.push_back(it->first); + try + { + std::string val = it->second.cast(); + types.push_back(CV_USRTYPE1); + strValues.push_back(val); + numValues.push_back(-1); + continue; + } + catch (...) {} + + strValues.push_back(it->second.type().name()); + + try + { + double val = it->second.cast(); + types.push_back( CV_64F ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + float val = it->second.cast(); + types.push_back( CV_32F ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + int val = it->second.cast(); + types.push_back( CV_32S ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + short val = it->second.cast(); + types.push_back( CV_16S ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + ushort val = it->second.cast(); + types.push_back( CV_16U ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + char val = it->second.cast(); + types.push_back( CV_8S ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + uchar val = it->second.cast(); + types.push_back( CV_8U ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + bool val = it->second.cast(); + types.push_back( CV_MAKETYPE(CV_USRTYPE1,2) ); + numValues.push_back(val); + continue; + } + catch (...) {} + try + { + cvflann::flann_algorithm_t val = it->second.cast(); + types.push_back( CV_MAKETYPE(CV_USRTYPE1,3) ); + numValues.push_back(val); + continue; + } + catch (...) {} + + + types.push_back(-1); // unknown type + numValues.push_back(-1); + } +} + + +KDTreeIndexParams::KDTreeIndexParams(int trees) +{ + ::cvflann::IndexParams& p = get_params(*this); + p["algorithm"] = FLANN_INDEX_KDTREE; + p["trees"] = trees; +} + +LinearIndexParams::LinearIndexParams() +{ + ::cvflann::IndexParams& p = get_params(*this); + p["algorithm"] = FLANN_INDEX_LINEAR; +} + +CompositeIndexParams::CompositeIndexParams(int trees, int branching, int iterations, + flann_centers_init_t centers_init, float cb_index ) +{ + ::cvflann::IndexParams& p = get_params(*this); + p["algorithm"] = FLANN_INDEX_KMEANS; + // number of randomized trees to use (for kdtree) + p["trees"] = trees; + // branching factor + p["branching"] = branching; + // max iterations to perform in one kmeans clustering (kmeans tree) + p["iterations"] = iterations; + // algorithm used for picking the initial cluster centers for kmeans tree + p["centers_init"] = centers_init; + // cluster boundary index. Used when searching the kmeans tree + p["cb_index"] = cb_index; +} + +AutotunedIndexParams::AutotunedIndexParams(float target_precision, float build_weight, + float memory_weight, float sample_fraction) +{ + ::cvflann::IndexParams& p = get_params(*this); + p["algorithm"] = FLANN_INDEX_AUTOTUNED; + // precision desired (used for autotuning, -1 otherwise) + p["target_precision"] = target_precision; + // build tree time weighting factor + p["build_weight"] = build_weight; + // index memory weighting factor + p["memory_weight"] = memory_weight; + // what fraction of the dataset to use for autotuning + p["sample_fraction"] = sample_fraction; +} + + +KMeansIndexParams::KMeansIndexParams(int branching, int iterations, + flann_centers_init_t centers_init, float cb_index ) +{ + ::cvflann::IndexParams& p = get_params(*this); + p["algorithm"] = FLANN_INDEX_KMEANS; + // branching factor + p["branching"] = branching; + // max iterations to perform in one kmeans clustering (kmeans tree) + p["iterations"] = iterations; + // algorithm used for picking the initial cluster centers for kmeans tree + p["centers_init"] = centers_init; + // cluster boundary index. Used when searching the kmeans tree + p["cb_index"] = cb_index; +} + +LshIndexParams::LshIndexParams(int table_number, int key_size, int multi_probe_level) +{ + ::cvflann::IndexParams& p = get_params(*this); + p["algorithm"] = FLANN_INDEX_LSH; + // The number of hash tables to use + p["table_number"] = (unsigned)table_number; + // The length of the key in the hash tables + p["key_size"] = (unsigned)key_size; + // Number of levels to use in multi-probe (0 for standard LSH) + p["multi_probe_level"] = (unsigned)multi_probe_level; +} + +SavedIndexParams::SavedIndexParams(const std::string& _filename) +{ + std::string filename = _filename; + ::cvflann::IndexParams& p = get_params(*this); + + p["algorithm"] = FLANN_INDEX_SAVED; + p["filename"] = filename; +} + +SearchParams::SearchParams( int checks, float eps, bool sorted ) +{ + ::cvflann::IndexParams& p = get_params(*this); + + // how many leafs to visit when searching for neighbours (-1 for unlimited) + p["checks"] = checks; + // search for eps-approximate neighbours (default: 0) + p["eps"] = eps; + // only for radius search, require neighbours sorted by distance (default: true) + p["sorted"] = sorted; +} + + +template void +buildIndex_(void*& index, const Mat& data, const IndexParams& params, const Distance& dist = Distance()) +{ + typedef typename Distance::ElementType ElementType; + CV_Assert(DataType::type == data.type() && data.isContinuous()); + + ::cvflann::Matrix dataset((ElementType*)data.data, data.rows, data.cols); + IndexType* _index = new IndexType(dataset, get_params(params), dist); + _index->buildIndex(); + index = _index; +} + +template void +buildIndex(void*& index, const Mat& data, const IndexParams& params, const Distance& dist = Distance()) +{ + buildIndex_ >(index, data, params, dist); +} + +typedef ::cvflann::HammingLUT HammingDistance; +typedef ::cvflann::LshIndex LshIndex; + +Index::Index() +{ + index = 0; + featureType = CV_32F; + algo = FLANN_INDEX_LINEAR; + distType = FLANN_DIST_L2; +} + +Index::Index(InputArray _data, const IndexParams& params, flann_distance_t _distType) +{ + index = 0; + featureType = CV_32F; + algo = FLANN_INDEX_LINEAR; + distType = FLANN_DIST_L2; + build(_data, params, _distType); +} + +void Index::build(InputArray _data, const IndexParams& params, flann_distance_t _distType) +{ + release(); + algo = getParam(params, "algorithm", FLANN_INDEX_LINEAR); + if( algo == FLANN_INDEX_SAVED ) + { + load(_data, getParam(params, "filename", std::string())); + return; + } + + Mat data = _data.getMat(); + index = 0; + featureType = data.type(); + distType = _distType; + + if( algo == FLANN_INDEX_LSH ) + { + buildIndex_(index, data, params); + return; + } + + switch( distType ) + { + case FLANN_DIST_L2: + buildIndex< ::cvflann::L2 >(index, data, params); + break; + case FLANN_DIST_L1: + buildIndex< ::cvflann::L1 >(index, data, params); + break; +#if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES + case FLANN_DIST_MAX: + buildIndex< ::cvflann::MaxDistance >(index, data, params); + break; + case FLANN_DIST_HIST_INTERSECT: + buildIndex< ::cvflann::HistIntersectionDistance >(index, data, params); + break; + case FLANN_DIST_HELLINGER: + buildIndex< ::cvflann::HellingerDistance >(index, data, params); + break; + case FLANN_DIST_CHI_SQUARE: + buildIndex< ::cvflann::ChiSquareDistance >(index, data, params); + break; + case FLANN_DIST_KL: + buildIndex< ::cvflann::KL_Divergence >(index, data, params); + break; +#endif + default: + CV_Error(CV_StsBadArg, "Unknown/unsupported distance type"); + } +} + +template void deleteIndex_(void* index) +{ + delete (IndexType*)index; +} + +template void deleteIndex(void* index) +{ + deleteIndex_< ::cvflann::Index >(index); +} + +Index::~Index() +{ + release(); +} + +void Index::release() +{ + if( !index ) + return; + if( algo == FLANN_INDEX_LSH ) + { + deleteIndex_(index); + } + else + { + CV_Assert( featureType == CV_32F ); + switch( distType ) + { + case FLANN_DIST_L2: + deleteIndex< ::cvflann::L2 >(index); + break; + case FLANN_DIST_L1: + deleteIndex< ::cvflann::L1 >(index); + break; +#if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES + case FLANN_DIST_MAX: + deleteIndex< ::cvflann::MaxDistance >(index); + break; + case FLANN_DIST_HIST_INTERSECT: + deleteIndex< ::cvflann::HistIntersectionDistance >(index); + break; + case FLANN_DIST_HELLINGER: + deleteIndex< ::cvflann::HellingerDistance >(index); + break; + case FLANN_DIST_CHI_SQUARE: + deleteIndex< ::cvflann::ChiSquareDistance >(index); + break; + case FLANN_DIST_KL: + deleteIndex< ::cvflann::KL_Divergence >(index); + break; +#endif + default: + CV_Error(CV_StsBadArg, "Unknown/unsupported distance type"); + } + } + index = 0; +} + +template +void runKnnSearch_(void* index, const Mat& query, Mat& indices, Mat& dists, + int knn, const SearchParams& params) +{ + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + int type = DataType::type; + int dtype = DataType::type; + CV_Assert(query.type() == type && indices.type() == CV_32S && dists.type() == dtype); + CV_Assert(query.isContinuous() && indices.isContinuous() && dists.isContinuous()); + + ::cvflann::Matrix _query((ElementType*)query.data, query.rows, query.cols); + ::cvflann::Matrix _indices((int*)indices.data, indices.rows, indices.cols); + ::cvflann::Matrix _dists((DistanceType*)dists.data, dists.rows, dists.cols); + + ((IndexType*)index)->knnSearch(_query, _indices, _dists, knn, + (const ::cvflann::SearchParams&)get_params(params)); +} + +template +void runKnnSearch(void* index, const Mat& query, Mat& indices, Mat& dists, + int knn, const SearchParams& params) +{ + runKnnSearch_ >(index, query, indices, dists, knn, params); +} + +template +int runRadiusSearch_(void* index, const Mat& query, Mat& indices, Mat& dists, + double radius, const SearchParams& params) +{ + typedef typename Distance::ElementType ElementType; + typedef typename Distance::ResultType DistanceType; + int type = DataType::type; + int dtype = DataType::type; + CV_Assert(query.type() == type && indices.type() == CV_32S && dists.type() == dtype); + CV_Assert(query.isContinuous() && indices.isContinuous() && dists.isContinuous()); + + ::cvflann::Matrix _query((ElementType*)query.data, query.rows, query.cols); + ::cvflann::Matrix _indices((int*)indices.data, indices.rows, indices.cols); + ::cvflann::Matrix _dists((DistanceType*)dists.data, dists.rows, dists.cols); + + return ((IndexType*)index)->radiusSearch(_query, _indices, _dists, + saturate_cast(radius), + (const ::cvflann::SearchParams&)get_params(params)); +} + +template +int runRadiusSearch(void* index, const Mat& query, Mat& indices, Mat& dists, + double radius, const SearchParams& params) +{ + return runRadiusSearch_ >(index, query, indices, dists, radius, params); +} + + +static void createIndicesDists(OutputArray _indices, OutputArray _dists, + Mat& indices, Mat& dists, int rows, + int minCols, int maxCols, int dtype) +{ + if( _indices.needed() ) + { + indices = _indices.getMat(); + if( !indices.isContinuous() || indices.type() != CV_32S || + indices.rows != rows || indices.cols < minCols || indices.cols > maxCols ) + { + if( !indices.isContinuous() ) + _indices.release(); + _indices.create( rows, minCols, CV_32S ); + indices = _indices.getMat(); + } + } + else + indices.create( rows, minCols, CV_32S ); + + if( _dists.needed() ) + { + dists = _dists.getMat(); + if( !dists.isContinuous() || dists.type() != dtype || + dists.rows != rows || dists.cols < minCols || dists.cols > maxCols ) + { + if( !indices.isContinuous() ) + _dists.release(); + _dists.create( rows, minCols, dtype ); + dists = _dists.getMat(); + } + } + else + dists.create( rows, minCols, dtype ); +} + + +void Index::knnSearch(InputArray _query, OutputArray _indices, + OutputArray _dists, int knn, const SearchParams& params) +{ + Mat query = _query.getMat(), indices, dists; + int dtype = algo == FLANN_INDEX_LSH ? CV_32S : CV_32F; + + createIndicesDists( _indices, _dists, indices, dists, query.rows, knn, knn, dtype ); + + if( algo == FLANN_INDEX_LSH ) + { + runKnnSearch_(index, query, indices, dists, knn, params); + return; + } + + switch( distType ) + { + case FLANN_DIST_L2: + runKnnSearch< ::cvflann::L2 >(index, query, indices, dists, knn, params); + break; + case FLANN_DIST_L1: + runKnnSearch< ::cvflann::L1 >(index, query, indices, dists, knn, params); + break; +#if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES + case FLANN_DIST_MAX: + runKnnSearch< ::cvflann::MaxDistance >(index, query, indices, dists, knn, params); + break; + case FLANN_DIST_HIST_INTERSECT: + runKnnSearch< ::cvflann::HistIntersectionDistance >(index, query, indices, dists, knn, params); + break; + case FLANN_DIST_HELLINGER: + runKnnSearch< ::cvflann::HellingerDistance >(index, query, indices, dists, knn, params); + break; + case FLANN_DIST_CHI_SQUARE: + runKnnSearch< ::cvflann::ChiSquareDistance >(index, query, indices, dists, knn, params); + break; + case FLANN_DIST_KL: + runKnnSearch< ::cvflann::KL_Divergence >(index, query, indices, dists, knn, params); + break; +#endif + default: + CV_Error(CV_StsBadArg, "Unknown/unsupported distance type"); + } +} + +int Index::radiusSearch(InputArray _query, OutputArray _indices, + OutputArray _dists, double radius, int maxResults, + const SearchParams& params) +{ + Mat query = _query.getMat(), indices, dists; + int dtype = algo == FLANN_INDEX_LSH ? CV_32S : CV_32F; + CV_Assert( maxResults > 0 ); + createIndicesDists( _indices, _dists, indices, dists, query.rows, maxResults, INT_MAX, dtype ); + + if( algo == FLANN_INDEX_LSH ) + CV_Error( CV_StsNotImplemented, "LSH index does not support radiusSearch operation" ); + + switch( distType ) + { + case FLANN_DIST_L2: + return runRadiusSearch< ::cvflann::L2 >(index, query, indices, dists, radius, params); + case FLANN_DIST_L1: + return runRadiusSearch< ::cvflann::L1 >(index, query, indices, dists, radius, params); +#if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES + case FLANN_DIST_MAX: + return runRadiusSearch< ::cvflann::MaxDistance >(index, query, indices, dists, radius, params); + case FLANN_DIST_HIST_INTERSECT: + return runRadiusSearch< ::cvflann::HistIntersectionDistance >(index, query, indices, dists, radius, params); + case FLANN_DIST_HELLINGER: + return runRadiusSearch< ::cvflann::HellingerDistance >(index, query, indices, dists, radius, params); + case FLANN_DIST_CHI_SQUARE: + return runRadiusSearch< ::cvflann::ChiSquareDistance >(index, query, indices, dists, radius, params); + case FLANN_DIST_KL: + return runRadiusSearch< ::cvflann::KL_Divergence >(index, query, indices, dists, radius, params); +#endif + default: + CV_Error(CV_StsBadArg, "Unknown/unsupported distance type"); + } + return -1; +} + +flann_distance_t Index::getDistance() const +{ + return distType; +} + +flann_algorithm_t Index::getAlgorithm() const +{ + return algo; +} + +template void saveIndex_(const Index* index0, const void* index, FILE* fout) +{ + IndexType* _index = (IndexType*)index; + ::cvflann::save_header(fout, *_index); + // some compilers may store short enumerations as bytes, + // so make sure we always write integers (which are 4-byte values in any modern C compiler) + int idistType = (int)index0->getDistance(); + ::cvflann::save_value(fout, idistType); + _index->saveIndex(fout); +} + +template void saveIndex(const Index* index0, const void* index, FILE* fout) +{ + saveIndex_< ::cvflann::Index >(index0, index, fout); +} + +void Index::save(const std::string& filename) const +{ + FILE* fout = fopen(filename.c_str(), "wb"); + if (fout == NULL) + CV_Error_( CV_StsError, ("Can not open file %s for writing FLANN index\n", filename.c_str()) ); + + if( algo == FLANN_INDEX_LSH ) + { + saveIndex_(this, index, fout); + return; + } + + switch( distType ) + { + case FLANN_DIST_L2: + saveIndex< ::cvflann::L2 >(this, index, fout); + break; + case FLANN_DIST_L1: + saveIndex< ::cvflann::L1 >(this, index, fout); + break; +#if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES + case FLANN_DIST_MAX: + saveIndex< ::cvflann::MaxDistance >(this, index, fout); + break; + case FLANN_DIST_HIST_INTERSECT: + saveIndex< ::cvflann::HistIntersectionDistance >(this, index, fout); + break; + case FLANN_DIST_HELLINGER: + saveIndex< ::cvflann::HellingerDistance >(this, index, fout); + break; + case FLANN_DIST_CHI_SQUARE: + saveIndex< ::cvflann::ChiSquareDistance >(this, index, fout); + break; + case FLANN_DIST_KL: + saveIndex< ::cvflann::KL_Divergence >(this, index, fout); + break; +#endif + default: + fclose(fout); + fout = 0; + CV_Error(CV_StsBadArg, "Unknown/unsupported distance type"); + } + if( fout ) + fclose(fout); +} + + +template +bool loadIndex_(Index* index0, void*& index, const Mat& data, FILE* fin, const Distance& dist=Distance()) +{ + typedef typename Distance::ElementType ElementType; + CV_Assert(DataType::type == data.type() && data.isContinuous()); + + ::cvflann::Matrix dataset((ElementType*)data.data, data.rows, data.cols); + + ::cvflann::IndexParams params; + params["algorithm"] = index0->getAlgorithm(); + IndexType* _index = new IndexType(dataset, params, dist); + _index->loadIndex(fin); + index = _index; + return true; +} + +template +bool loadIndex(Index* index0, void*& index, const Mat& data, FILE* fin, const Distance& dist=Distance()) +{ + return loadIndex_ >(index0, index, data, fin, dist); +} + +bool Index::load(InputArray _data, const std::string& filename) +{ + Mat data = _data.getMat(); + bool ok = true; + release(); + FILE* fin = fopen(filename.c_str(), "rb"); + if (fin == NULL) + return false; + + ::cvflann::IndexHeader header = ::cvflann::load_header(fin); + algo = header.index_type; + featureType = header.data_type == FLANN_UINT8 ? CV_8U : + header.data_type == FLANN_INT8 ? CV_8S : + header.data_type == FLANN_UINT16 ? CV_16U : + header.data_type == FLANN_INT16 ? CV_16S : + header.data_type == FLANN_INT32 ? CV_32S : + header.data_type == FLANN_FLOAT32 ? CV_32F : + header.data_type == FLANN_FLOAT64 ? CV_64F : -1; + + if( (int)header.rows != data.rows || (int)header.cols != data.cols || + featureType != data.type() ) + { + fprintf(stderr, "Reading FLANN index error: the saved data size (%d, %d) or type (%d) is different from the passed one (%d, %d), %d\n", + (int)header.rows, (int)header.cols, featureType, data.rows, data.cols, data.type()); + fclose(fin); + return false; + } + + if( !((algo == FLANN_INDEX_LSH && featureType == CV_8U) || + (algo != FLANN_INDEX_LSH && featureType == CV_32F)) ) + { + fprintf(stderr, "Reading FLANN index error: unsupported feature type %d for the index type %d\n", featureType, algo); + fclose(fin); + return false; + } + int idistType = 0; + ::cvflann::load_value(fin, idistType); + distType = (flann_distance_t)idistType; + + if( algo == FLANN_INDEX_LSH ) + { + loadIndex_(this, index, data, fin); + } + else + { + switch( distType ) + { + case FLANN_DIST_L2: + loadIndex< ::cvflann::L2 >(this, index, data, fin); + break; + case FLANN_DIST_L1: + loadIndex< ::cvflann::L1 >(this, index, data, fin); + break; + #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES + case FLANN_DIST_MAX: + loadIndex< ::cvflann::MaxDistance >(this, index, data, fin); + break; + case FLANN_DIST_HIST_INTERSECT: + loadIndex< ::cvflann::HistIntersectionDistance >(index, data, fin); + break; + case FLANN_DIST_HELLINGER: + loadIndex< ::cvflann::HellingerDistance >(this, index, data, fin); + break; + case FLANN_DIST_CHI_SQUARE: + loadIndex< ::cvflann::ChiSquareDistance >(this, index, data, fin); + break; + case FLANN_DIST_KL: + loadIndex< ::cvflann::KL_Divergence >(this, index, data, fin); + break; + #endif + default: + fprintf(stderr, "Reading FLANN index error: unsupported distance type %d\n", distType); + ok = false; + } + } + + if( fin ) + fclose(fin); + return ok; +} + +} + +} diff --git a/modules/flann/src/precomp.hpp b/modules/flann/src/precomp.hpp index 8c511ced52..7678a47ebc 100644 --- a/modules/flann/src/precomp.hpp +++ b/modules/flann/src/precomp.hpp @@ -5,10 +5,13 @@ #include #include +#include "opencv2/flann/miniflann.hpp" #include "opencv2/flann/dist.h" #include "opencv2/flann/index_testing.h" +#include "opencv2/flann/params.h" #include "opencv2/flann/saving.h" #include "opencv2/flann/general.h" +#include "opencv2/flann/dummy.h" // index types #include "opencv2/flann/all_indices.h" diff --git a/modules/gpu/CMakeLists.txt b/modules/gpu/CMakeLists.txt index 06778053ec..b9f36664f2 100644 --- a/modules/gpu/CMakeLists.txt +++ b/modules/gpu/CMakeLists.txt @@ -6,8 +6,8 @@ project(${the_target}) set(DEPS "opencv_core" "opencv_imgproc" "opencv_objdetect" "opencv_features2d" "opencv_flann" "opencv_calib3d") #"opencv_features2d" "opencv_flann" "opencv_objdetect" - only headers needed set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} opencv_gpu) -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include" - "${CMAKE_CURRENT_SOURCE_DIR}/src/cuda" +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/src/cuda" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_BINARY_DIR}") @@ -23,7 +23,9 @@ source_group("Include" FILES ${lib_hdrs}) #file(GLOB lib_device_hdrs "include/opencv2/${name}/device/*.h*") file(GLOB lib_device_hdrs "src/opencv2/gpu/device/*.h*") +file(GLOB lib_device_hdrs_detail "src/opencv2/gpu/device/detail/*.h*") source_group("Device" FILES ${lib_device_hdrs}) +source_group("Device\\Detail" FILES ${lib_device_hdrs_detail}) if (HAVE_CUDA) file(GLOB_RECURSE ncv_srcs "src/nvidia/*.cpp") @@ -83,19 +85,7 @@ foreach(d ${DEPS}) endif() endforeach() -add_library(${the_target} ${lib_srcs} ${lib_hdrs} ${lib_int_hdrs} ${lib_cuda} ${lib_cuda_hdrs} ${lib_device_hdrs} ${ncv_srcs} ${ncv_hdrs} ${ncv_cuda} ${cuda_objs}) - -if(PCHSupport_FOUND) - set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/src/precomp.hpp) - if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*") - if(${CMAKE_GENERATOR} MATCHES "Visual*") - set(${the_target}_pch "src/precomp.cpp") - endif() - add_native_precompiled_header(${the_target} ${pch_header}) - elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles") - add_precompiled_header(${the_target} ${pch_header}) - endif() -endif() +add_library(${the_target} ${lib_srcs} ${lib_hdrs} ${lib_int_hdrs} ${lib_cuda} ${lib_cuda_hdrs} ${lib_device_hdrs} ${lib_device_hdrs_detail} ${ncv_srcs} ${ncv_hdrs} ${ncv_cuda} ${cuda_objs}) # For dynamic link numbering convenions set_target_properties(${the_target} PROPERTIES @@ -112,36 +102,38 @@ if (BUILD_SHARED_LIBS) if (MSVC) set_target_properties(${the_target} PROPERTIES DEFINE_SYMBOL CVAPI_EXPORTS) else() - add_definitions(-DCVAPI_EXPORTS) - endif() + add_definitions(-DCVAPI_EXPORTS) + endif() endif() +add_opencv_precompiled_headers(${the_target}) + # Additional target properties set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" + DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} INSTALL_NAME_DIR lib - ) + ) # Add the required libraries for linking: target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${IPP_LIBS} ${DEPS} ) if (HAVE_CUDA) - target_link_libraries(${the_target} ${CUDA_LIBRARIES}) + target_link_libraries(${the_target} ${CUDA_LIBRARIES}) CUDA_ADD_CUFFT_TO_TARGET(${the_target}) - - unset(CUDA_npp_LIBRARY CACHE) - find_cuda_helper_libs(npp) - target_link_libraries(${the_target} ${CUDA_npp_LIBRARY}) + + unset(CUDA_npp_LIBRARY CACHE) + find_cuda_helper_libs(npp) + target_link_libraries(${the_target} ${CUDA_npp_LIBRARY}) endif() if(MSVC) - if(CMAKE_CROSSCOMPILING) - set_target_properties(${the_target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:secchk") - endif() - - set_target_properties(${the_target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:libc") + if(CMAKE_CROSSCOMPILING) + set_target_properties(${the_target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:secchk") + endif() + + set_target_properties(${the_target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:libc") endif() # Dependencies of this target: @@ -149,19 +141,19 @@ add_dependencies(${the_target} ${DEPS}) install(TARGETS ${the_target} RUNTIME DESTINATION bin COMPONENT main - LIBRARY DESTINATION lib COMPONENT main - ARCHIVE DESTINATION lib COMPONENT main) + LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main + ARCHIVE DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT main) install(FILES ${lib_hdrs} - DESTINATION include/opencv2/${name} + DESTINATION ${OPENCV_INCLUDE_PREFIX}/opencv2/${name} COMPONENT main) install(FILES src/nvidia/NPP_staging/NPP_staging.hpp src/nvidia/core/NCV.hpp - DESTINATION include/opencv2/${name} + DESTINATION ${OPENCV_INCLUDE_PREFIX}/opencv2/${name} COMPONENT main) #install(FILES ${lib_device_hdrs} -# DESTINATION include/opencv2/${name}/device +# DESTINATION ${OPENCV_INCLUDE_PREFIX}/opencv2/${name}/device # COMPONENT main) @@ -181,11 +173,8 @@ if(BUILD_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test) set(test_deps opencv_${name} opencv_ts opencv_highgui opencv_calib3d ${DEPS}) foreach(d ${test_deps}) if(${d} MATCHES "opencv_") - if(${d} MATCHES "opencv_lapack") - else() - string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d}) - include_directories("${d_dir}/include") - endif() + string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d}) + include_directories("${d_dir}/include") endif() endforeach() @@ -203,17 +192,7 @@ if(BUILD_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test) add_executable(${the_test_target} ${test_srcs} ${test_hdrs} ${nvidia}) - if(PCHSupport_FOUND) - set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/test/test_precomp.hpp) - if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*") - if(${CMAKE_GENERATOR} MATCHES "Visual*") - set(${the_test_target}_pch "test/test_precomp.cpp") - endif() - add_native_precompiled_header(${the_test_target} ${pch_header}) - elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles") - add_precompiled_header(${the_test_target} ${pch_header}) - endif() - endif() + add_opencv_precompiled_headers(${the_test_target}) # Additional target properties set_target_properties(${the_test_target} PROPERTIES @@ -223,7 +202,7 @@ if(BUILD_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test) if(ENABLE_SOLUTION_FOLDERS) set_target_properties(${the_test_target} PROPERTIES FOLDER "tests") - endif() + endif() add_dependencies(${the_test_target} ${test_deps}) diff --git a/modules/gpu/doc/camera_calibration_and_3d_reconstruction.rst b/modules/gpu/doc/camera_calibration_and_3d_reconstruction.rst index 13b654925e..423f7233b7 100644 --- a/modules/gpu/doc/camera_calibration_and_3d_reconstruction.rst +++ b/modules/gpu/doc/camera_calibration_and_3d_reconstruction.rst @@ -3,8 +3,6 @@ Camera Calibration and 3D Reconstruction .. highlight:: cpp -.. index:: gpu::StereoBM_GPU - gpu::StereoBM_GPU ----------------- .. ocv:class:: gpu::StereoBM_GPU @@ -87,16 +85,12 @@ gpu::StereoBM_GPU::operator () :param stream: Stream for the asynchronous version. -.. index:: gpu::StereoBM_GPU::checkIfGpuCallReasonable - gpu::StereoBM_GPU::checkIfGpuCallReasonable ----------------------------------------------- .. ocv:function:: bool gpu::StereoBM_GPU::checkIfGpuCallReasonable() Uses a heuristic method to estimate whether the current GPU is faster than the CPU in this algorithm. It queries the currently active device. -.. index:: gpu::StereoBeliefPropagation - gpu::StereoBeliefPropagation ---------------------------- .. ocv:class:: gpu::StereoBeliefPropagation @@ -163,8 +157,6 @@ The class implements algorithm described in [Felzenszwalb2006]_ . It can compute ``width_step`` is the number of bytes in a line including padding. -.. index:: gpu::StereoBeliefPropagation::StereoBeliefPropagation - gpu::StereoBeliefPropagation::StereoBeliefPropagation --------------------------------------------------------- .. ocv:function:: gpu::StereoBeliefPropagation::StereoBeliefPropagation( int ndisp = DEFAULT_NDISP, int iters = DEFAULT_ITERS, int levels = DEFAULT_LEVELS, int msg_type = CV_32F) @@ -207,8 +199,6 @@ By default, :ocv:class:`StereoBeliefPropagation` uses floating-point arithmetics 10 \cdot 2^{levels-1} \cdot max \_ data \_ term < SHRT \_ MAX -.. index:: gpu::StereoBeliefPropagation::estimateRecommendedParams - gpu::StereoBeliefPropagation::estimateRecommendedParams ----------------------------------------------------------- @@ -216,36 +206,28 @@ gpu::StereoBeliefPropagation::estimateRecommendedParams Uses a heuristic method to compute the recommended parameters (``ndisp``, ``iters`` and ``levels``) for the specified image size (``width`` and ``height``). -.. index:: gpu::StereoBeliefPropagation::operator () - gpu::StereoBeliefPropagation::operator () --------------------------------------------- .. ocv:function:: void gpu::StereoBeliefPropagation::operator()( const GpuMat& left, const GpuMat& right, GpuMat& disparity) .. ocv:function:: void gpu::StereoBeliefPropagation::operator()( const GpuMat& left, const GpuMat& right, GpuMat& disparity, Stream& stream) +.. ocv:function:: void gpu::StereoBeliefPropagation::operator()( const GpuMat& data, GpuMat& disparity) + +.. ocv:function:: void gpu::StereoBeliefPropagation::operator()( const GpuMat& data, GpuMat& disparity, Stream& stream) + Enables the stereo correspondence operator that finds the disparity for the specified rectified stereo pair or data cost. :param left: Left image. ``CV_8UC1`` , ``CV_8UC3`` and ``CV_8UC4`` types are supported. :param right: Right image with the same size and the same type as the left one. - :param disparity: Output disparity map. If ``disparity`` is empty, the output type is ``CV_16SC1`` . Otherwise, the output type is ``disparity.type()`` . - - :param stream: Stream for the asynchronous version. - -.. ocv:function:: void gpu::StereoBeliefPropagation::operator()( const GpuMat& data, GpuMat& disparity) - -.. ocv:function:: void gpu::StereoBeliefPropagation::operator()( const GpuMat& data, GpuMat& disparity, Stream& stream) - :param data: User-specified data cost, a matrix of ``msg_type`` type and ``Size(*ndisp, )`` size. - :param disparity: Output disparity map. If the matrix is empty, it is created as the ``CV_16SC1`` matrix. Otherwise, the type is retained. + :param disparity: Output disparity map. If ``disparity`` is empty, the output type is ``CV_16SC1`` . Otherwise, the type is retained. :param stream: Stream for the asynchronous version. -.. index:: gpu::StereoConstantSpaceBP - gpu::StereoConstantSpaceBP -------------------------- .. ocv:class:: gpu::StereoConstantSpaceBP @@ -303,8 +285,6 @@ Class computing stereo correspondence using the constant space belief propagatio The class implements algorithm described in [Yang2010]_. ``StereoConstantSpaceBP`` supports both local minimum and global minimum data cost initialization algortihms. For more details, see the paper mentioned above. By default, a local algorithm is used. To enable a global algorithm, set ``use_local_init_data_cost`` to ``false``. -.. index:: gpu::StereoConstantSpaceBP::StereoConstantSpaceBP - gpu::StereoConstantSpaceBP::StereoConstantSpaceBP ----------------------------------------------------- .. ocv:function:: gpu::StereoConstantSpaceBP::StereoConstantSpaceBP(int ndisp = DEFAULT_NDISP, int iters = DEFAULT_ITERS, int levels = DEFAULT_LEVELS, int nr_plane = DEFAULT_NR_PLANE, int msg_type = CV_32F) @@ -351,8 +331,6 @@ By default, ``StereoConstantSpaceBP`` uses floating-point arithmetics and the `` 10 \cdot 2^{levels-1} \cdot max \_ data \_ term < SHRT \_ MAX -.. index:: gpu::StereoConstantSpaceBP::estimateRecommendedParams - gpu::StereoConstantSpaceBP::estimateRecommendedParams --------------------------------------------------------- @@ -360,8 +338,6 @@ gpu::StereoConstantSpaceBP::estimateRecommendedParams Uses a heuristic method to compute parameters (ndisp, iters, levelsand nrplane) for the specified image size (widthand height). -.. index:: gpu::StereoConstantSpaceBP::operator () - gpu::StereoConstantSpaceBP::operator () ------------------------------------------- .. ocv:function:: void gpu::StereoConstantSpaceBP::operator()( const GpuMat& left, const GpuMat& right, GpuMat& disparity) @@ -378,10 +354,6 @@ gpu::StereoConstantSpaceBP::operator () :param stream: Stream for the asynchronous version. -.. index:: gpu::DisparityBilateralFilter - -.. _gpu::DisparityBilateralFilter: - gpu::DisparityBilateralFilter ----------------------------- .. ocv:class:: gpu::DisparityBilateralFilter @@ -413,8 +385,6 @@ Class refinining a disparity map using joint bilateral filtering. :: The class implements [Yang2010]_ algorithm. -.. index:: gpu::DisparityBilateralFilter::DisparityBilateralFilter - gpu::DisparityBilateralFilter::DisparityBilateralFilter ----------------------------------------------------------- .. ocv:function:: gpu::DisparityBilateralFilter::DisparityBilateralFilter( int ndisp = DEFAULT_NDISP, int radius = DEFAULT_RADIUS, int iters = DEFAULT_ITERS) @@ -435,8 +405,6 @@ gpu::DisparityBilateralFilter::DisparityBilateralFilter :param sigma_range: Filter range. -.. index:: gpu::DisparityBilateralFilter::operator () - gpu::DisparityBilateralFilter::operator () ---------------------------------------------- .. ocv:function:: void gpu::DisparityBilateralFilter::operator()( const GpuMat& disparity, const GpuMat& image, GpuMat& dst) @@ -453,8 +421,6 @@ gpu::DisparityBilateralFilter::operator () :param stream: Stream for the asynchronous version. -.. index:: gpu::drawColorDisp - gpu::drawColorDisp ---------------------- .. ocv:function:: void gpu::drawColorDisp(const GpuMat& src_disp, GpuMat& dst_disp, int ndisp) @@ -473,8 +439,6 @@ gpu::drawColorDisp This function draws a colored disparity map by converting disparity values from ``[0..ndisp)`` interval first to ``HSV`` color space (where different disparity values correspond to different hues) and then converting the pixels to ``RGB`` for visualization. -.. index:: gpu::reprojectImageTo3D - gpu::reprojectImageTo3D --------------------------- .. ocv:function:: void gpu::reprojectImageTo3D(const GpuMat& disp, GpuMat& xyzw, const Mat& Q) @@ -491,10 +455,6 @@ gpu::reprojectImageTo3D :param stream: Stream for the asynchronous version. -.. seealso:: :ocv:func:`reprojectImageTo3D` . - -.. index:: gpu::solvePnPRansac - gpu::solvePnPRansac ------------------- diff --git a/modules/gpu/doc/data_structures.rst b/modules/gpu/doc/data_structures.rst index d9442872e3..dd22f472f8 100644 --- a/modules/gpu/doc/data_structures.rst +++ b/modules/gpu/doc/data_structures.rst @@ -37,6 +37,7 @@ Lightweight class encapsulating pitched memory on a GPU and passed to nvcc-compi typedef DevMem2D_ DevMem2D; typedef DevMem2D_ DevMem2Df; typedef DevMem2D_ DevMem2Di; + .. @@ -108,6 +109,7 @@ Base storage class for GPU memory with reference counting. Its interface matches Beware that the latter limitation may lead to overloaded matrix operators that cause memory allocations. The ``GpuMat`` class is convertible to :ocv:class:`gpu::DevMem2D_` and :ocv:class:`gpu::PtrStep_` so it can be passed directly to the kernel. .. note:: In contrast with :ocv:class:`Mat`, in most cases ``GpuMat::isContinuous() == false`` . This means that rows are aligned to a size depending on the hardware. Single-row ``GpuMat`` is always a continuous matrix. + :: class CV_EXPORTS GpuMat @@ -144,10 +146,10 @@ Beware that the latter limitation may lead to overloaded matrix operators that c .. note:: - You are not recommended to leave static or global ``GpuMat`` variables allocated, that is, to rely on its destructor. The destruction order of such variables and CUDA context is undefined. GPU memory release function returns error if the CUDA context has been destroyed before. + You are not recommended to leave static or global ``GpuMat`` variables allocated, that is, to rely on its destructor. The destruction order of such variables and CUDA context is undefined. GPU memory release function returns error if the CUDA context has been destroyed before. .. seealso:: -:ocv:class:`Mat` + :ocv:class:`Mat` .. index:: gpu::CudaMem @@ -166,8 +168,8 @@ Class with reference counting wrapping special memory type allocation functions ``ALLOC_WRITE_COMBINED`` sets the write combined buffer that is not cached by CPU. Such buffers are used to supply GPU with data when GPU only reads it. The advantage is a better CPU cache utilization. .. note:: + Allocation size of such memory types is usually limited. For more details, see *CUDA 2.2 Pinned Memory APIs* document or *CUDA C Programming Guide*. - Allocation size of such memory types is usually limited. For more details, see *CUDA 2.2 Pinned Memory APIs* document or *CUDA C Programming Guide*. :: class CV_EXPORTS CudaMem @@ -235,8 +237,8 @@ gpu::Stream This class encapsulates a queue of asynchronous calls. Some functions have overloads with the additional ``gpu::Stream`` parameter. The overloads do initialization work (allocate output buffers, upload constants, and so on), start the GPU kernel, and return before results are ready. You can check whether all operations are complete via :ocv:func:`gpu::Stream::queryIfComplete`. You can asynchronously upload/download data from/to page-locked buffers, using the :ocv:class:`gpu::CudaMem` or :ocv:class:`Mat` header that points to a region of :ocv:class:`gpu::CudaMem`. .. note:: - - Currently, you may face problems if an operation is enqueued twice with different data. Some functions use the constant GPU memory, and next call may update the memory before the previous one has been finished. But calling different operations asynchronously is safe because each operation has its own constant buffer. Memory copy/upload/download/set operations to the buffers you hold are also safe. + Currently, you may face problems if an operation is enqueued twice with different data. Some functions use the constant GPU memory, and next call may update the memory before the previous one has been finished. But calling different operations asynchronously is safe because each operation has its own constant buffer. Memory copy/upload/download/set operations to the buffers you hold are also safe. + :: class CV_EXPORTS Stream @@ -324,11 +326,11 @@ gpu::createContinuous The following wrappers are also available: - * .. ocv:function:: GpuMat gpu::createContinuous(int rows, int cols, int type) + * .. ocv:function:: GpuMat gpu::createContinuous(int rows, int cols, int type) - * .. ocv:function:: void gpu::createContinuous(Size size, int type, GpuMat& m) + * .. ocv:function:: void gpu::createContinuous(Size size, int type, GpuMat& m) - * .. ocv:function:: GpuMat gpu::createContinuous(Size size, int type) + * .. ocv:function:: GpuMat gpu::createContinuous(Size size, int type) Matrix is called continuous if its elements are stored continuously, that is, without gaps at the end of each row. diff --git a/modules/gpu/doc/feature_detection_and_description.rst b/modules/gpu/doc/feature_detection_and_description.rst index ef4b5528ab..af95c2bba2 100644 --- a/modules/gpu/doc/feature_detection_and_description.rst +++ b/modules/gpu/doc/feature_detection_and_description.rst @@ -3,7 +3,7 @@ Feature Detection and Description .. highlight:: cpp -.. index:: gpu::SURF_GPU + gpu::SURF_GPU ------------- @@ -97,9 +97,9 @@ The ``descriptors`` matrix is :math:`\texttt{nFeatures} \times \texttt{descripto The class ``SURF_GPU`` uses some buffers and provides access to it. All buffers can be safely released between function calls. .. seealso:: -:ocv:class:`SURF` + :ocv:class:`SURF` + -.. index:: gpu::BruteForceMatcher_GPU gpu::BruteForceMatcher_GPU -------------------------- @@ -193,10 +193,10 @@ Brute-force descriptor matcher. For each descriptor in the first set, this match The class ``BruteForceMatcher_GPU`` has an interface similar to the class :ocv:class:`DescriptorMatcher`. It has two groups of ``match`` methods: for matching descriptors of one image with another image or with an image set. Also, all functions have an alternative to save results either to the GPU memory or to the CPU memory. The ``Distance`` template parameter is kept for CPU/GPU interfaces similarity. ``BruteForceMatcher_GPU`` supports only the ``L1``, ``L2``, and ``Hamming`` distance types. .. seealso:: -:ocv:class:`DescriptorMatcher`, -:ocv:class:`BruteForceMatcher` + :ocv:class:`DescriptorMatcher`, + :ocv:class:`BruteForceMatcher` + -.. index:: gpu::BruteForceMatcher_GPU::match gpu::BruteForceMatcher_GPU::match ------------------------------------- @@ -207,9 +207,9 @@ gpu::BruteForceMatcher_GPU::match Finds the best match for each descriptor from a query set with train descriptors. .. seealso:: -:ocv:func:`DescriptorMatcher::match` + :ocv:func:`DescriptorMatcher::match` + -.. index:: gpu::BruteForceMatcher_GPU::matchSingle gpu::BruteForceMatcher_GPU::matchSingle ------------------------------------------- @@ -227,13 +227,13 @@ gpu::BruteForceMatcher_GPU::matchSingle :param mask: Mask specifying permissible matches between the input query and train matrices of descriptors. -.. index:: gpu::BruteForceMatcher_GPU::matchCollection + gpu::BruteForceMatcher_GPU::matchCollection ----------------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::matchCollection(const GpuMat& queryDescs, const GpuMat& trainCollection, GpuMat& trainIdx, GpuMat& imgIdx, GpuMat& distance, const GpuMat& maskCollection) - Finds the best match for each query descriptor from train collection. Results are stored in the GPU memory. + Finds the best match for each query descriptor from train collection. Results are stored in the GPU memory. :param queryDescs: Query set of descriptors. @@ -247,16 +247,16 @@ gpu::BruteForceMatcher_GPU::matchCollection :param maskCollection: ``GpuMat`` containing a set of masks. It can be obtained from ``std::vector`` by :ocv:func:`gpu::BruteForceMatcher_GPU::makeGpuCollection` or it may contain a user-defined mask set. This is an empty matrix or one-row matrix where each element is a ``PtrStep`` that points to one mask. -.. index:: gpu::BruteForceMatcher_GPU::makeGpuCollection + gpu::BruteForceMatcher_GPU::makeGpuCollection ------------------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::makeGpuCollection(GpuMat& trainCollection, GpuMat& maskCollection, const vector&masks = std::vector()) - Performs a GPU collection of train descriptors and masks in a suitable format for the - :ocv:func:`gpu::BruteForceMatcher_GPU::matchCollection` function. + Performs a GPU collection of train descriptors and masks in a suitable format for the + :ocv:func:`gpu::BruteForceMatcher_GPU::matchCollection` function. + -.. index:: gpu::BruteForceMatcher_GPU::matchDownload gpu::BruteForceMatcher_GPU::matchDownload --------------------------------------------- @@ -264,30 +264,21 @@ gpu::BruteForceMatcher_GPU::matchDownload .. ocv:function:: void gpu::BruteForceMatcher_GPU::matchDownload(const GpuMat& trainIdx, GpuMat& imgIdx, const GpuMat& distance, std::vector&matches) - Downloads ``trainIdx``, ``imgIdx``, and ``distance`` matrices obtained via - :ocv:func:`gpu::BruteForceMatcher_GPU::matchSingle` or - :ocv:func:`gpu::BruteForceMatcher_GPU::matchCollection` to CPU vector with :ocv:class:`DMatch`. + Downloads ``trainIdx``, ``imgIdx``, and ``distance`` matrices obtained via + :ocv:func:`gpu::BruteForceMatcher_GPU::matchSingle` or + :ocv:func:`gpu::BruteForceMatcher_GPU::matchCollection` to CPU vector with :ocv:class:`DMatch`. + -.. index:: gpu::BruteForceMatcher_GPU::knnMatch gpu::BruteForceMatcher_GPU::knnMatch ---------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::knnMatch(const GpuMat& queryDescs, const GpuMat& trainDescs, std::vector< std::vector >&matches, int k, const GpuMat& mask = GpuMat(), bool compactResult = false) - Finds the k best matches for each descriptor from a query set with train descriptors. The function returns detected k (or less if not possible) matches in the increasing order by distance. +.. ocv:function:: void gpu::BruteForceMatcher_GPU::knnMatch(const GpuMat& queryDescs, std::vector< std::vector >&matches, int k, const std::vector&masks = std::vector(), bool compactResult = false ) -.. ocv:function:: void knnMatch(const GpuMat& queryDescs, std::vector< std::vector >&matches, int k, const std::vector&masks = std::vector(), bool compactResult = false ) - -.. seealso:: -:ocv:func:`DescriptorMatcher::knnMatch` - -.. index:: gpu::BruteForceMatcher_GPU::knnMatch - -gpu::BruteForceMatcher_GPU::knnMatch ----------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::knnMatch(const GpuMat& queryDescs, const GpuMat& trainDescs, GpuMat& trainIdx, GpuMat& distance, GpuMat& allDist, int k, const GpuMat& mask = GpuMat()) - Finds the k best matches for each descriptor from a query set with train descriptors. The function returns detected k (or less if not possible) matches in the increasing order by distance. Results are stored in the GPU memory. + Finds the k best matches for each descriptor from a query set with train descriptors. The function returns detected k (or less if not possible) matches in the increasing order by distance. :param queryDescs: Query set of descriptors. :param trainDescs: Training set of descriptors. It is not be added to train descriptors collection stored in the class object. @@ -299,7 +290,11 @@ gpu::BruteForceMatcher_GPU::knnMatch :param mask: Mask specifying permissible matches between the input query and train matrices of descriptors. -.. index:: gpu::BruteForceMatcher_GPU::knnMatchDownload +The third variant of the method stores the results in GPU memory. + +.. seealso:: + :ocv:func:`DescriptorMatcher::knnMatch` + gpu::BruteForceMatcher_GPU::knnMatchDownload ------------------------------------------------ @@ -307,28 +302,17 @@ gpu::BruteForceMatcher_GPU::knnMatchDownload Downloads ``trainIdx`` and ``distance`` matrices obtained via :ocv:func:`gpu::BruteForceMatcher_GPU::knnMatch` to CPU vector with :ocv:class:`DMatch`. If ``compactResult`` is true, the ``matches`` vector does not contain matches for fully masked-out query descriptors. -.. index:: gpu::BruteForceMatcher_GPU::radiusMatch + gpu::BruteForceMatcher_GPU::radiusMatch ------------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::radiusMatch(const GpuMat& queryDescs, const GpuMat& trainDescs, std::vector< std::vector >&matches, float maxDistance, const GpuMat& mask = GpuMat(), bool compactResult = false) - For each query descriptor, finds the best matches with a distance less than a given threshold. The function returns detected matches in the increasing order by distance. - .. ocv:function:: void gpu::BruteForceMatcher_GPU::radiusMatch(const GpuMat& queryDescs, std::vector< std::vector >&matches, float maxDistance, const std::vector&masks = std::vector(), bool compactResult = false) -This function works only on devices with the compute capability :math:`>=` 1.1. - -.. seealso:: -:ocv:func:`DescriptorMatcher::radiusMatch` - -.. index:: gpu::BruteForceMatcher_GPU::radiusMatch - -gpu::BruteForceMatcher_GPU::radiusMatch -------------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::radiusMatch(const GpuMat& queryDescs, const GpuMat& trainDescs, GpuMat& trainIdx, GpuMat& nMatches, GpuMat& distance, float maxDistance, const GpuMat& mask = GpuMat()) - For each query descriptor, finds the best matches with a distance less than a given threshold (``maxDistance``). The results are stored in the GPU memory. + For each query descriptor, finds the best matches with a distance less than a given threshold. The function returns detected matches in the increasing order by distance. :param queryDescs: Query set of descriptors. @@ -344,13 +328,16 @@ gpu::BruteForceMatcher_GPU::radiusMatch :param mask: Mask specifying permissible matches between the input query and train matrices of descriptors. - In contrast to :ocv:func:`gpu::BruteForceMatcher_GPU::knnMatch`, here the results are not sorted by the distance. This function works only on devices with the compute capability >= 1.1. +The methods work only on devices with the compute capability :math:`>=` 1.1. +The third variant of the method stores the results in GPU memory and does not store the points by the distance. + +.. seealso:: + :ocv:func:`DescriptorMatcher::radiusMatch` -.. index:: gpu::BruteForceMatcher_GPU::radiusMatchDownload gpu::BruteForceMatcher_GPU::radiusMatchDownload --------------------------------------------------- .. ocv:function:: void gpu::BruteForceMatcher_GPU::radiusMatchDownload(const GpuMat& trainIdx, const GpuMat& nMatches, const GpuMat& distance, std::vector< std::vector >&matches, bool compactResult = false) - Downloads ``trainIdx``, ``nMatches`` and ``distance`` matrices obtained via :ocv:func:`gpu::BruteForceMatcher_GPU::radiusMatch` to CPU vector with :ocv:class:`DMatch`. If ``compactResult`` is true, the ``matches`` vector does not contain matches for fully masked-out query descriptors. + Downloads ``trainIdx``, ``nMatches`` and ``distance`` matrices obtained via :ocv:func:`gpu::BruteForceMatcher_GPU::radiusMatch` to CPU vector with :ocv:class:`DMatch`. If ``compactResult`` is true, the ``matches`` vector does not contain matches for fully masked-out query descriptors. diff --git a/modules/gpu/doc/image_filtering.rst b/modules/gpu/doc/image_filtering.rst index cb066be5d0..9b5521d310 100644 --- a/modules/gpu/doc/image_filtering.rst +++ b/modules/gpu/doc/image_filtering.rst @@ -116,17 +116,17 @@ By using ``FilterEngine_GPU`` instead of functions you can avoid unnecessary mem .. seealso:: - :ocv:class:`gpu::BaseRowFilter_GPU`, - :ocv:class:`gpu::BaseColumnFilter_GPU`, - :ocv:class:`gpu::BaseFilter_GPU`, - :ocv:func:`gpu::createFilter2D_GPU`, - :ocv:func:`gpu::createSeparableFilter_GPU`, - :ocv:func:`gpu::createBoxFilter_GPU`, - :ocv:func:`gpu::createMorphologyFilter_GPU`, - :ocv:func:`gpu::createLinearFilter_GPU`, - :ocv:func:`gpu::createSeparableLinearFilter_GPU`, - :ocv:func:`gpu::createDerivFilter_GPU`, - :ocv:func:`gpu::createGaussianFilter_GPU` + :ocv:class:`gpu::BaseRowFilter_GPU`, + :ocv:class:`gpu::BaseColumnFilter_GPU`, + :ocv:class:`gpu::BaseFilter_GPU`, + :ocv:func:`gpu::createFilter2D_GPU`, + :ocv:func:`gpu::createSeparableFilter_GPU`, + :ocv:func:`gpu::createBoxFilter_GPU`, + :ocv:func:`gpu::createMorphologyFilter_GPU`, + :ocv:func:`gpu::createLinearFilter_GPU`, + :ocv:func:`gpu::createSeparableLinearFilter_GPU`, + :ocv:func:`gpu::createDerivFilter_GPU`, + :ocv:func:`gpu::createGaussianFilter_GPU` .. index:: gpu::createFilter2D_GPU @@ -240,7 +240,7 @@ gpu::boxFilter :param anchor: Anchor point. The default value ``Point(-1, -1)`` means that the anchor is at the kernel center. - .. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. + .. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. .. seealso:: :ocv:func:`boxFilter` @@ -307,8 +307,8 @@ gpu::erode :param iterations: Number of times erosion to be applied. .. note:: - - This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. + + This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. .. seealso:: :ocv:func:`erode` @@ -365,7 +365,7 @@ gpu::morphologyEx :param iterations: Number of times erosion and dilation to be applied. -.. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. +.. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. .. seealso:: :ocv:func:`morphologyEx` @@ -410,8 +410,8 @@ gpu::filter2D :param kernel: 2D array of filter coefficients. This filter works with integers kernels. If ``kernel`` has a ``float`` or ``double`` type, it uses fixed-point arithmetic. :param anchor: Anchor of the kernel that indicates the relative position of a filtered point within the kernel. The anchor resides within the kernel. The special default value (-1,-1) means that the anchor is at the kernel cente - - This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. + + This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. .. seealso:: :ocv:func:`filter2D` @@ -433,7 +433,7 @@ gpu::Laplacian :param scale: Optional scale factor for the computed Laplacian values. By default, no scaling is applied (see :ocv:func:`getDerivKernels` ). -.. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. +.. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. .. seealso:: :ocv:func:`Laplacian`,:ocv:func:`gpu::filter2D` . @@ -455,7 +455,7 @@ gpu::getLinearRowFilter_GPU :param borderType: Pixel extrapolation method. For details, see :ocv:func:`borderInterpolate`. For details on limitations, see below. - There are two versions of the algorithm: NPP and OpenCV. +There are two versions of the algorithm: NPP and OpenCV. * NPP version is called when ``srcType == CV_8UC1`` or ``srcType == CV_8UC4`` and ``bufType == srcType`` . Otherwise, the OpenCV version is called. NPP supports only ``BORDER_CONSTANT`` border type and does not check indices outside the image. @@ -481,10 +481,10 @@ gpu::getLinearColumnFilter_GPU :param borderType: Pixel extrapolation method. For details, see :ocv:func:`borderInterpolate` . For details on limitations, see below. - There are two versions of the algorithm: NPP and OpenCV. - * NPP version is called when ``dstType == CV_8UC1`` or ``dstType == CV_8UC4`` and ``bufType == dstType`` . Otherwise, the OpenCV version is called. NPP supports only ``BORDER_CONSTANT`` border type and does not check indices outside the image. - * OpenCV version supports only ``CV_32F`` buffer depth and ``BORDER_REFLECT101``, ``BORDER_REPLICATE``, and ``BORDER_CONSTANT`` border types. It checks indices outside image. - + There are two versions of the algorithm: NPP and OpenCV. + * NPP version is called when ``dstType == CV_8UC1`` or ``dstType == CV_8UC4`` and ``bufType == dstType`` . Otherwise, the OpenCV version is called. NPP supports only ``BORDER_CONSTANT`` border type and does not check indices outside the image. + * OpenCV version supports only ``CV_32F`` buffer depth and ``BORDER_REFLECT101``, ``BORDER_REPLICATE``, and ``BORDER_CONSTANT`` border types. It checks indices outside image. + .. seealso:: :ocv:func:`gpu::getLinearRowFilter_GPU`, :ocv:func:`createSeparableLinearFilter` .. index:: gpu::createSeparableLinearFilter_GPU @@ -696,4 +696,4 @@ gpu::getMinFilter_GPU :param anchor: Anchor point. The default value (-1) means that the anchor is at the kernel center. - .. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. + .. note:: This filter does not check out-of-border accesses, so only a proper sub-matrix of a bigger matrix has to be passed to it. diff --git a/modules/gpu/doc/image_processing.rst b/modules/gpu/doc/image_processing.rst index 9ed7e59452..60c2e4d6f5 100644 --- a/modules/gpu/doc/image_processing.rst +++ b/modules/gpu/doc/image_processing.rst @@ -44,7 +44,6 @@ gpu::meanShiftProc .. seealso:: :ocv:func:`gpu::meanShiftFiltering` - gpu::meanShiftSegmentation ------------------------------ .. ocv:function:: void gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, int minsize, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)) @@ -128,7 +127,6 @@ gpu::cornerHarris .. seealso:: :ocv:func:`cornerHarris` - gpu::cornerMinEigenVal -------------------------- .. ocv:function:: void gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, int borderType=BORDER_REFLECT101) @@ -172,7 +170,6 @@ gpu::mulSpectrums .. seealso:: :ocv:func:`mulSpectrums` - gpu::mulAndScaleSpectrums ----------------------------- .. ocv:function:: void gpu::mulAndScaleSpectrums(const GpuMat& a, const GpuMat& b, GpuMat& c, int flags, float scale, bool conjB=false) @@ -321,7 +318,6 @@ gpu::matchTemplate .. seealso:: :ocv:func:`matchTemplate` - gpu::remap -------------- .. ocv:function:: void gpu::remap(const GpuMat& src, GpuMat& dst, const GpuMat& xmap, const GpuMat& ymap) @@ -347,7 +343,6 @@ Values of pixels with non-integer coordinates are computed using the bilinear in .. seealso:: :ocv:func:`remap` - gpu::cvtColor ----------------- .. ocv:function:: void gpu::cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn = 0) @@ -518,7 +513,6 @@ gpu::copyMakeBorder .. seealso:: :ocv:func:`copyMakeBorder` - gpu::rectStdDev ------------------- .. ocv:function:: void gpu::rectStdDev(const GpuMat& src, const GpuMat& sqr, GpuMat& dst, const Rect& rect) diff --git a/modules/gpu/doc/initalization_and_information.rst b/modules/gpu/doc/initalization_and_information.rst index cc1e0dcf30..1308cec5f3 100644 --- a/modules/gpu/doc/initalization_and_information.rst +++ b/modules/gpu/doc/initalization_and_information.rst @@ -166,9 +166,9 @@ Class providing a set of static methods to check what NVIDIA* card architecture The following method checks whether the module was built with the support of the given feature: - .. ocv:function:: static bool gpu::TargetArchs::builtWith(GpuFeature feature) + .. ocv:function:: static bool gpu::TargetArchs::builtWith(GpuFeature feature) - :param feature: Feature to be checked. See :ocv:class:`gpu::GpuFeature`. + :param feature: Feature to be checked. See :ocv:class:`gpu::GpuFeature`. There is a set of methods to check whether the module contains intermediate (PTX) or binary GPU code for the given architecture(s): diff --git a/modules/gpu/doc/introduction.rst b/modules/gpu/doc/introduction.rst index 775326d1c8..2d2da7fe4a 100644 --- a/modules/gpu/doc/introduction.rst +++ b/modules/gpu/doc/introduction.rst @@ -49,7 +49,7 @@ The OpenCV GPU module follows the CUDA Runtime API conventions regarding the mul It is also possible to create the context explicitly using the CUDA Driver API, attach, and set the "current" context for all necessary threads. The CUDA Runtime API (and OpenCV functions, respectively) picks it up. Utilizing Multiple GPUs ---------- +----------------------- In the current version, each of the OpenCV GPU algorithms can use only a single GPU. So, to utilize multiple GPUs, you have to manually distribute the work between GPUs. Consider the following ways of utilizing multiple GPUs: @@ -74,5 +74,5 @@ While developing algorithms for multiple GPUs, note a data passing overhead. For With this algorithm, a dual GPU gave a 180 % performance increase comparing to the single Fermi GPU. For a source code example, see -https://code.ros.org/svn/opencv/trunk/opencv/examples/gpu/. +https://code.ros.org/svn/opencv/trunk/opencv/samples/gpu/. diff --git a/modules/gpu/doc/matrix_reductions.rst b/modules/gpu/doc/matrix_reductions.rst index 99092354de..8a42cd0353 100644 --- a/modules/gpu/doc/matrix_reductions.rst +++ b/modules/gpu/doc/matrix_reductions.rst @@ -7,7 +7,7 @@ Matrix Reductions gpu::meanStdDev ------------------- -.. cpp:function:: void gpu::meanStdDev(const GpuMat\& mtx, Scalar\& mean, Scalar\& stddev) +.. ocv:function:: void gpu::meanStdDev(const GpuMat\& mtx, Scalar\& mean, Scalar\& stddev) Computes a mean value and a standard deviation of matrix elements. @@ -18,7 +18,7 @@ gpu::meanStdDev :param stddev: Standard deviation value. .. seealso:: -:ocv:func:`meanStdDev` + :ocv:func:`meanStdDev` .. index:: gpu::norm @@ -39,7 +39,7 @@ gpu::norm :param buf: Optional buffer to avoid extra memory allocations. It is resized automatically. .. seealso:: -:ocv:func:`norm` + :ocv:func:`norm` .. index:: gpu::sum @@ -56,7 +56,7 @@ gpu::sum :param buf: Optional buffer to avoid extra memory allocations. It is resized automatically. .. seealso:: -:ocv:func:`sum` + :ocv:func:`sum` .. index:: gpu::absSum @@ -107,9 +107,9 @@ gpu::minMax :param buf: Optional buffer to avoid extra memory allocations. It is resized automatically. The function does not work with ``CV_64F`` images on GPUs with the compute capability < 1.3. - + .. seealso:: -:ocv:func:`minMaxLoc` + :ocv:func:`minMaxLoc` .. index:: gpu::minMaxLoc @@ -137,10 +137,10 @@ gpu::minMaxLoc :param locbuf: Optional locations buffer to avoid extra memory allocations. It is resized automatically. - The function does not work with ``CV_64F`` images on GPU with the compute capability < 1.3. + The function does not work with ``CV_64F`` images on GPU with the compute capability < 1.3. .. seealso:: -:ocv:func:`minMaxLoc` + :ocv:func:`minMaxLoc` .. index:: gpu::countNonZero @@ -157,6 +157,6 @@ gpu::countNonZero :param buf: Optional buffer to avoid extra memory allocations. It is resized automatically. The function does not work with ``CV_64F`` images on GPUs with the compute capability < 1.3. - + .. seealso:: -:ocv:func:`countNonZero` + :ocv:func:`countNonZero` diff --git a/modules/gpu/doc/object_detection.rst b/modules/gpu/doc/object_detection.rst index e935beac2d..43c20e2c79 100644 --- a/modules/gpu/doc/object_detection.rst +++ b/modules/gpu/doc/object_detection.rst @@ -67,14 +67,9 @@ Interfaces of all methods are kept similar to the ``CPU HOG`` descriptor and det gpu::HOGDescriptor::HOGDescriptor ------------------------------------- -.. ocv:function:: gpu::HOGDescriptor::HOGDescriptor(Size win_size=Size(64, 128), - Size block_size=Size(16, 16), Size block_stride=Size(8, 8), - Size cell_size=Size(8, 8), int nbins=9, - double win_sigma=DEFAULT_WIN_SIGMA, - double threshold_L2hys=0.2, bool gamma_correction=true, - int nlevels=DEFAULT_NLEVELS)??check the output?? +.. ocv:function:: gpu::HOGDescriptor::HOGDescriptor(Size win_size=Size(64, 128), Size block_size=Size(16, 16), Size block_stride=Size(8, 8), Size cell_size=Size(8, 8), int nbins=9, double win_sigma=DEFAULT_WIN_SIGMA, double threshold_L2hys=0.2, bool gamma_correction=true, int nlevels=DEFAULT_NLEVELS) - Creates the ``HOG`` descriptor and detector. + Creates the ``HOG`` descriptor and detector. :param win_size: Detection window size. Align to block size and block stride. @@ -114,7 +109,7 @@ gpu::HOGDescriptor::getBlockHistogramSize gpu::HOGDescriptor::setSVMDetector -------------------------------------- -.. ocv:function:: void gpu::HOGDescriptor::setSVMDetector(const vector\& detector) +.. ocv:function:: void gpu::HOGDescriptor::setSVMDetector(const vector& detector) Sets coefficients for the linear SVM classifier. @@ -146,11 +141,9 @@ gpu::HOGDescriptor::getPeopleDetector64x128 gpu::HOGDescriptor::detect ------------------------------ -.. ocv:function:: void gpu::HOGDescriptor::detect(const GpuMat\& img, - vector\& found_locations, double hit_threshold=0, - Size win_stride=Size(), Size padding=Size())??see output?? +.. ocv:function:: void gpu::HOGDescriptor::detect(const GpuMat& img, vector& found_locations, double hit_threshold=0, Size win_stride=Size(), Size padding=Size()) - Performs object detection without a multi-scale window. + Performs object detection without a multi-scale window. :param img: Source image. ``CV_8UC1`` and ``CV_8UC4`` types are supported for now. @@ -166,12 +159,9 @@ gpu::HOGDescriptor::detect gpu::HOGDescriptor::detectMultiScale ---------------------------------------- -.. ocv:function:: void gpu::HOGDescriptor::detectMultiScale(const GpuMat\& img, - vector\& found_locations, double hit_threshold=0, - Size win_stride=Size(), Size padding=Size(), - double scale0=1.05, int group_threshold=2)??the same?? +.. ocv:function:: void gpu::HOGDescriptor::detectMultiScale(const GpuMat& img, vector& found_locations, double hit_threshold=0, Size win_stride=Size(), Size padding=Size(), double scale0=1.05, int group_threshold=2) - Performs object detection with a multi-scale window. + Performs object detection with a multi-scale window. :param img: Source image. See :ocv:func:`gpu::HOGDescriptor::detect` for type limitations. @@ -191,11 +181,9 @@ gpu::HOGDescriptor::detectMultiScale gpu::HOGDescriptor::getDescriptors -------------------------------------- -.. ocv:function:: void gpu::HOGDescriptor::getDescriptors(const GpuMat\& img, - Size win_stride, GpuMat\& descriptors, - int descr_format=DESCR_FORMAT_COL_BY_COL)?? the same?? +.. ocv:function:: void gpu::HOGDescriptor::getDescriptors(const GpuMat& img, Size win_stride, GpuMat& descriptors, int descr_format=DESCR_FORMAT_COL_BY_COL) - Returns block descriptors computed for the whole image. The function is mainly used to learn the classifier. + Returns block descriptors computed for the whole image. The function is mainly used to learn the classifier. :param img: Source image. See :ocv:func:`gpu::HOGDescriptor::detect` for type limitations. @@ -247,7 +235,7 @@ Cascade classifier class used for object detection. gpu::CascadeClassifier_GPU::CascadeClassifier_GPU ----------------------------------------------------- -.. ocv:function:: gpu::CascadeClassifier_GPU(const string\& filename) +.. ocv:function:: gpu::CascadeClassifier_GPU(const string& filename) Loads the classifier from a file. @@ -269,7 +257,7 @@ gpu::CascadeClassifier_GPU::empty gpu::CascadeClassifier_GPU::load ------------------------------------ -.. ocv:function:: bool gpu::CascadeClassifier_GPU::load(const string\& filename) +.. ocv:function:: bool gpu::CascadeClassifier_GPU::load(const string& filename) Loads the classifier from a file. The previous content is destroyed. @@ -287,7 +275,7 @@ gpu::CascadeClassifier_GPU::release gpu::CascadeClassifier_GPU::detectMultiScale ------------------------------------------------ -.. ocv:function:: int gpu::CascadeClassifier_GPU::detectMultiScale(const GpuMat\& image, GpuMat\& objectsBuf, double scaleFactor=1.2, int minNeighbors=4, Size minSize=Size()) +.. ocv:function:: int gpu::CascadeClassifier_GPU::detectMultiScale(const GpuMat& image, GpuMat& objectsBuf, double scaleFactor=1.2, int minNeighbors=4, Size minSize=Size()) Detects objects of different sizes in the input image. The detected objects are returned as a list of rectangles. @@ -302,6 +290,7 @@ gpu::CascadeClassifier_GPU::detectMultiScale :param minSize: Minimum possible object size. Objects smaller than that are ignored. The function returns the number of detected objects, so you can retrieve them as in the following example: + :: gpu::CascadeClassifier_GPU cascade_gpu(...); diff --git a/modules/gpu/doc/operations_on_matrices.rst b/modules/gpu/doc/operations_on_matrices.rst index ba9106a467..92d6c720ed 100644 --- a/modules/gpu/doc/operations_on_matrices.rst +++ b/modules/gpu/doc/operations_on_matrices.rst @@ -16,7 +16,7 @@ gpu::transpose :param dst: Destination matrix. .. seealso:: -:ocv:func:`transpose` + :ocv:func:`transpose` .. index:: gpu::flip @@ -40,7 +40,7 @@ gpu::flip .. seealso:: -:ocv:func:`flip` + :ocv:func:`flip` .. index:: gpu::LUT @@ -58,7 +58,7 @@ gpu::LUT .. seealso:: -:ocv:func:`LUT` + :ocv:func:`LUT` .. index:: gpu::merge @@ -83,7 +83,7 @@ gpu::merge :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`merge` + :ocv:func:`merge` .. index:: gpu::split @@ -106,7 +106,7 @@ gpu::split :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`split` + :ocv:func:`split` .. index:: gpu::magnitude @@ -131,7 +131,7 @@ gpu::magnitude :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`magnitude` + :ocv:func:`magnitude` .. index:: gpu::magnitudeSqr @@ -176,7 +176,7 @@ gpu::phase :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`phase` + :ocv:func:`phase` .. index:: gpu::cartToPolar @@ -201,7 +201,7 @@ gpu::cartToPolar :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`cartToPolar` + :ocv:func:`cartToPolar` .. index:: gpu::polarToCart @@ -226,4 +226,4 @@ gpu::polarToCart :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`polarToCart` + :ocv:func:`polarToCart` diff --git a/modules/gpu/doc/per_element_operations.rst b/modules/gpu/doc/per_element_operations.rst index 89c9870016..94ec745685 100644 --- a/modules/gpu/doc/per_element_operations.rst +++ b/modules/gpu/doc/per_element_operations.rst @@ -22,7 +22,7 @@ gpu::add :param dst: Destination matrix with the same size and type as ``src1``. .. seealso:: -:ocv:func:`add` + :ocv:func:`add` .. index:: gpu::subtract @@ -41,7 +41,7 @@ gpu::subtract :param dst: Destination matrix with the same size and type as ``src1``. .. seealso:: -:ocv:func:`subtract` + :ocv:func:`subtract` @@ -62,7 +62,7 @@ gpu::multiply :param dst: Destination matrix with the same size and type as ``src1``. .. seealso:: -:ocv:func:`multiply` + :ocv:func:`multiply` .. index:: gpu::divide @@ -84,7 +84,7 @@ gpu::divide This function, in contrast to :ocv:func:`divide`, uses a round-down rounding mode. .. seealso:: -:ocv:func:`divide` + :ocv:func:`divide` @@ -101,7 +101,7 @@ gpu::exp :param dst: Destination matrix with the same size and type as ``src``. .. seealso:: -:ocv:func:`exp` + :ocv:func:`exp` @@ -138,7 +138,7 @@ gpu::absdiff :param dst: Destination matrix with the same size and type as ``src1``. .. seealso:: -:ocv:func:`absdiff` + :ocv:func:`absdiff` .. index:: gpu::compare @@ -164,7 +164,7 @@ gpu::compare * **CMP_NE:** ``src1(.) != src2(.)`` .. seealso:: -:ocv:func:`compare` + :ocv:func:`compare` .. index:: gpu::bitwise_not @@ -276,7 +276,7 @@ gpu::min :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`min` + :ocv:func:`min` @@ -303,4 +303,4 @@ gpu::max :param stream: Stream for the asynchronous version. .. seealso:: -:ocv:func:`max` + :ocv:func:`max` diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index 7c1ebb786a..9ef46a477d 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -47,8 +47,8 @@ #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/objdetect/objdetect.hpp" -#include "opencv2/gpu/devmem2d.hpp" #include "opencv2/features2d/features2d.hpp" +#include "opencv2/gpu/gpumat.hpp" namespace cv { @@ -124,6 +124,8 @@ namespace cv // Checks whether the GPU module can be run on the given device bool isCompatible() const; + int deviceID() const { return device_id_; } + private: void query(); void queryMemory(size_t& free_memory, size_t& total_memory) const; @@ -141,188 +143,17 @@ namespace cv CV_EXPORTS void error(const char *error_string, const char *file, const int line, const char *func); CV_EXPORTS void nppError( int err, const char *file, const int line, const char *func); - //////////////////////////////// GpuMat //////////////////////////////// - class Stream; - class CudaMem; - - //! Smart pointer for GPU memory with reference counting. Its interface is mostly similar with cv::Mat. - class CV_EXPORTS GpuMat - { - public: - //! default constructor - GpuMat(); - //! constructs GpuMatrix of the specified size and type (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.) - GpuMat(int rows, int cols, int type); - GpuMat(Size size, int type); - //! constucts GpuMatrix and fills it with the specified value _s. - GpuMat(int rows, int cols, int type, const Scalar& s); - GpuMat(Size size, int type, const Scalar& s); - //! copy constructor - GpuMat(const GpuMat& m); - - //! constructor for GpuMatrix headers pointing to user-allocated data - GpuMat(int rows, int cols, int type, void* data, size_t step = Mat::AUTO_STEP); - GpuMat(Size size, int type, void* data, size_t step = Mat::AUTO_STEP); - - //! creates a matrix header for a part of the bigger matrix - GpuMat(const GpuMat& m, const Range& rowRange, const Range& colRange); - GpuMat(const GpuMat& m, const Rect& roi); - - //! builds GpuMat from Mat. Perfom blocking upload to device. - explicit GpuMat (const Mat& m); - - //! destructor - calls release() - ~GpuMat(); - - //! assignment operators - GpuMat& operator = (const GpuMat& m); - //! assignment operator. Perfom blocking upload to device. - GpuMat& operator = (const Mat& m); - - //! returns lightweight DevMem2D_ structure for passing to nvcc-compiled code. - // Contains just image size, data ptr and step. - template operator DevMem2D_() const; - template operator PtrStep_() const; - - //! pefroms blocking upload data to GpuMat. - void upload(const cv::Mat& m); - - //! upload async - void upload(const CudaMem& m, Stream& stream); - - //! downloads data from device to host memory. Blocking calls. - operator Mat() const; - void download(cv::Mat& m) const; - - //! download async - void download(CudaMem& m, Stream& stream) const; - - //! returns a new GpuMatrix header for the specified row - GpuMat row(int y) const; - //! returns a new GpuMatrix header for the specified column - GpuMat col(int x) const; - //! ... for the specified row span - GpuMat rowRange(int startrow, int endrow) const; - GpuMat rowRange(const Range& r) const; - //! ... for the specified column span - GpuMat colRange(int startcol, int endcol) const; - GpuMat colRange(const Range& r) const; - - //! returns deep copy of the GpuMatrix, i.e. the data is copied - GpuMat clone() const; - //! copies the GpuMatrix content to "m". - // It calls m.create(this->size(), this->type()). - void copyTo( GpuMat& m ) const; - //! copies those GpuMatrix elements to "m" that are marked with non-zero mask elements. - void copyTo( GpuMat& m, const GpuMat& mask ) const; - //! converts GpuMatrix to another datatype with optional scalng. See cvConvertScale. - void convertTo( GpuMat& m, int rtype, double alpha=1, double beta=0 ) const; - - void assignTo( GpuMat& m, int type=-1 ) const; - - //! sets every GpuMatrix element to s - GpuMat& operator = (const Scalar& s); - //! sets some of the GpuMatrix elements to s, according to the mask - GpuMat& setTo(const Scalar& s, const GpuMat& mask = GpuMat()); - //! creates alternative GpuMatrix header for the same data, with different - // number of channels and/or different number of rows. see cvReshape. - GpuMat reshape(int cn, int rows = 0) const; - - //! allocates new GpuMatrix data unless the GpuMatrix already has specified size and type. - // previous data is unreferenced if needed. - void create(int rows, int cols, int type); - void create(Size size, int type); - //! decreases reference counter; - // deallocate the data when reference counter reaches 0. - void release(); - - //! swaps with other smart pointer - void swap(GpuMat& mat); - - //! locates GpuMatrix header within a parent GpuMatrix. See below - void locateROI( Size& wholeSize, Point& ofs ) const; - //! moves/resizes the current GpuMatrix ROI inside the parent GpuMatrix. - GpuMat& adjustROI( int dtop, int dbottom, int dleft, int dright ); - //! extracts a rectangular sub-GpuMatrix - // (this is a generalized form of row, rowRange etc.) - GpuMat operator()( Range rowRange, Range colRange ) const; - GpuMat operator()( const Rect& roi ) const; - - //! returns true iff the GpuMatrix data is continuous - // (i.e. when there are no gaps between successive rows). - // similar to CV_IS_GpuMat_CONT(cvGpuMat->type) - bool isContinuous() const; - //! returns element size in bytes, - // similar to CV_ELEM_SIZE(cvMat->type) - size_t elemSize() const; - //! returns the size of element channel in bytes. - size_t elemSize1() const; - //! returns element type, similar to CV_MAT_TYPE(cvMat->type) - int type() const; - //! returns element type, similar to CV_MAT_DEPTH(cvMat->type) - int depth() const; - //! returns element type, similar to CV_MAT_CN(cvMat->type) - int channels() const; - //! returns step/elemSize1() - size_t step1() const; - //! returns GpuMatrix size: - // width == number of columns, height == number of rows - Size size() const; - //! returns true if GpuMatrix data is NULL - bool empty() const; - - //! returns pointer to y-th row - uchar* ptr(int y = 0); - const uchar* ptr(int y = 0) const; - - //! template version of the above method - template _Tp* ptr(int y = 0); - template const _Tp* ptr(int y = 0) const; - - //! matrix transposition - GpuMat t() const; - - /*! includes several bit-fields: - - the magic signature - - continuity flag - - depth - - number of channels - */ - int flags; - //! the number of rows and columns - int rows, cols; - //! a distance between successive rows in bytes; includes the gap if any - size_t step; - //! pointer to the data - uchar* data; - - //! pointer to the reference counter; - // when GpuMatrix points to user-allocated data, the pointer is NULL - int* refcount; - - //! helper fields used in locateROI and adjustROI - uchar* datastart; - uchar* dataend; - }; - -//#define TemplatedGpuMat // experimental now, deprecated to use -#ifdef TemplatedGpuMat - #include "GpuMat_BetaDeprecated.hpp" -#endif - - //! Creates continuous GPU matrix - CV_EXPORTS void createContinuous(int rows, int cols, int type, GpuMat& m); - - //! Ensures that size of the given matrix is not less than (rows, cols) size - //! and matrix type is match specified one too - CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, GpuMat& m); - //////////////////////////////// CudaMem //////////////////////////////// // CudaMem is limited cv::Mat with page locked memory allocation. // Page locked memory is only needed for async and faster coping to GPU. // It is convertable to cv::Mat header without reference counting // so you can use it with other opencv functions. + // Page-locks the matrix m memory and maps it for the device(s) + CV_EXPORTS void registerPageLocked(Mat& m); + // Unmaps the memory of matrix m, and makes it pageable again. + CV_EXPORTS void unregisterPageLocked(Mat& m); + class CV_EXPORTS CudaMem { public: @@ -439,372 +270,7 @@ namespace cv explicit Stream(Impl* impl); }; - - - ////////////////////////////// Arithmetics /////////////////////////////////// - - //! transposes the matrix - //! supports matrix with element size = 1, 4 and 8 bytes (CV_8UC1, CV_8UC4, CV_16UC2, CV_32FC1, etc) - CV_EXPORTS void transpose(const GpuMat& src1, GpuMat& dst, Stream& stream = Stream::Null()); - - //! reverses the order of the rows, columns or both in a matrix - //! supports CV_8UC1, CV_8UC4 types - CV_EXPORTS void flip(const GpuMat& a, GpuMat& b, int flipCode, Stream& stream = Stream::Null()); - - //! transforms 8-bit unsigned integers using lookup table: dst(i)=lut(src(i)) - //! destination array will have the depth type as lut and the same channels number as source - //! supports CV_8UC1, CV_8UC3 types - CV_EXPORTS void LUT(const GpuMat& src, const Mat& lut, GpuMat& dst, Stream& stream = Stream::Null()); - - //! makes multi-channel array out of several single-channel arrays - CV_EXPORTS void merge(const GpuMat* src, size_t n, GpuMat& dst, Stream& stream = Stream::Null()); - - //! makes multi-channel array out of several single-channel arrays - CV_EXPORTS void merge(const vector& src, GpuMat& dst, Stream& stream = Stream::Null()); - - //! copies each plane of a multi-channel array to a dedicated array - CV_EXPORTS void split(const GpuMat& src, GpuMat* dst, Stream& stream = Stream::Null()); - - //! copies each plane of a multi-channel array to a dedicated array - CV_EXPORTS void split(const GpuMat& src, vector& dst, Stream& stream = Stream::Null()); - - //! computes magnitude of complex (x(i).re, x(i).im) vector - //! supports only CV_32FC2 type - CV_EXPORTS void magnitude(const GpuMat& x, GpuMat& magnitude, Stream& stream = Stream::Null()); - - //! computes squared magnitude of complex (x(i).re, x(i).im) vector - //! supports only CV_32FC2 type - CV_EXPORTS void magnitudeSqr(const GpuMat& x, GpuMat& magnitude, Stream& stream = Stream::Null()); - - //! computes magnitude of each (x(i), y(i)) vector - //! supports only floating-point source - CV_EXPORTS void magnitude(const GpuMat& x, const GpuMat& y, GpuMat& magnitude, Stream& stream = Stream::Null()); - - //! computes squared magnitude of each (x(i), y(i)) vector - //! supports only floating-point source - CV_EXPORTS void magnitudeSqr(const GpuMat& x, const GpuMat& y, GpuMat& magnitude, Stream& stream = Stream::Null()); - - //! computes angle (angle(i)) of each (x(i), y(i)) vector - //! supports only floating-point source - CV_EXPORTS void phase(const GpuMat& x, const GpuMat& y, GpuMat& angle, bool angleInDegrees = false, Stream& stream = Stream::Null()); - - //! converts Cartesian coordinates to polar - //! supports only floating-point source - CV_EXPORTS void cartToPolar(const GpuMat& x, const GpuMat& y, GpuMat& magnitude, GpuMat& angle, bool angleInDegrees = false, Stream& stream = Stream::Null()); - - //! converts polar coordinates to Cartesian - //! supports only floating-point source - CV_EXPORTS void polarToCart(const GpuMat& magnitude, const GpuMat& angle, GpuMat& x, GpuMat& y, bool angleInDegrees = false, Stream& stream = Stream::Null()); - - - //////////////////////////// Per-element operations //////////////////////////////////// - - //! adds one matrix to another (c = a + b) - //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types - CV_EXPORTS void add(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); - //! adds scalar to a matrix (c = a + s) - //! supports CV_32FC1 and CV_32FC2 type - CV_EXPORTS void add(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); - - //! subtracts one matrix from another (c = a - b) - //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types - CV_EXPORTS void subtract(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); - //! subtracts scalar from a matrix (c = a - s) - //! supports CV_32FC1 and CV_32FC2 type - CV_EXPORTS void subtract(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); - - //! computes element-wise product of the two arrays (c = a * b) - //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types - CV_EXPORTS void multiply(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); - //! multiplies matrix to a scalar (c = a * s) - //! supports CV_32FC1 and CV_32FC2 type - CV_EXPORTS void multiply(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); - - //! computes element-wise quotient of the two arrays (c = a / b) - //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types - CV_EXPORTS void divide(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); - //! computes element-wise quotient of matrix and scalar (c = a / s) - //! supports CV_32FC1 and CV_32FC2 type - CV_EXPORTS void divide(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); - - //! computes exponent of each matrix element (b = e**a) - //! supports only CV_32FC1 type - CV_EXPORTS void exp(const GpuMat& a, GpuMat& b, Stream& stream = Stream::Null()); - - //! computes natural logarithm of absolute value of each matrix element: b = log(abs(a)) - //! supports only CV_32FC1 type - CV_EXPORTS void log(const GpuMat& a, GpuMat& b, Stream& stream = Stream::Null()); - - //! computes element-wise absolute difference of two arrays (c = abs(a - b)) - //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types - CV_EXPORTS void absdiff(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); - //! computes element-wise absolute difference of array and scalar (c = abs(a - s)) - //! supports only CV_32FC1 type - CV_EXPORTS void absdiff(const GpuMat& a, const Scalar& s, GpuMat& c, Stream& stream = Stream::Null()); - - //! compares elements of two arrays (c = a b) - //! supports CV_8UC4, CV_32FC1 types - CV_EXPORTS void compare(const GpuMat& a, const GpuMat& b, GpuMat& c, int cmpop, Stream& stream = Stream::Null()); - - //! performs per-elements bit-wise inversion - CV_EXPORTS void bitwise_not(const GpuMat& src, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); - - //! calculates per-element bit-wise disjunction of two arrays - CV_EXPORTS void bitwise_or(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); - - //! calculates per-element bit-wise conjunction of two arrays - CV_EXPORTS void bitwise_and(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); - - //! calculates per-element bit-wise "exclusive or" operation - CV_EXPORTS void bitwise_xor(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); - - //! computes per-element minimum of two arrays (dst = min(src1, src2)) - CV_EXPORTS void min(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, Stream& stream = Stream::Null()); - - //! computes per-element minimum of array and scalar (dst = min(src1, src2)) - CV_EXPORTS void min(const GpuMat& src1, double src2, GpuMat& dst, Stream& stream = Stream::Null()); - - //! computes per-element maximum of two arrays (dst = max(src1, src2)) - CV_EXPORTS void max(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, Stream& stream = Stream::Null()); - - //! computes per-element maximum of array and scalar (dst = max(src1, src2)) - CV_EXPORTS void max(const GpuMat& src1, double src2, GpuMat& dst, Stream& stream = Stream::Null()); - - - ////////////////////////////// Image processing ////////////////////////////// - - //! DST[x,y] = SRC[xmap[x,y],ymap[x,y]] with bilinear interpolation. - //! supports CV_8UC1, CV_8UC3 source types and CV_32FC1 map type - CV_EXPORTS void remap(const GpuMat& src, GpuMat& dst, const GpuMat& xmap, const GpuMat& ymap); - - //! Does mean shift filtering on GPU. - CV_EXPORTS void meanShiftFiltering(const GpuMat& src, GpuMat& dst, int sp, int sr, - TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); - - //! Does mean shift procedure on GPU. - CV_EXPORTS void meanShiftProc(const GpuMat& src, GpuMat& dstr, GpuMat& dstsp, int sp, int sr, - TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); - - //! Does mean shift segmentation with elimination of small regions. - CV_EXPORTS void meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, int minsize, - TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); - - //! Does coloring of disparity image: [0..ndisp) -> [0..240, 1, 1] in HSV. - //! Supported types of input disparity: CV_8U, CV_16S. - //! Output disparity has CV_8UC4 type in BGRA format (alpha = 255). - CV_EXPORTS void drawColorDisp(const GpuMat& src_disp, GpuMat& dst_disp, int ndisp, Stream& stream = Stream::Null()); - - //! Reprojects disparity image to 3D space. - //! Supports CV_8U and CV_16S types of input disparity. - //! The output is a 4-channel floating-point (CV_32FC4) matrix. - //! Each element of this matrix will contain the 3D coordinates of the point (x,y,z,1), computed from the disparity map. - //! Q is the 4x4 perspective transformation matrix that can be obtained with cvStereoRectify. - CV_EXPORTS void reprojectImageTo3D(const GpuMat& disp, GpuMat& xyzw, const Mat& Q, Stream& stream = Stream::Null()); - - //! converts image from one color space to another - CV_EXPORTS void cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn = 0, Stream& stream = Stream::Null()); - - //! applies fixed threshold to the image - CV_EXPORTS double threshold(const GpuMat& src, GpuMat& dst, double thresh, double maxval, int type, Stream& stream = Stream::Null()); - - //! resizes the image - //! Supports INTER_NEAREST, INTER_LINEAR - //! supports CV_8UC1, CV_8UC4 types - CV_EXPORTS void resize(const GpuMat& src, GpuMat& dst, Size dsize, double fx=0, double fy=0, int interpolation = INTER_LINEAR, Stream& stream = Stream::Null()); - - //! warps the image using affine transformation - //! Supports INTER_NEAREST, INTER_LINEAR, INTER_CUBIC - CV_EXPORTS void warpAffine(const GpuMat& src, GpuMat& dst, const Mat& M, Size dsize, int flags = INTER_LINEAR, Stream& stream = Stream::Null()); - - //! warps the image using perspective transformation - //! Supports INTER_NEAREST, INTER_LINEAR, INTER_CUBIC - CV_EXPORTS void warpPerspective(const GpuMat& src, GpuMat& dst, const Mat& M, Size dsize, int flags = INTER_LINEAR, Stream& stream = Stream::Null()); - - //! rotate 8bit single or four channel image - //! Supports INTER_NEAREST, INTER_LINEAR, INTER_CUBIC - //! supports CV_8UC1, CV_8UC4 types - CV_EXPORTS void rotate(const GpuMat& src, GpuMat& dst, Size dsize, double angle, double xShift = 0, double yShift = 0, int interpolation = INTER_LINEAR, Stream& stream = Stream::Null()); - - //! copies 2D array to a larger destination array and pads borders with user-specifiable constant - //! supports CV_8UC1, CV_8UC4, CV_32SC1 and CV_32FC1 types - CV_EXPORTS void copyMakeBorder(const GpuMat& src, GpuMat& dst, int top, int bottom, int left, int right, const Scalar& value = Scalar(), Stream& stream = Stream::Null()); - - //! computes the integral image - //! sum will have CV_32S type, but will contain unsigned int values - //! supports only CV_8UC1 source type - CV_EXPORTS void integral(const GpuMat& src, GpuMat& sum, Stream& stream = Stream::Null()); - - //! buffered version - CV_EXPORTS void integralBuffered(const GpuMat& src, GpuMat& sum, GpuMat& buffer, Stream& stream = Stream::Null()); - - //! computes the integral image and integral for the squared image - //! sum will have CV_32S type, sqsum - CV32F type - //! supports only CV_8UC1 source type - CV_EXPORTS void integral(const GpuMat& src, GpuMat& sum, GpuMat& sqsum, Stream& stream = Stream::Null()); - - //! computes squared integral image - //! result matrix will have 64F type, but will contain 64U values - //! supports source images of 8UC1 type only - CV_EXPORTS void sqrIntegral(const GpuMat& src, GpuMat& sqsum, Stream& stream = Stream::Null()); - - //! computes vertical sum, supports only CV_32FC1 images - CV_EXPORTS void columnSum(const GpuMat& src, GpuMat& sum); - - //! computes the standard deviation of integral images - //! supports only CV_32SC1 source type and CV_32FC1 sqr type - //! output will have CV_32FC1 type - CV_EXPORTS void rectStdDev(const GpuMat& src, const GpuMat& sqr, GpuMat& dst, const Rect& rect, Stream& stream = Stream::Null()); - - //! computes Harris cornerness criteria at each image pixel - CV_EXPORTS void cornerHarris(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, double k, int borderType=BORDER_REFLECT101); - - //! computes minimum eigen value of 2x2 derivative covariation matrix at each pixel - the cornerness criteria - CV_EXPORTS void cornerMinEigenVal(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, int borderType=BORDER_REFLECT101); - - //! performs per-element multiplication of two full (not packed) Fourier spectrums - //! supports 32FC2 matrixes only (interleaved format) - CV_EXPORTS void mulSpectrums(const GpuMat& a, const GpuMat& b, GpuMat& c, int flags, bool conjB=false); - - //! performs per-element multiplication of two full (not packed) Fourier spectrums - //! supports 32FC2 matrixes only (interleaved format) - CV_EXPORTS void mulAndScaleSpectrums(const GpuMat& a, const GpuMat& b, GpuMat& c, int flags, - float scale, bool conjB=false); - - //! Performs a forward or inverse discrete Fourier transform (1D or 2D) of floating point matrix. - //! Param dft_size is the size of DFT transform. - //! - //! If the source matrix is not continous, then additional copy will be done, - //! so to avoid copying ensure the source matrix is continous one. If you want to use - //! preallocated output ensure it is continuous too, otherwise it will be reallocated. - //! - //! Being implemented via CUFFT real-to-complex transform result contains only non-redundant values - //! in CUFFT's format. Result as full complex matrix for such kind of transform cannot be retrieved. - //! - //! For complex-to-real transform it is assumed that the source matrix is packed in CUFFT's format. - CV_EXPORTS void dft(const GpuMat& src, GpuMat& dst, Size dft_size, int flags=0); - - //! computes convolution (or cross-correlation) of two images using discrete Fourier transform - //! supports source images of 32FC1 type only - //! result matrix will have 32FC1 type - CV_EXPORTS void convolve(const GpuMat& image, const GpuMat& templ, GpuMat& result, - bool ccorr=false); - - struct CV_EXPORTS ConvolveBuf; - - //! buffered version - CV_EXPORTS void convolve(const GpuMat& image, const GpuMat& templ, GpuMat& result, - bool ccorr, ConvolveBuf& buf); - - struct CV_EXPORTS ConvolveBuf - { - ConvolveBuf() {} - ConvolveBuf(Size image_size, Size templ_size) - { create(image_size, templ_size); } - void create(Size image_size, Size templ_size); - - private: - static Size estimateBlockSize(Size result_size, Size templ_size); - friend void convolve(const GpuMat&, const GpuMat&, GpuMat&, bool, ConvolveBuf&); - - Size result_size; - Size block_size; - Size dft_size; - int spect_len; - - GpuMat image_spect, templ_spect, result_spect; - GpuMat image_block, templ_block, result_data; - }; - - //! computes the proximity map for the raster template and the image where the template is searched for - CV_EXPORTS void matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method); - - //! downsamples image - CV_EXPORTS void downsample(const GpuMat& src, GpuMat& dst, int k=2); - - //! performs linear blending of two images - //! to avoid accuracy errors sum of weigths shouldn't be very close to zero - CV_EXPORTS void blendLinear(const GpuMat& img1, const GpuMat& img2, const GpuMat& weights1, const GpuMat& weights2, - GpuMat& result, Stream& stream = Stream::Null()); - - ////////////////////////////// Matrix reductions ////////////////////////////// - - //! computes mean value and standard deviation of all or selected array elements - //! supports only CV_8UC1 type - CV_EXPORTS void meanStdDev(const GpuMat& mtx, Scalar& mean, Scalar& stddev); - - //! computes norm of array - //! supports NORM_INF, NORM_L1, NORM_L2 - //! supports all matrices except 64F - CV_EXPORTS double norm(const GpuMat& src1, int normType=NORM_L2); - - //! computes norm of array - //! supports NORM_INF, NORM_L1, NORM_L2 - //! supports all matrices except 64F - CV_EXPORTS double norm(const GpuMat& src1, int normType, GpuMat& buf); - - //! computes norm of the difference between two arrays - //! supports NORM_INF, NORM_L1, NORM_L2 - //! supports only CV_8UC1 type - CV_EXPORTS double norm(const GpuMat& src1, const GpuMat& src2, int normType=NORM_L2); - - //! computes sum of array elements - //! supports only single channel images - CV_EXPORTS Scalar sum(const GpuMat& src); - - //! computes sum of array elements - //! supports only single channel images - CV_EXPORTS Scalar sum(const GpuMat& src, GpuMat& buf); - - //! computes sum of array elements absolute values - //! supports only single channel images - CV_EXPORTS Scalar absSum(const GpuMat& src); - - //! computes sum of array elements absolute values - //! supports only single channel images - CV_EXPORTS Scalar absSum(const GpuMat& src, GpuMat& buf); - - //! computes squared sum of array elements - //! supports only single channel images - CV_EXPORTS Scalar sqrSum(const GpuMat& src); - - //! computes squared sum of array elements - //! supports only single channel images - CV_EXPORTS Scalar sqrSum(const GpuMat& src, GpuMat& buf); - - //! finds global minimum and maximum array elements and returns their values - CV_EXPORTS void minMax(const GpuMat& src, double* minVal, double* maxVal=0, const GpuMat& mask=GpuMat()); - - //! finds global minimum and maximum array elements and returns their values - CV_EXPORTS void minMax(const GpuMat& src, double* minVal, double* maxVal, const GpuMat& mask, GpuMat& buf); - - //! finds global minimum and maximum array elements and returns their values with locations - CV_EXPORTS void minMaxLoc(const GpuMat& src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, - const GpuMat& mask=GpuMat()); - - //! finds global minimum and maximum array elements and returns their values with locations - CV_EXPORTS void minMaxLoc(const GpuMat& src, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, - const GpuMat& mask, GpuMat& valbuf, GpuMat& locbuf); - - //! counts non-zero array elements - CV_EXPORTS int countNonZero(const GpuMat& src); - - //! counts non-zero array elements - CV_EXPORTS int countNonZero(const GpuMat& src, GpuMat& buf); - - - ///////////////////////////// Calibration 3D ////////////////////////////////// - - CV_EXPORTS void transformPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, - GpuMat& dst, Stream& stream = Stream::Null()); - - CV_EXPORTS void projectPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, - const Mat& camera_mat, const Mat& dist_coef, GpuMat& dst, - Stream& stream = Stream::Null()); - - CV_EXPORTS void solvePnPRansac(const Mat& object, const Mat& image, const Mat& camera_mat, - const Mat& dist_coef, Mat& rvec, Mat& tvec, bool use_extrinsic_guess=false, - int num_iters=100, float max_dist=8.0, int min_inlier_count=100, - vector* inliers=NULL); + //////////////////////////////// Filter Engine //////////////////////////////// @@ -990,6 +456,464 @@ namespace cv //! supports only ksize = 1 and ksize = 3 CV_EXPORTS void Laplacian(const GpuMat& src, GpuMat& dst, int ddepth, int ksize = 1, double scale = 1, Stream& stream = Stream::Null()); + + ////////////////////////////// Arithmetics /////////////////////////////////// + + //! transposes the matrix + //! supports matrix with element size = 1, 4 and 8 bytes (CV_8UC1, CV_8UC4, CV_16UC2, CV_32FC1, etc) + CV_EXPORTS void transpose(const GpuMat& src1, GpuMat& dst, Stream& stream = Stream::Null()); + + //! reverses the order of the rows, columns or both in a matrix + //! supports CV_8UC1, CV_8UC4 types + CV_EXPORTS void flip(const GpuMat& a, GpuMat& b, int flipCode, Stream& stream = Stream::Null()); + + //! transforms 8-bit unsigned integers using lookup table: dst(i)=lut(src(i)) + //! destination array will have the depth type as lut and the same channels number as source + //! supports CV_8UC1, CV_8UC3 types + CV_EXPORTS void LUT(const GpuMat& src, const Mat& lut, GpuMat& dst, Stream& stream = Stream::Null()); + + //! makes multi-channel array out of several single-channel arrays + CV_EXPORTS void merge(const GpuMat* src, size_t n, GpuMat& dst, Stream& stream = Stream::Null()); + + //! makes multi-channel array out of several single-channel arrays + CV_EXPORTS void merge(const vector& src, GpuMat& dst, Stream& stream = Stream::Null()); + + //! copies each plane of a multi-channel array to a dedicated array + CV_EXPORTS void split(const GpuMat& src, GpuMat* dst, Stream& stream = Stream::Null()); + + //! copies each plane of a multi-channel array to a dedicated array + CV_EXPORTS void split(const GpuMat& src, vector& dst, Stream& stream = Stream::Null()); + + //! computes magnitude of complex (x(i).re, x(i).im) vector + //! supports only CV_32FC2 type + CV_EXPORTS void magnitude(const GpuMat& x, GpuMat& magnitude, Stream& stream = Stream::Null()); + + //! computes squared magnitude of complex (x(i).re, x(i).im) vector + //! supports only CV_32FC2 type + CV_EXPORTS void magnitudeSqr(const GpuMat& x, GpuMat& magnitude, Stream& stream = Stream::Null()); + + //! computes magnitude of each (x(i), y(i)) vector + //! supports only floating-point source + CV_EXPORTS void magnitude(const GpuMat& x, const GpuMat& y, GpuMat& magnitude, Stream& stream = Stream::Null()); + + //! computes squared magnitude of each (x(i), y(i)) vector + //! supports only floating-point source + CV_EXPORTS void magnitudeSqr(const GpuMat& x, const GpuMat& y, GpuMat& magnitude, Stream& stream = Stream::Null()); + + //! computes angle (angle(i)) of each (x(i), y(i)) vector + //! supports only floating-point source + CV_EXPORTS void phase(const GpuMat& x, const GpuMat& y, GpuMat& angle, bool angleInDegrees = false, Stream& stream = Stream::Null()); + + //! converts Cartesian coordinates to polar + //! supports only floating-point source + CV_EXPORTS void cartToPolar(const GpuMat& x, const GpuMat& y, GpuMat& magnitude, GpuMat& angle, bool angleInDegrees = false, Stream& stream = Stream::Null()); + + //! converts polar coordinates to Cartesian + //! supports only floating-point source + CV_EXPORTS void polarToCart(const GpuMat& magnitude, const GpuMat& angle, GpuMat& x, GpuMat& y, bool angleInDegrees = false, Stream& stream = Stream::Null()); + + + //////////////////////////// Per-element operations //////////////////////////////////// + + //! adds one matrix to another (c = a + b) + //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types + CV_EXPORTS void add(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); + //! adds scalar to a matrix (c = a + s) + //! supports CV_32FC1 and CV_32FC2 type + CV_EXPORTS void add(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); + + //! subtracts one matrix from another (c = a - b) + //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types + CV_EXPORTS void subtract(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); + //! subtracts scalar from a matrix (c = a - s) + //! supports CV_32FC1 and CV_32FC2 type + CV_EXPORTS void subtract(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); + + //! computes element-wise product of the two arrays (c = a * b) + //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types + CV_EXPORTS void multiply(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); + //! multiplies matrix to a scalar (c = a * s) + //! supports CV_32FC1 type + CV_EXPORTS void multiply(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); + + //! computes element-wise quotient of the two arrays (c = a / b) + //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types + CV_EXPORTS void divide(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); + //! computes element-wise quotient of matrix and scalar (c = a / s) + //! supports CV_32FC1 type + CV_EXPORTS void divide(const GpuMat& a, const Scalar& sc, GpuMat& c, Stream& stream = Stream::Null()); + + //! computes exponent of each matrix element (b = e**a) + //! supports only CV_32FC1 type + CV_EXPORTS void exp(const GpuMat& a, GpuMat& b, Stream& stream = Stream::Null()); + + //! computes power of each matrix element: + // (dst(i,j) = pow( src(i,j) , power), if src.type() is integer + // (dst(i,j) = pow(fabs(src(i,j)), power), otherwise + //! supports all, except depth == CV_64F + CV_EXPORTS void pow(const GpuMat& src, double power, GpuMat& dst, Stream& stream = Stream::Null()); + + //! computes natural logarithm of absolute value of each matrix element: b = log(abs(a)) + //! supports only CV_32FC1 type + CV_EXPORTS void log(const GpuMat& a, GpuMat& b, Stream& stream = Stream::Null()); + + //! computes element-wise absolute difference of two arrays (c = abs(a - b)) + //! supports CV_8UC1, CV_8UC4, CV_32SC1, CV_32FC1 types + CV_EXPORTS void absdiff(const GpuMat& a, const GpuMat& b, GpuMat& c, Stream& stream = Stream::Null()); + //! computes element-wise absolute difference of array and scalar (c = abs(a - s)) + //! supports only CV_32FC1 type + CV_EXPORTS void absdiff(const GpuMat& a, const Scalar& s, GpuMat& c, Stream& stream = Stream::Null()); + + //! compares elements of two arrays (c = a b) + //! supports CV_8UC4, CV_32FC1 types + CV_EXPORTS void compare(const GpuMat& a, const GpuMat& b, GpuMat& c, int cmpop, Stream& stream = Stream::Null()); + + //! performs per-elements bit-wise inversion + CV_EXPORTS void bitwise_not(const GpuMat& src, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); + + //! calculates per-element bit-wise disjunction of two arrays + CV_EXPORTS void bitwise_or(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); + + //! calculates per-element bit-wise conjunction of two arrays + CV_EXPORTS void bitwise_and(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); + + //! calculates per-element bit-wise "exclusive or" operation + CV_EXPORTS void bitwise_xor(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, const GpuMat& mask=GpuMat(), Stream& stream = Stream::Null()); + + //! computes per-element minimum of two arrays (dst = min(src1, src2)) + CV_EXPORTS void min(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, Stream& stream = Stream::Null()); + + //! computes per-element minimum of array and scalar (dst = min(src1, src2)) + CV_EXPORTS void min(const GpuMat& src1, double src2, GpuMat& dst, Stream& stream = Stream::Null()); + + //! computes per-element maximum of two arrays (dst = max(src1, src2)) + CV_EXPORTS void max(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, Stream& stream = Stream::Null()); + + //! computes per-element maximum of array and scalar (dst = max(src1, src2)) + CV_EXPORTS void max(const GpuMat& src1, double src2, GpuMat& dst, Stream& stream = Stream::Null()); + + + ////////////////////////////// Image processing ////////////////////////////// + + //! DST[x,y] = SRC[xmap[x,y],ymap[x,y]] with bilinear interpolation. + //! supports CV_8UC1, CV_8UC3 source types and CV_32FC1 map type + CV_EXPORTS void remap(const GpuMat& src, GpuMat& dst, const GpuMat& xmap, const GpuMat& ymap); + + //! Does mean shift filtering on GPU. + CV_EXPORTS void meanShiftFiltering(const GpuMat& src, GpuMat& dst, int sp, int sr, + TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); + + //! Does mean shift procedure on GPU. + CV_EXPORTS void meanShiftProc(const GpuMat& src, GpuMat& dstr, GpuMat& dstsp, int sp, int sr, + TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); + + //! Does mean shift segmentation with elimination of small regions. + CV_EXPORTS void meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, int minsize, + TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); + + //! Does coloring of disparity image: [0..ndisp) -> [0..240, 1, 1] in HSV. + //! Supported types of input disparity: CV_8U, CV_16S. + //! Output disparity has CV_8UC4 type in BGRA format (alpha = 255). + CV_EXPORTS void drawColorDisp(const GpuMat& src_disp, GpuMat& dst_disp, int ndisp, Stream& stream = Stream::Null()); + + //! Reprojects disparity image to 3D space. + //! Supports CV_8U and CV_16S types of input disparity. + //! The output is a 4-channel floating-point (CV_32FC4) matrix. + //! Each element of this matrix will contain the 3D coordinates of the point (x,y,z,1), computed from the disparity map. + //! Q is the 4x4 perspective transformation matrix that can be obtained with cvStereoRectify. + CV_EXPORTS void reprojectImageTo3D(const GpuMat& disp, GpuMat& xyzw, const Mat& Q, Stream& stream = Stream::Null()); + + //! converts image from one color space to another + CV_EXPORTS void cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn = 0, Stream& stream = Stream::Null()); + + //! applies fixed threshold to the image + CV_EXPORTS double threshold(const GpuMat& src, GpuMat& dst, double thresh, double maxval, int type, Stream& stream = Stream::Null()); + + //! resizes the image + //! Supports INTER_NEAREST, INTER_LINEAR + //! supports CV_8UC1, CV_8UC4 types + CV_EXPORTS void resize(const GpuMat& src, GpuMat& dst, Size dsize, double fx=0, double fy=0, int interpolation = INTER_LINEAR, Stream& stream = Stream::Null()); + + //! warps the image using affine transformation + //! Supports INTER_NEAREST, INTER_LINEAR, INTER_CUBIC + CV_EXPORTS void warpAffine(const GpuMat& src, GpuMat& dst, const Mat& M, Size dsize, int flags = INTER_LINEAR, Stream& stream = Stream::Null()); + + //! warps the image using perspective transformation + //! Supports INTER_NEAREST, INTER_LINEAR, INTER_CUBIC + CV_EXPORTS void warpPerspective(const GpuMat& src, GpuMat& dst, const Mat& M, Size dsize, int flags = INTER_LINEAR, Stream& stream = Stream::Null()); + + //! builds plane warping maps + CV_EXPORTS void buildWarpPlaneMaps(Size src_size, Rect dst_roi, const Mat& R, double f, double s, double dist, + GpuMat& map_x, GpuMat& map_y, Stream& stream = Stream::Null()); + + //! builds cylindrical warping maps + CV_EXPORTS void buildWarpCylindricalMaps(Size src_size, Rect dst_roi, const Mat& R, double f, double s, + GpuMat& map_x, GpuMat& map_y, Stream& stream = Stream::Null()); + + //! builds spherical warping maps + CV_EXPORTS void buildWarpSphericalMaps(Size src_size, Rect dst_roi, const Mat& R, double f, double s, + GpuMat& map_x, GpuMat& map_y, Stream& stream = Stream::Null()); + + //! rotate 8bit single or four channel image + //! Supports INTER_NEAREST, INTER_LINEAR, INTER_CUBIC + //! supports CV_8UC1, CV_8UC4 types + CV_EXPORTS void rotate(const GpuMat& src, GpuMat& dst, Size dsize, double angle, double xShift = 0, double yShift = 0, int interpolation = INTER_LINEAR, Stream& stream = Stream::Null()); + + //! copies 2D array to a larger destination array and pads borders with user-specifiable constant + //! supports CV_8UC1, CV_8UC4, CV_32SC1 and CV_32FC1 types + CV_EXPORTS void copyMakeBorder(const GpuMat& src, GpuMat& dst, int top, int bottom, int left, int right, const Scalar& value = Scalar(), Stream& stream = Stream::Null()); + + //! computes the integral image + //! sum will have CV_32S type, but will contain unsigned int values + //! supports only CV_8UC1 source type + CV_EXPORTS void integral(const GpuMat& src, GpuMat& sum, Stream& stream = Stream::Null()); + + //! buffered version + CV_EXPORTS void integralBuffered(const GpuMat& src, GpuMat& sum, GpuMat& buffer, Stream& stream = Stream::Null()); + + //! computes the integral image and integral for the squared image + //! sum will have CV_32S type, sqsum - CV32F type + //! supports only CV_8UC1 source type + CV_EXPORTS void integral(const GpuMat& src, GpuMat& sum, GpuMat& sqsum, Stream& stream = Stream::Null()); + + //! computes squared integral image + //! result matrix will have 64F type, but will contain 64U values + //! supports source images of 8UC1 type only + CV_EXPORTS void sqrIntegral(const GpuMat& src, GpuMat& sqsum, Stream& stream = Stream::Null()); + + //! computes vertical sum, supports only CV_32FC1 images + CV_EXPORTS void columnSum(const GpuMat& src, GpuMat& sum); + + //! computes the standard deviation of integral images + //! supports only CV_32SC1 source type and CV_32FC1 sqr type + //! output will have CV_32FC1 type + CV_EXPORTS void rectStdDev(const GpuMat& src, const GpuMat& sqr, GpuMat& dst, const Rect& rect, Stream& stream = Stream::Null()); + + //! computes Harris cornerness criteria at each image pixel + CV_EXPORTS void cornerHarris(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, double k, int borderType=BORDER_REFLECT101); + CV_EXPORTS void cornerHarris(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, double k, int borderType=BORDER_REFLECT101); + + //! computes minimum eigen value of 2x2 derivative covariation matrix at each pixel - the cornerness criteria + CV_EXPORTS void cornerMinEigenVal(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, int borderType=BORDER_REFLECT101); + CV_EXPORTS void cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, int borderType=BORDER_REFLECT101); + + //! performs per-element multiplication of two full (not packed) Fourier spectrums + //! supports 32FC2 matrixes only (interleaved format) + CV_EXPORTS void mulSpectrums(const GpuMat& a, const GpuMat& b, GpuMat& c, int flags, bool conjB=false); + + //! performs per-element multiplication of two full (not packed) Fourier spectrums + //! supports 32FC2 matrixes only (interleaved format) + CV_EXPORTS void mulAndScaleSpectrums(const GpuMat& a, const GpuMat& b, GpuMat& c, int flags, + float scale, bool conjB=false); + + //! Performs a forward or inverse discrete Fourier transform (1D or 2D) of floating point matrix. + //! Param dft_size is the size of DFT transform. + //! + //! If the source matrix is not continous, then additional copy will be done, + //! so to avoid copying ensure the source matrix is continous one. If you want to use + //! preallocated output ensure it is continuous too, otherwise it will be reallocated. + //! + //! Being implemented via CUFFT real-to-complex transform result contains only non-redundant values + //! in CUFFT's format. Result as full complex matrix for such kind of transform cannot be retrieved. + //! + //! For complex-to-real transform it is assumed that the source matrix is packed in CUFFT's format. + CV_EXPORTS void dft(const GpuMat& src, GpuMat& dst, Size dft_size, int flags=0); + + //! computes convolution (or cross-correlation) of two images using discrete Fourier transform + //! supports source images of 32FC1 type only + //! result matrix will have 32FC1 type + CV_EXPORTS void convolve(const GpuMat& image, const GpuMat& templ, GpuMat& result, + bool ccorr=false); + + struct CV_EXPORTS ConvolveBuf; + + //! buffered version + CV_EXPORTS void convolve(const GpuMat& image, const GpuMat& templ, GpuMat& result, + bool ccorr, ConvolveBuf& buf); + + struct CV_EXPORTS ConvolveBuf + { + ConvolveBuf() {} + ConvolveBuf(Size image_size, Size templ_size) + { create(image_size, templ_size); } + void create(Size image_size, Size templ_size); + + private: + static Size estimateBlockSize(Size result_size, Size templ_size); + friend void convolve(const GpuMat&, const GpuMat&, GpuMat&, bool, ConvolveBuf&); + + Size result_size; + Size block_size; + Size dft_size; + int spect_len; + + GpuMat image_spect, templ_spect, result_spect; + GpuMat image_block, templ_block, result_data; + }; + + //! computes the proximity map for the raster template and the image where the template is searched for + CV_EXPORTS void matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method); + + //! downsamples image + CV_EXPORTS void downsample(const GpuMat& src, GpuMat& dst, Stream& stream = Stream::Null()); + + //! upsamples image + CV_EXPORTS void upsample(const GpuMat& src, GpuMat &dst, Stream& stream = Stream::Null()); + + //! smoothes the source image and downsamples it + CV_EXPORTS void pyrDown(const GpuMat& src, GpuMat& dst, Stream& stream = Stream::Null()); + + struct CV_EXPORTS PyrDownBuf; + + CV_EXPORTS void pyrDown(const GpuMat& src, GpuMat& dst, PyrDownBuf& buf, Stream& stream = Stream::Null()); + + struct CV_EXPORTS PyrDownBuf + { + PyrDownBuf() : image_type(-1) {} + PyrDownBuf(Size image_size, int image_type_) : image_type(-1) { create(image_size, image_type_); } + void create(Size image_size, int image_type_); + + private: + friend void pyrDown(const GpuMat&, GpuMat&, PyrDownBuf&, Stream& stream); + + static Mat ker; + GpuMat buf; + Ptr filter; + int image_type; + }; + + //! upsamples the source image and then smoothes it + CV_EXPORTS void pyrUp(const GpuMat& src, GpuMat& dst, Stream& stream = Stream::Null()); + + struct CV_EXPORTS PyrUpBuf; + + CV_EXPORTS void pyrUp(const GpuMat& src, GpuMat& dst, PyrUpBuf& buf, Stream& stream = Stream::Null()); + + struct CV_EXPORTS PyrUpBuf + { + PyrUpBuf() : image_type(-1) {} + PyrUpBuf(Size image_size, int image_type_) : image_type(-1) { create(image_size, image_type_); } + void create(Size image_size, int image_type_); + + private: + friend void pyrUp(const GpuMat&, GpuMat&, PyrUpBuf&, Stream& stream); + + static Mat ker; + GpuMat buf; + Ptr filter; + int image_type; + }; + + //! performs linear blending of two images + //! to avoid accuracy errors sum of weigths shouldn't be very close to zero + CV_EXPORTS void blendLinear(const GpuMat& img1, const GpuMat& img2, const GpuMat& weights1, const GpuMat& weights2, + GpuMat& result, Stream& stream = Stream::Null()); + + + struct CV_EXPORTS CannyBuf; + + CV_EXPORTS void Canny(const GpuMat& image, GpuMat& edges, double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false); + CV_EXPORTS void Canny(const GpuMat& image, CannyBuf& buf, GpuMat& edges, double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false); + CV_EXPORTS void Canny(const GpuMat& dx, const GpuMat& dy, GpuMat& edges, double low_thresh, double high_thresh, bool L2gradient = false); + CV_EXPORTS void Canny(const GpuMat& dx, const GpuMat& dy, CannyBuf& buf, GpuMat& edges, double low_thresh, double high_thresh, bool L2gradient = false); + + struct CV_EXPORTS CannyBuf + { + CannyBuf() {} + explicit CannyBuf(const Size& image_size, int apperture_size = 3) {create(image_size, apperture_size);} + CannyBuf(const GpuMat& dx_, const GpuMat& dy_); + + void create(const Size& image_size, int apperture_size = 3); + + void release(); + + GpuMat dx, dy; + GpuMat dx_buf, dy_buf; + GpuMat edgeBuf; + GpuMat trackBuf1, trackBuf2; + Ptr filterDX, filterDY; + }; + + ////////////////////////////// Matrix reductions ////////////////////////////// + + //! computes mean value and standard deviation of all or selected array elements + //! supports only CV_8UC1 type + CV_EXPORTS void meanStdDev(const GpuMat& mtx, Scalar& mean, Scalar& stddev); + + //! computes norm of array + //! supports NORM_INF, NORM_L1, NORM_L2 + //! supports all matrices except 64F + CV_EXPORTS double norm(const GpuMat& src1, int normType=NORM_L2); + + //! computes norm of array + //! supports NORM_INF, NORM_L1, NORM_L2 + //! supports all matrices except 64F + CV_EXPORTS double norm(const GpuMat& src1, int normType, GpuMat& buf); + + //! computes norm of the difference between two arrays + //! supports NORM_INF, NORM_L1, NORM_L2 + //! supports only CV_8UC1 type + CV_EXPORTS double norm(const GpuMat& src1, const GpuMat& src2, int normType=NORM_L2); + + //! computes sum of array elements + //! supports only single channel images + CV_EXPORTS Scalar sum(const GpuMat& src); + + //! computes sum of array elements + //! supports only single channel images + CV_EXPORTS Scalar sum(const GpuMat& src, GpuMat& buf); + + //! computes sum of array elements absolute values + //! supports only single channel images + CV_EXPORTS Scalar absSum(const GpuMat& src); + + //! computes sum of array elements absolute values + //! supports only single channel images + CV_EXPORTS Scalar absSum(const GpuMat& src, GpuMat& buf); + + //! computes squared sum of array elements + //! supports only single channel images + CV_EXPORTS Scalar sqrSum(const GpuMat& src); + + //! computes squared sum of array elements + //! supports only single channel images + CV_EXPORTS Scalar sqrSum(const GpuMat& src, GpuMat& buf); + + //! finds global minimum and maximum array elements and returns their values + CV_EXPORTS void minMax(const GpuMat& src, double* minVal, double* maxVal=0, const GpuMat& mask=GpuMat()); + + //! finds global minimum and maximum array elements and returns their values + CV_EXPORTS void minMax(const GpuMat& src, double* minVal, double* maxVal, const GpuMat& mask, GpuMat& buf); + + //! finds global minimum and maximum array elements and returns their values with locations + CV_EXPORTS void minMaxLoc(const GpuMat& src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, + const GpuMat& mask=GpuMat()); + + //! finds global minimum and maximum array elements and returns their values with locations + CV_EXPORTS void minMaxLoc(const GpuMat& src, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, + const GpuMat& mask, GpuMat& valbuf, GpuMat& locbuf); + + //! counts non-zero array elements + CV_EXPORTS int countNonZero(const GpuMat& src); + + //! counts non-zero array elements + CV_EXPORTS int countNonZero(const GpuMat& src, GpuMat& buf); + + + ///////////////////////////// Calibration 3D ////////////////////////////////// + + CV_EXPORTS void transformPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, + GpuMat& dst, Stream& stream = Stream::Null()); + + CV_EXPORTS void projectPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, + const Mat& camera_mat, const Mat& dist_coef, GpuMat& dst, + Stream& stream = Stream::Null()); + + CV_EXPORTS void solvePnPRansac(const Mat& object, const Mat& image, const Mat& camera_mat, + const Mat& dist_coef, Mat& rvec, Mat& tvec, bool use_extrinsic_guess=false, + int num_iters=100, float max_dist=8.0, int min_inlier_count=100, + vector* inliers=NULL); + //////////////////////////////// Image Labeling //////////////////////////////// //!performs labeling via graph cuts @@ -1003,22 +927,36 @@ namespace cv //! Supports CV_8UC1, CV_16UC1 and CV_16SC1 source types. //! Output hist will have one row and histSize cols and CV_32SC1 type. CV_EXPORTS void histEven(const GpuMat& src, GpuMat& hist, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()); + CV_EXPORTS void histEven(const GpuMat& src, GpuMat& hist, GpuMat& buf, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()); //! Calculates histogram with evenly distributed bins for four-channel source. //! All channels of source are processed separately. //! Supports CV_8UC4, CV_16UC4 and CV_16SC4 source types. //! Output hist[i] will have one row and histSize[i] cols and CV_32SC1 type. CV_EXPORTS void histEven(const GpuMat& src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()); + CV_EXPORTS void histEven(const GpuMat& src, GpuMat hist[4], GpuMat& buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()); //! Calculates histogram with bins determined by levels array. //! levels must have one row and CV_32SC1 type if source has integer type or CV_32FC1 otherwise. //! Supports CV_8UC1, CV_16UC1, CV_16SC1 and CV_32FC1 source types. //! Output hist will have one row and (levels.cols-1) cols and CV_32SC1 type. CV_EXPORTS void histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, Stream& stream = Stream::Null()); + CV_EXPORTS void histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, GpuMat& buf, Stream& stream = Stream::Null()); //! Calculates histogram with bins determined by levels array. //! All levels must have one row and CV_32SC1 type if source has integer type or CV_32FC1 otherwise. //! All channels of source are processed separately. //! Supports CV_8UC4, CV_16UC4, CV_16SC4 and CV_32FC4 source types. //! Output hist[i] will have one row and (levels[i].cols-1) cols and CV_32SC1 type. CV_EXPORTS void histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], Stream& stream = Stream::Null()); + CV_EXPORTS void histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], GpuMat& buf, Stream& stream = Stream::Null()); + + //! Calculates histogram for 8u one channel image + //! Output hist will have one row, 256 cols and CV32SC1 type. + CV_EXPORTS void calcHist(const GpuMat& src, GpuMat& hist, Stream& stream = Stream::Null()); + CV_EXPORTS void calcHist(const GpuMat& src, GpuMat& hist, GpuMat& buf, Stream& stream = Stream::Null()); + + //! normalizes the grayscale image brightness and contrast by normalizing its histogram + CV_EXPORTS void equalizeHist(const GpuMat& src, GpuMat& dst, Stream& stream = Stream::Null()); + CV_EXPORTS void equalizeHist(const GpuMat& src, GpuMat& dst, GpuMat& hist, Stream& stream = Stream::Null()); + CV_EXPORTS void equalizeHist(const GpuMat& src, GpuMat& dst, GpuMat& hist, GpuMat& buf, Stream& stream = Stream::Null()); //////////////////////////////// StereoBM_GPU //////////////////////////////// @@ -1321,8 +1259,10 @@ namespace cv GpuMat& trainIdx, GpuMat& distance, const GpuMat& mask = GpuMat(), Stream& stream = Stream::Null()); - // Download trainIdx and distance to CPU vector with DMatch + // Download trainIdx and distance and convert it to CPU vector with DMatch static void matchDownload(const GpuMat& trainIdx, const GpuMat& distance, std::vector& matches); + // Convert trainIdx and distance to vector with DMatch + static void matchConvert(const Mat& trainIdx, const Mat& distance, std::vector& matches); // Find one best match for each query descriptor. void match(const GpuMat& queryDescs, const GpuMat& trainDescs, std::vector& matches, @@ -1340,13 +1280,13 @@ namespace cv GpuMat& trainIdx, GpuMat& imgIdx, GpuMat& distance, const GpuMat& maskCollection, Stream& stream = Stream::Null()); - // Download trainIdx, imgIdx and distance to CPU vector with DMatch - static void matchDownload(const GpuMat& trainIdx, const GpuMat& imgIdx, const GpuMat& distance, - std::vector& matches); + // Download trainIdx, imgIdx and distance and convert it to vector with DMatch + static void matchDownload(const GpuMat& trainIdx, const GpuMat& imgIdx, const GpuMat& distance, std::vector& matches); + // Convert trainIdx, imgIdx and distance to vector with DMatch + static void matchConvert(const Mat& trainIdx, const Mat& imgIdx, const Mat& distance, std::vector& matches); // Find one best match from train collection for each query descriptor. - void match(const GpuMat& queryDescs, std::vector& matches, - const std::vector& masks = std::vector()); + void match(const GpuMat& queryDescs, std::vector& matches, const std::vector& masks = std::vector()); // Find k best matches for each query descriptor (in increasing order of distances). // trainIdx.at(queryIdx, i) will contain index of i'th best trains (i < k). @@ -1358,12 +1298,15 @@ namespace cv void knnMatch(const GpuMat& queryDescs, const GpuMat& trainDescs, GpuMat& trainIdx, GpuMat& distance, GpuMat& allDist, int k, const GpuMat& mask = GpuMat(), Stream& stream = Stream::Null()); - // Download trainIdx and distance to CPU vector with DMatch + // Download trainIdx and distance and convert it to vector with DMatch // compactResult is used when mask is not empty. If compactResult is false matches // vector will have the same size as queryDescriptors rows. If compactResult is true // matches vector will not contain matches for fully masked out query descriptors. static void knnMatchDownload(const GpuMat& trainIdx, const GpuMat& distance, std::vector< std::vector >& matches, bool compactResult = false); + // Convert trainIdx and distance to vector with DMatch + static void knnMatchConvert(const Mat& trainIdx, const Mat& distance, + std::vector< std::vector >& matches, bool compactResult = false); // Find k best matches for each query descriptor (in increasing order of distances). // compactResult is used when mask is not empty. If compactResult is false matches @@ -1393,13 +1336,16 @@ namespace cv GpuMat& trainIdx, GpuMat& nMatches, GpuMat& distance, float maxDistance, const GpuMat& mask = GpuMat(), Stream& stream = Stream::Null()); - // Download trainIdx, nMatches and distance to CPU vector with DMatch. + // Download trainIdx, nMatches and distance and convert it to vector with DMatch. // matches will be sorted in increasing order of distances. // compactResult is used when mask is not empty. If compactResult is false matches // vector will have the same size as queryDescriptors rows. If compactResult is true // matches vector will not contain matches for fully masked out query descriptors. static void radiusMatchDownload(const GpuMat& trainIdx, const GpuMat& nMatches, const GpuMat& distance, std::vector< std::vector >& matches, bool compactResult = false); + // Convert trainIdx, nMatches and distance to vector with DMatch. + static void radiusMatchConvert(const Mat& trainIdx, const Mat& nMatches, const Mat& distance, + std::vector< std::vector >& matches, bool compactResult = false); // Find best matches for each query descriptor which have distance less than maxDistance // in increasing order of distances). @@ -1412,9 +1358,9 @@ namespace cv void radiusMatch(const GpuMat& queryDescs, std::vector< std::vector >& matches, float maxDistance, const std::vector& masks = std::vector(), bool compactResult = false); - private: DistType distType; + private: std::vector trainDescCollection; }; @@ -1529,6 +1475,8 @@ namespace cv void operator()(const GpuMat& img, const GpuMat& mask, std::vector& keypoints, std::vector& descriptors, bool useProvidedKeypoints = false); + void releaseMemory(); + //! max keypoints = min(keypointsRatio * img.size().area(), 65535) float keypointsRatio; diff --git a/modules/gpu/include/opencv2/gpu/gpumat.hpp b/modules/gpu/include/opencv2/gpu/gpumat.hpp new file mode 100644 index 0000000000..8ce456a93d --- /dev/null +++ b/modules/gpu/include/opencv2/gpu/gpumat.hpp @@ -0,0 +1,274 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other GpuMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_GPUMAT_HPP__ +#define __OPENCV_GPUMAT_HPP__ + +#include "opencv2/core/core.hpp" +#include "opencv2/gpu/devmem2d.hpp" + +namespace cv { namespace gpu +{ + class Stream; + class CudaMem; + + //! Smart pointer for GPU memory with reference counting. Its interface is mostly similar with cv::Mat. + class CV_EXPORTS GpuMat + { + public: + //! default constructor + GpuMat(); + //! constructs GpuMatrix of the specified size and type (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.) + GpuMat(int rows, int cols, int type); + GpuMat(Size size, int type); + //! constucts GpuMatrix and fills it with the specified value _s. + GpuMat(int rows, int cols, int type, const Scalar& s); + GpuMat(Size size, int type, const Scalar& s); + //! copy constructor + GpuMat(const GpuMat& m); + + //! constructor for GpuMatrix headers pointing to user-allocated data + GpuMat(int rows, int cols, int type, void* data, size_t step = Mat::AUTO_STEP); + GpuMat(Size size, int type, void* data, size_t step = Mat::AUTO_STEP); + + //! creates a matrix header for a part of the bigger matrix + GpuMat(const GpuMat& m, const Range& rowRange, const Range& colRange); + GpuMat(const GpuMat& m, const Rect& roi); + + //! builds GpuMat from Mat. Perfom blocking upload to device. + explicit GpuMat (const Mat& m); + + //! destructor - calls release() + ~GpuMat(); + + //! assignment operators + GpuMat& operator = (const GpuMat& m); + //! assignment operator. Perfom blocking upload to device. + GpuMat& operator = (const Mat& m); + + //! returns lightweight DevMem2D_ structure for passing to nvcc-compiled code. + // Contains just image size, data ptr and step. + template operator DevMem2D_() const; + template operator PtrStep_() const; + + //! pefroms blocking upload data to GpuMat. + void upload(const cv::Mat& m); + + //! upload async + void upload(const CudaMem& m, Stream& stream); + + //! downloads data from device to host memory. Blocking calls. + operator Mat() const; + void download(cv::Mat& m) const; + + //! download async + void download(CudaMem& m, Stream& stream) const; + + //! returns a new GpuMatrix header for the specified row + GpuMat row(int y) const; + //! returns a new GpuMatrix header for the specified column + GpuMat col(int x) const; + //! ... for the specified row span + GpuMat rowRange(int startrow, int endrow) const; + GpuMat rowRange(const Range& r) const; + //! ... for the specified column span + GpuMat colRange(int startcol, int endcol) const; + GpuMat colRange(const Range& r) const; + + //! returns deep copy of the GpuMatrix, i.e. the data is copied + GpuMat clone() const; + //! copies the GpuMatrix content to "m". + // It calls m.create(this->size(), this->type()). + void copyTo( GpuMat& m ) const; + //! copies those GpuMatrix elements to "m" that are marked with non-zero mask elements. + void copyTo( GpuMat& m, const GpuMat& mask ) const; + //! converts GpuMatrix to another datatype with optional scalng. See cvConvertScale. + void convertTo( GpuMat& m, int rtype, double alpha=1, double beta=0 ) const; + + void assignTo( GpuMat& m, int type=-1 ) const; + + //! sets every GpuMatrix element to s + GpuMat& operator = (const Scalar& s); + //! sets some of the GpuMatrix elements to s, according to the mask + GpuMat& setTo(const Scalar& s, const GpuMat& mask = GpuMat()); + //! creates alternative GpuMatrix header for the same data, with different + // number of channels and/or different number of rows. see cvReshape. + GpuMat reshape(int cn, int rows = 0) const; + + //! allocates new GpuMatrix data unless the GpuMatrix already has specified size and type. + // previous data is unreferenced if needed. + void create(int rows, int cols, int type); + void create(Size size, int type); + //! decreases reference counter; + // deallocate the data when reference counter reaches 0. + void release(); + + //! swaps with other smart pointer + void swap(GpuMat& mat); + + //! locates GpuMatrix header within a parent GpuMatrix. See below + void locateROI( Size& wholeSize, Point& ofs ) const; + //! moves/resizes the current GpuMatrix ROI inside the parent GpuMatrix. + GpuMat& adjustROI( int dtop, int dbottom, int dleft, int dright ); + //! extracts a rectangular sub-GpuMatrix + // (this is a generalized form of row, rowRange etc.) + GpuMat operator()( Range rowRange, Range colRange ) const; + GpuMat operator()( const Rect& roi ) const; + + //! returns true iff the GpuMatrix data is continuous + // (i.e. when there are no gaps between successive rows). + // similar to CV_IS_GpuMat_CONT(cvGpuMat->type) + bool isContinuous() const; + //! returns element size in bytes, + // similar to CV_ELEM_SIZE(cvMat->type) + size_t elemSize() const; + //! returns the size of element channel in bytes. + size_t elemSize1() const; + //! returns element type, similar to CV_MAT_TYPE(cvMat->type) + int type() const; + //! returns element type, similar to CV_MAT_DEPTH(cvMat->type) + int depth() const; + //! returns element type, similar to CV_MAT_CN(cvMat->type) + int channels() const; + //! returns step/elemSize1() + size_t step1() const; + //! returns GpuMatrix size: + // width == number of columns, height == number of rows + Size size() const; + //! returns true if GpuMatrix data is NULL + bool empty() const; + + //! returns pointer to y-th row + uchar* ptr(int y = 0); + const uchar* ptr(int y = 0) const; + + //! template version of the above method + template _Tp* ptr(int y = 0); + template const _Tp* ptr(int y = 0) const; + + //! matrix transposition + GpuMat t() const; + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + //! the number of rows and columns + int rows, cols; + //! a distance between successive rows in bytes; includes the gap if any + size_t step; + //! pointer to the data + uchar* data; + + //! pointer to the reference counter; + // when GpuMatrix points to user-allocated data, the pointer is NULL + int* refcount; + + //! helper fields used in locateROI and adjustROI + uchar* datastart; + uchar* dataend; + }; + + //! Creates continuous GPU matrix + CV_EXPORTS void createContinuous(int rows, int cols, int type, GpuMat& m); + CV_EXPORTS GpuMat createContinuous(int rows, int cols, int type); + CV_EXPORTS void createContinuous(Size size, int type, GpuMat& m); + CV_EXPORTS GpuMat createContinuous(Size size, int type); + + //! Ensures that size of the given matrix is not less than (rows, cols) size + //! and matrix type is match specified one too + CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, GpuMat& m); + CV_EXPORTS void ensureSizeIsEnough(Size size, int type, GpuMat& m); + + //////////////////////////////////////////////////////////////////////// + //////////////////////////////// GpuMat //////////////////////////////// + //////////////////////////////////////////////////////////////////////// + + inline GpuMat::GpuMat() : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) {} + + inline GpuMat::GpuMat(int rows_, int cols_, int type_) : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) + { + if (rows_ > 0 && cols_ > 0) + create(rows_, cols_, type_); + } + + inline GpuMat::~GpuMat() { release(); } + + template inline GpuMat::operator DevMem2D_() const { return DevMem2D_(rows, cols, (T*)data, step); } + template inline GpuMat::operator PtrStep_() const { return PtrStep_(static_cast< DevMem2D_ >(*this)); } + + inline GpuMat GpuMat::clone() const + { + GpuMat m; + copyTo(m); + return m; + } + + inline void GpuMat::assignTo(GpuMat& m, int type) const + { + if( type < 0 ) + m = *this; + else + convertTo(m, type); + } + + inline size_t GpuMat::step1() const { return step/elemSize1(); } + + inline bool GpuMat::empty() const { return data == 0; } + + template inline _Tp* GpuMat::ptr(int y) + { + return (_Tp*)ptr(y); + } + + template inline const _Tp* GpuMat::ptr(int y) const + { + return (const _Tp*)ptr(y); + } + + inline void swap(GpuMat& a, GpuMat& b) { a.swap(b); } +}} + +#endif // __OPENCV_GPUMAT_HPP__ diff --git a/modules/gpu/include/opencv2/gpu/matrix_operations.hpp b/modules/gpu/include/opencv2/gpu/matrix_operations.hpp index 7af0907824..e8bb9167b7 100644 --- a/modules/gpu/include/opencv2/gpu/matrix_operations.hpp +++ b/modules/gpu/include/opencv2/gpu/matrix_operations.hpp @@ -48,328 +48,6 @@ namespace cv namespace gpu { - -//////////////////////////////////////////////////////////////////////// -//////////////////////////////// GpuMat //////////////////////////////// -//////////////////////////////////////////////////////////////////////// - -inline GpuMat::GpuMat() : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) {} - -inline GpuMat::GpuMat(int _rows, int _cols, int _type) : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) -{ - if( _rows > 0 && _cols > 0 ) - create( _rows, _cols, _type ); -} - -inline GpuMat::GpuMat(Size _size, int _type) : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) -{ - if( _size.height > 0 && _size.width > 0 ) - create( _size.height, _size.width, _type ); -} - -inline GpuMat::GpuMat(int _rows, int _cols, int _type, const Scalar& _s) - : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) -{ - if(_rows > 0 && _cols > 0) - { - create(_rows, _cols, _type); - *this = _s; - } -} - -inline GpuMat::GpuMat(Size _size, int _type, const Scalar& _s) - : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) -{ - if( _size.height > 0 && _size.width > 0 ) - { - create( _size.height, _size.width, _type ); - *this = _s; - } -} - -inline GpuMat::GpuMat(const GpuMat& m) - : flags(m.flags), rows(m.rows), cols(m.cols), step(m.step), data(m.data), refcount(m.refcount), datastart(m.datastart), dataend(m.dataend) -{ - if( refcount ) - CV_XADD(refcount, 1); -} - -inline GpuMat::GpuMat(int _rows, int _cols, int _type, void* _data, size_t _step) - : flags(Mat::MAGIC_VAL + (_type & TYPE_MASK)), rows(_rows), cols(_cols), step(_step), data((uchar*)_data), refcount(0), - datastart((uchar*)_data), dataend((uchar*)_data) -{ - size_t minstep = cols*elemSize(); - if( step == Mat::AUTO_STEP ) - { - step = minstep; - flags |= Mat::CONTINUOUS_FLAG; - } - else - { - if( rows == 1 ) step = minstep; - CV_DbgAssert( step >= minstep ); - flags |= step == minstep ? Mat::CONTINUOUS_FLAG : 0; - } - dataend += step*(rows-1) + minstep; -} - -inline GpuMat::GpuMat(Size _size, int _type, void* _data, size_t _step) - : flags(Mat::MAGIC_VAL + (_type & TYPE_MASK)), rows(_size.height), cols(_size.width), - step(_step), data((uchar*)_data), refcount(0), - datastart((uchar*)_data), dataend((uchar*)_data) -{ - size_t minstep = cols*elemSize(); - if( step == Mat::AUTO_STEP ) - { - step = minstep; - flags |= Mat::CONTINUOUS_FLAG; - } - else - { - if( rows == 1 ) step = minstep; - CV_DbgAssert( step >= minstep ); - flags |= step == minstep ? Mat::CONTINUOUS_FLAG : 0; - } - dataend += step*(rows-1) + minstep; -} - - -inline GpuMat::GpuMat(const GpuMat& m, const Range& rowRange, const Range& colRange) -{ - flags = m.flags; - step = m.step; refcount = m.refcount; - data = m.data; datastart = m.datastart; dataend = m.dataend; - - if( rowRange == Range::all() ) - rows = m.rows; - else - { - CV_Assert( 0 <= rowRange.start && rowRange.start <= rowRange.end && rowRange.end <= m.rows ); - rows = rowRange.size(); - data += step*rowRange.start; - } - - if( colRange == Range::all() ) - cols = m.cols; - else - { - CV_Assert( 0 <= colRange.start && colRange.start <= colRange.end && colRange.end <= m.cols ); - cols = colRange.size(); - data += colRange.start*elemSize(); - flags &= cols < m.cols ? ~Mat::CONTINUOUS_FLAG : -1; - } - - if( rows == 1 ) - flags |= Mat::CONTINUOUS_FLAG; - - if( refcount ) - CV_XADD(refcount, 1); - if( rows <= 0 || cols <= 0 ) - rows = cols = 0; -} - -inline GpuMat::GpuMat(const GpuMat& m, const Rect& roi) - : flags(m.flags), rows(roi.height), cols(roi.width), - step(m.step), data(m.data + roi.y*step), refcount(m.refcount), - datastart(m.datastart), dataend(m.dataend) -{ - flags &= roi.width < m.cols ? ~Mat::CONTINUOUS_FLAG : -1; - data += roi.x*elemSize(); - CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && - 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows ); - if( refcount ) - CV_XADD(refcount, 1); - if( rows <= 0 || cols <= 0 ) - rows = cols = 0; -} - -inline GpuMat::GpuMat(const Mat& m) -: flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) { upload(m); } - -inline GpuMat::~GpuMat() { release(); } - -inline GpuMat& GpuMat::operator = (const GpuMat& m) -{ - if( this != &m ) - { - if( m.refcount ) - CV_XADD(m.refcount, 1); - release(); - flags = m.flags; - rows = m.rows; cols = m.cols; - step = m.step; data = m.data; - datastart = m.datastart; dataend = m.dataend; - refcount = m.refcount; - } - return *this; -} - -inline GpuMat& GpuMat::operator = (const Mat& m) { upload(m); return *this; } - -template inline GpuMat::operator DevMem2D_() const { return DevMem2D_(rows, cols, (T*)data, step); } -template inline GpuMat::operator PtrStep_() const { return PtrStep_(static_cast< DevMem2D_ >(*this)); } - -//CPP: void GpuMat::upload(const Mat& m); - - inline GpuMat::operator Mat() const - { - Mat m; - download(m); - return m; - } - -//CPP void GpuMat::download(cv::Mat& m) const; - -inline GpuMat GpuMat::row(int y) const { return GpuMat(*this, Range(y, y+1), Range::all()); } -inline GpuMat GpuMat::col(int x) const { return GpuMat(*this, Range::all(), Range(x, x+1)); } -inline GpuMat GpuMat::rowRange(int startrow, int endrow) const { return GpuMat(*this, Range(startrow, endrow), Range::all()); } -inline GpuMat GpuMat::rowRange(const Range& r) const { return GpuMat(*this, r, Range::all()); } -inline GpuMat GpuMat::colRange(int startcol, int endcol) const { return GpuMat(*this, Range::all(), Range(startcol, endcol)); } -inline GpuMat GpuMat::colRange(const Range& r) const { return GpuMat(*this, Range::all(), r); } - -inline GpuMat GpuMat::clone() const -{ - GpuMat m; - copyTo(m); - return m; -} - -//CPP void GpuMat::copyTo( GpuMat& m ) const; -//CPP void GpuMat::copyTo( GpuMat& m, const GpuMat& mask ) const; -//CPP void GpuMat::convertTo( GpuMat& m, int rtype, double alpha=1, double beta=0 ) const; - -inline void GpuMat::assignTo( GpuMat& m, int type ) const -{ - if( type < 0 ) - m = *this; - else - convertTo(m, type); -} - -//CPP GpuMat& GpuMat::operator = (const Scalar& s); -//CPP GpuMat& GpuMat::setTo(const Scalar& s, const GpuMat& mask=GpuMat()); -//CPP GpuMat GpuMat::reshape(int _cn, int _rows=0) const; -inline void GpuMat::create(Size _size, int _type) { create(_size.height, _size.width, _type); } -//CPP void GpuMat::create(int _rows, int _cols, int _type); -//CPP void GpuMat::release(); - -inline void GpuMat::swap(GpuMat& b) -{ - std::swap( flags, b.flags ); - std::swap( rows, b.rows ); std::swap( cols, b.cols ); - std::swap( step, b.step ); std::swap( data, b.data ); - std::swap( datastart, b.datastart ); - std::swap( dataend, b.dataend ); - std::swap( refcount, b.refcount ); -} - -inline void GpuMat::locateROI( Size& wholeSize, Point& ofs ) const -{ - size_t esz = elemSize(), minstep; - ptrdiff_t delta1 = data - datastart, delta2 = dataend - datastart; - CV_DbgAssert( step > 0 ); - if( delta1 == 0 ) - ofs.x = ofs.y = 0; - else - { - ofs.y = (int)(delta1/step); - ofs.x = (int)((delta1 - step*ofs.y)/esz); - CV_DbgAssert( data == datastart + ofs.y*step + ofs.x*esz ); - } - minstep = (ofs.x + cols)*esz; - wholeSize.height = (int)((delta2 - minstep)/step + 1); - wholeSize.height = std::max(wholeSize.height, ofs.y + rows); - wholeSize.width = (int)((delta2 - step*(wholeSize.height-1))/esz); - wholeSize.width = std::max(wholeSize.width, ofs.x + cols); -} - -inline GpuMat& GpuMat::adjustROI( int dtop, int dbottom, int dleft, int dright ) -{ - Size wholeSize; Point ofs; - size_t esz = elemSize(); - locateROI( wholeSize, ofs ); - int row1 = std::max(ofs.y - dtop, 0), row2 = std::min(ofs.y + rows + dbottom, wholeSize.height); - int col1 = std::max(ofs.x - dleft, 0), col2 = std::min(ofs.x + cols + dright, wholeSize.width); - data += (row1 - ofs.y)*step + (col1 - ofs.x)*esz; - rows = row2 - row1; cols = col2 - col1; - if( esz*cols == step || rows == 1 ) - flags |= Mat::CONTINUOUS_FLAG; - else - flags &= ~Mat::CONTINUOUS_FLAG; - return *this; -} - -inline GpuMat GpuMat::operator()( Range rowRange, Range colRange ) const { return GpuMat(*this, rowRange, colRange); } -inline GpuMat GpuMat::operator()( const Rect& roi ) const { return GpuMat(*this, roi); } - -inline bool GpuMat::isContinuous() const { return (flags & Mat::CONTINUOUS_FLAG) != 0; } -inline size_t GpuMat::elemSize() const { return CV_ELEM_SIZE(flags); } -inline size_t GpuMat::elemSize1() const { return CV_ELEM_SIZE1(flags); } -inline int GpuMat::type() const { return CV_MAT_TYPE(flags); } -inline int GpuMat::depth() const { return CV_MAT_DEPTH(flags); } -inline int GpuMat::channels() const { return CV_MAT_CN(flags); } -inline size_t GpuMat::step1() const { return step/elemSize1(); } -inline Size GpuMat::size() const { return Size(cols, rows); } -inline bool GpuMat::empty() const { return data == 0; } - -inline uchar* GpuMat::ptr(int y) -{ - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - return data + step*y; -} - -inline const uchar* GpuMat::ptr(int y) const -{ - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - return data + step*y; -} - -template inline _Tp* GpuMat::ptr(int y) -{ - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - return (_Tp*)(data + step*y); -} - -template inline const _Tp* GpuMat::ptr(int y) const -{ - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - return (const _Tp*)(data + step*y); -} - -inline GpuMat GpuMat::t() const -{ - GpuMat tmp; - transpose(*this, tmp); - return tmp; -} - -static inline void swap( GpuMat& a, GpuMat& b ) { a.swap(b); } - -inline GpuMat createContinuous(int rows, int cols, int type) -{ - GpuMat m; - createContinuous(rows, cols, type, m); - return m; -} - -inline void createContinuous(Size size, int type, GpuMat& m) -{ - createContinuous(size.height, size.width, type, m); -} - -inline GpuMat createContinuous(Size size, int type) -{ - GpuMat m; - createContinuous(size, type, m); - return m; -} - -inline void ensureSizeIsEnough(Size size, int type, GpuMat& m) -{ - ensureSizeIsEnough(size.height, size.width, type, m); -} - - /////////////////////////////////////////////////////////////////////// //////////////////////////////// CudaMem //////////////////////////////// /////////////////////////////////////////////////////////////////////// @@ -457,41 +135,6 @@ inline size_t CudaMem::step1() const { return step/elemSize1(); } inline Size CudaMem::size() const { return Size(cols, rows); } inline bool CudaMem::empty() const { return data == 0; } -////////////////////////////////////////////////////////////////////////////// -// Arithmetical operations - -inline GpuMat operator ~ (const GpuMat& src) -{ - GpuMat dst; - bitwise_not(src, dst); - return dst; -} - - -inline GpuMat operator | (const GpuMat& src1, const GpuMat& src2) -{ - GpuMat dst; - bitwise_or(src1, src2, dst); - return dst; -} - - -inline GpuMat operator & (const GpuMat& src1, const GpuMat& src2) -{ - GpuMat dst; - bitwise_and(src1, src2, dst); - return dst; -} - - -inline GpuMat operator ^ (const GpuMat& src1, const GpuMat& src2) -{ - GpuMat dst; - bitwise_xor(src1, src2, dst); - return dst; -} - - } /* end of namespace gpu */ } /* end of namespace cv */ diff --git a/modules/gpu/src/arithm.cpp b/modules/gpu/src/arithm.cpp index 176eeb3025..67da283eb6 100644 --- a/modules/gpu/src/arithm.cpp +++ b/modules/gpu/src/arithm.cpp @@ -82,7 +82,8 @@ void cv::gpu::transpose(const GpuMat& src, GpuMat& dst, Stream& s) sz.width = src.cols; sz.height = src.rows; - nppSafeCall( nppiTranspose_8u_C1R(src.ptr(), src.step, dst.ptr(), dst.step, sz) ); + nppSafeCall( nppiTranspose_8u_C1R(src.ptr(), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz) ); } else if (src.elemSize() == 4) { @@ -92,8 +93,8 @@ void cv::gpu::transpose(const GpuMat& src, GpuMat& dst, Stream& s) sz.width = src.cols; sz.height = src.rows; - nppSafeCall( nppiStTranspose_32u_C1R(const_cast(src.ptr()), src.step, - dst.ptr(), dst.step, sz) ); + nppSafeCall( nppiStTranspose_32u_C1R(const_cast(src.ptr()), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz) ); } else // if (src.elemSize() == 8) { @@ -103,8 +104,8 @@ void cv::gpu::transpose(const GpuMat& src, GpuMat& dst, Stream& s) sz.width = src.cols; sz.height = src.rows; - nppSafeCall( nppiStTranspose_64u_C1R(const_cast(src.ptr()), src.step, - dst.ptr(), dst.step, sz) ); + nppSafeCall( nppiStTranspose_64u_C1R(const_cast(src.ptr()), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz) ); } if (stream == 0) @@ -130,14 +131,14 @@ void cv::gpu::flip(const GpuMat& src, GpuMat& dst, int flipCode, Stream& s) if (src.type() == CV_8UC1) { - nppSafeCall( nppiMirror_8u_C1R(src.ptr(), src.step, - dst.ptr(), dst.step, sz, + nppSafeCall( nppiMirror_8u_C1R(src.ptr(), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz, (flipCode == 0 ? NPP_HORIZONTAL_AXIS : (flipCode > 0 ? NPP_VERTICAL_AXIS : NPP_BOTH_AXIS))) ); } else { - nppSafeCall( nppiMirror_8u_C4R(src.ptr(), src.step, - dst.ptr(), dst.step, sz, + nppSafeCall( nppiMirror_8u_C4R(src.ptr(), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz, (flipCode == 0 ? NPP_HORIZONTAL_AXIS : (flipCode > 0 ? NPP_VERTICAL_AXIS : NPP_BOTH_AXIS))) ); } @@ -187,7 +188,8 @@ void cv::gpu::LUT(const GpuMat& src, const Mat& lut, GpuMat& dst, Stream& s) if (src.type() == CV_8UC1) { - nppSafeCall( nppiLUT_Linear_8u_C1R(src.ptr(), src.step, dst.ptr(), dst.step, sz, nppLut.ptr(), lvls.pLevels, 256) ); + nppSafeCall( nppiLUT_Linear_8u_C1R(src.ptr(), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz, nppLut.ptr(), lvls.pLevels, 256) ); } else { @@ -202,7 +204,8 @@ void cv::gpu::LUT(const GpuMat& src, const Mat& lut, GpuMat& dst, Stream& s) pValues3[1] = nppLut3[1].ptr(); pValues3[2] = nppLut3[2].ptr(); } - nppSafeCall( nppiLUT_Linear_8u_C3R(src.ptr(), src.step, dst.ptr(), dst.step, sz, pValues3, lvls.pLevels3, lvls.nValues3) ); + nppSafeCall( nppiLUT_Linear_8u_C3R(src.ptr(), static_cast(src.step), + dst.ptr(), static_cast(dst.step), sz, pValues3, lvls.pLevels3, lvls.nValues3) ); } if (stream == 0) @@ -226,7 +229,7 @@ void cv::gpu::exp(const GpuMat& src, GpuMat& dst, Stream& s) NppStreamHandler h(stream); - nppSafeCall( nppiExp_32f_C1R(src.ptr(), src.step, dst.ptr(), dst.step, sz) ); + nppSafeCall( nppiExp_32f_C1R(src.ptr(), static_cast(src.step), dst.ptr(), static_cast(dst.step), sz) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -249,7 +252,7 @@ void cv::gpu::log(const GpuMat& src, GpuMat& dst, Stream& s) NppStreamHandler h(stream); - nppSafeCall( nppiLn_32f_C1R(src.ptr(), src.step, dst.ptr(), dst.step, sz) ); + nppSafeCall( nppiLn_32f_C1R(src.ptr(), static_cast(src.step), dst.ptr(), static_cast(dst.step), sz) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -274,7 +277,7 @@ namespace NppStreamHandler h(stream); - nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz) ); + nppSafeCall( func(src.ptr(), static_cast(src.step), dst.ptr(), static_cast(dst.step), sz) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); diff --git a/modules/gpu/src/brute_force_matcher.cpp b/modules/gpu/src/brute_force_matcher.cpp index d8805a7f54..19521a2a64 100644 --- a/modules/gpu/src/brute_force_matcher.cpp +++ b/modules/gpu/src/brute_force_matcher.cpp @@ -56,17 +56,21 @@ bool cv::gpu::BruteForceMatcher_GPU_base::empty() const { throw_nogpu(); return bool cv::gpu::BruteForceMatcher_GPU_base::isMaskSupported() const { throw_nogpu(); return true; } void cv::gpu::BruteForceMatcher_GPU_base::matchSingle(const GpuMat&, const GpuMat&, GpuMat&, GpuMat&, const GpuMat&, Stream&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat&, const GpuMat&, vector&) { throw_nogpu(); } +void cv::gpu::BruteForceMatcher_GPU_base::matchConvert(const Mat&, const Mat&, std::vector&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::match(const GpuMat&, const GpuMat&, vector&, const GpuMat&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::makeGpuCollection(GpuMat&, GpuMat&, const vector&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::matchCollection(const GpuMat&, const GpuMat&, GpuMat&, GpuMat&, GpuMat&, const GpuMat&, Stream&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat&, const GpuMat&, const GpuMat&, std::vector&) { throw_nogpu(); } +void cv::gpu::BruteForceMatcher_GPU_base::matchConvert(const Mat&, const Mat&, const Mat&, std::vector&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::match(const GpuMat&, std::vector&, const std::vector&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::knnMatch(const GpuMat&, const GpuMat&, GpuMat&, GpuMat&, GpuMat&, int, const GpuMat&, Stream&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::knnMatchDownload(const GpuMat&, const GpuMat&, std::vector< std::vector >&, bool) { throw_nogpu(); } +void cv::gpu::BruteForceMatcher_GPU_base::knnMatchConvert(const Mat&, const Mat&, std::vector< std::vector >&, bool) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::knnMatch(const GpuMat&, const GpuMat&, std::vector< std::vector >&, int, const GpuMat&, bool) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::knnMatch(const GpuMat&, std::vector< std::vector >&, int, const std::vector&, bool) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::radiusMatch(const GpuMat&, const GpuMat&, GpuMat&, GpuMat&, GpuMat&, float, const GpuMat&, Stream&) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::radiusMatchDownload(const GpuMat&, const GpuMat&, const GpuMat&, std::vector< std::vector >&, bool) { throw_nogpu(); } +void cv::gpu::BruteForceMatcher_GPU_base::radiusMatchConvert(const Mat&, const Mat&, const Mat&, std::vector< std::vector >&, bool) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::radiusMatch(const GpuMat&, const GpuMat&, std::vector< std::vector >&, float, const GpuMat&, bool) { throw_nogpu(); } void cv::gpu::BruteForceMatcher_GPU_base::radiusMatch(const GpuMat&, std::vector< std::vector >&, float, const std::vector&, bool) { throw_nogpu(); } @@ -203,8 +207,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchSingle(const GpuMat& queryDescs, const int nQuery = queryDescs.rows; - trainIdx.create(1, nQuery, CV_32S); - distance.create(1, nQuery, CV_32F); + ensureSizeIsEnough(1, nQuery, CV_32S, trainIdx); + ensureSizeIsEnough(1, nQuery, CV_32F, distance); match_caller_t func = match_callers[distType][queryDescs.depth()]; CV_Assert(func != 0); @@ -216,8 +220,18 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchSingle(const GpuMat& queryDescs, func(queryDescs, trainDescs, mask, trainIdx, trainIdx, distance, cc_12, StreamAccessor::getStream(stream)); } -void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, const GpuMat& distance, - vector& matches) +void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, const GpuMat& distance, vector& matches) +{ + if (trainIdx.empty() || distance.empty()) + return; + + Mat trainIdxCPU = trainIdx; + Mat distanceCPU = distance; + + matchConvert(trainIdxCPU, distanceCPU, matches); +} + +void cv::gpu::BruteForceMatcher_GPU_base::matchConvert(const Mat& trainIdx, const Mat& distance, std::vector& matches) { if (trainIdx.empty() || distance.empty()) return; @@ -227,14 +241,11 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, const int nQuery = trainIdx.cols; - Mat trainIdxCPU = trainIdx; - Mat distanceCPU = distance; - matches.clear(); matches.reserve(nQuery); - const int* trainIdx_ptr = trainIdxCPU.ptr(); - const float* distance_ptr = distanceCPU.ptr(); + const int* trainIdx_ptr = trainIdx.ptr(); + const float* distance_ptr = distance.ptr(); for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx, ++trainIdx_ptr, ++distance_ptr) { int trainIdx = *trainIdx_ptr; @@ -265,7 +276,7 @@ void cv::gpu::BruteForceMatcher_GPU_base::makeGpuCollection(GpuMat& trainCollect if (masks.empty()) { - Mat trainCollectionCPU(1, trainDescCollection.size(), CV_8UC(sizeof(DevMem2D))); + Mat trainCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(DevMem2D))); for (size_t i = 0; i < trainDescCollection.size(); ++i) { @@ -280,8 +291,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::makeGpuCollection(GpuMat& trainCollect { CV_Assert(masks.size() == trainDescCollection.size()); - Mat trainCollectionCPU(1, trainDescCollection.size(), CV_8UC(sizeof(DevMem2D))); - Mat maskCollectionCPU(1, trainDescCollection.size(), CV_8UC(sizeof(PtrStep))); + Mat trainCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(DevMem2D))); + Mat maskCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(PtrStep))); for (size_t i = 0; i < trainDescCollection.size(); ++i) { @@ -335,9 +346,9 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchCollection(const GpuMat& queryDes const int nQuery = queryDescs.rows; - trainIdx.create(1, nQuery, CV_32S); - imgIdx.create(1, nQuery, CV_32S); - distance.create(1, nQuery, CV_32F); + ensureSizeIsEnough(1, nQuery, CV_32S, trainIdx); + ensureSizeIsEnough(1, nQuery, CV_32S, imgIdx); + ensureSizeIsEnough(1, nQuery, CV_32F, distance); match_caller_t func = match_callers[distType][queryDescs.depth()]; CV_Assert(func != 0); @@ -347,8 +358,19 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchCollection(const GpuMat& queryDes func(queryDescs, trainCollection, maskCollection, trainIdx, imgIdx, distance, cc_12, StreamAccessor::getStream(stream)); } -void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, const GpuMat& imgIdx, - const GpuMat& distance, vector& matches) +void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, const GpuMat& imgIdx, const GpuMat& distance, vector& matches) +{ + if (trainIdx.empty() || imgIdx.empty() || distance.empty()) + return; + + Mat trainIdxCPU = trainIdx; + Mat imgIdxCPU = imgIdx; + Mat distanceCPU = distance; + + matchConvert(trainIdxCPU, imgIdxCPU, distanceCPU, matches); +} + +void cv::gpu::BruteForceMatcher_GPU_base::matchConvert(const Mat& trainIdx, const Mat& imgIdx, const Mat& distance, std::vector& matches) { if (trainIdx.empty() || imgIdx.empty() || distance.empty()) return; @@ -359,16 +381,12 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, const int nQuery = trainIdx.cols; - Mat trainIdxCPU = trainIdx; - Mat imgIdxCPU = imgIdx; - Mat distanceCPU = distance; - matches.clear(); matches.reserve(nQuery); - const int* trainIdx_ptr = trainIdxCPU.ptr(); - const int* imgIdx_ptr = imgIdxCPU.ptr(); - const float* distance_ptr = distanceCPU.ptr(); + const int* trainIdx_ptr = trainIdx.ptr(); + const int* imgIdx_ptr = imgIdx.ptr(); + const float* distance_ptr = distance.ptr(); for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx, ++trainIdx_ptr, ++imgIdx_ptr, ++distance_ptr) { int trainIdx = *trainIdx_ptr; @@ -385,8 +403,7 @@ void cv::gpu::BruteForceMatcher_GPU_base::matchDownload(const GpuMat& trainIdx, } } -void cv::gpu::BruteForceMatcher_GPU_base::match(const GpuMat& queryDescs, vector& matches, - const vector& masks) +void cv::gpu::BruteForceMatcher_GPU_base::match(const GpuMat& queryDescs, vector& matches, const vector& masks) { GpuMat trainCollection; GpuMat maskCollection; @@ -435,8 +452,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::knnMatch(const GpuMat& queryDescs, con const int nQuery = queryDescs.rows; const int nTrain = trainDescs.rows; - trainIdx.create(nQuery, k, CV_32S); - distance.create(nQuery, k, CV_32F); + ensureSizeIsEnough(nQuery, k, CV_32S, trainIdx); + ensureSizeIsEnough(nQuery, k, CV_32F, distance); ensureSizeIsEnough(nQuery, nTrain, CV_32FC1, allDist); if (stream) @@ -462,15 +479,24 @@ void cv::gpu::BruteForceMatcher_GPU_base::knnMatchDownload(const GpuMat& trainId if (trainIdx.empty() || distance.empty()) return; + Mat trainIdxCPU = trainIdx; + Mat distanceCPU = distance; + + knnMatchConvert(trainIdxCPU, distanceCPU, matches, compactResult); +} + +void cv::gpu::BruteForceMatcher_GPU_base::knnMatchConvert(const Mat& trainIdx, const Mat& distance, + std::vector< std::vector >& matches, bool compactResult) +{ + if (trainIdx.empty() || distance.empty()) + return; + CV_Assert(trainIdx.type() == CV_32SC1); CV_Assert(distance.type() == CV_32FC1 && distance.size() == trainIdx.size()); const int nQuery = distance.rows; const int k = trainIdx.cols; - Mat trainIdxCPU = trainIdx; - Mat distanceCPU = distance; - matches.clear(); matches.reserve(nQuery); @@ -480,8 +506,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::knnMatchDownload(const GpuMat& trainId vector& curMatches = matches.back(); curMatches.reserve(k); - int* trainIdx_ptr = trainIdxCPU.ptr(queryIdx); - float* distance_ptr = distanceCPU.ptr(queryIdx); + const int* trainIdx_ptr = trainIdx.ptr(queryIdx); + const float* distance_ptr = distance.ptr(queryIdx); for (int i = 0; i < k; ++i, ++trainIdx_ptr, ++distance_ptr) { int trainIdx = *trainIdx_ptr; @@ -593,8 +619,8 @@ void cv::gpu::BruteForceMatcher_GPU_base::radiusMatch(const GpuMat& queryDescs, ensureSizeIsEnough(1, nQuery, CV_32SC1, nMatches); if (trainIdx.empty()) { - trainIdx.create(nQuery, nTrain, CV_32SC1); - distance.create(nQuery, nTrain, CV_32FC1); + ensureSizeIsEnough(nQuery, nTrain, CV_32SC1, trainIdx); + ensureSizeIsEnough(nQuery, nTrain, CV_32FC1, distance); } if (stream) @@ -614,24 +640,33 @@ void cv::gpu::BruteForceMatcher_GPU_base::radiusMatchDownload(const GpuMat& trai if (trainIdx.empty() || nMatches.empty() || distance.empty()) return; + Mat trainIdxCPU = trainIdx; + Mat nMatchesCPU = nMatches; + Mat distanceCPU = distance; + + radiusMatchConvert(trainIdxCPU, nMatchesCPU, distanceCPU, matches, compactResult); +} + +void cv::gpu::BruteForceMatcher_GPU_base::radiusMatchConvert(const Mat& trainIdx, const Mat& nMatches, const Mat& distance, + std::vector< std::vector >& matches, bool compactResult) +{ + if (trainIdx.empty() || nMatches.empty() || distance.empty()) + return; + CV_Assert(trainIdx.type() == CV_32SC1); CV_Assert(nMatches.type() == CV_32SC1 && nMatches.isContinuous() && nMatches.cols >= trainIdx.rows); CV_Assert(distance.type() == CV_32FC1 && distance.size() == trainIdx.size()); const int nQuery = trainIdx.rows; - Mat trainIdxCPU = trainIdx; - Mat nMatchesCPU = nMatches; - Mat distanceCPU = distance; - matches.clear(); matches.reserve(nQuery); - const unsigned int* nMatches_ptr = nMatchesCPU.ptr(); + const unsigned int* nMatches_ptr = nMatches.ptr(); for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx) { - const int* trainIdx_ptr = trainIdxCPU.ptr(queryIdx); - const float* distance_ptr = distanceCPU.ptr(queryIdx); + const int* trainIdx_ptr = trainIdx.ptr(queryIdx); + const float* distance_ptr = distance.ptr(queryIdx); const int nMatches = std::min(static_cast(nMatches_ptr[queryIdx]), trainIdx.cols); diff --git a/modules/gpu/src/calib3d.cpp b/modules/gpu/src/calib3d.cpp index 84db041148..301ea8167e 100644 --- a/modules/gpu/src/calib3d.cpp +++ b/modules/gpu/src/calib3d.cpp @@ -1,290 +1,290 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" - -#if !defined(HAVE_CUDA) - -void cv::gpu::transformPoints(const GpuMat&, const Mat&, const Mat&, GpuMat&, Stream&) { throw_nogpu(); } - -void cv::gpu::projectPoints(const GpuMat&, const Mat&, const Mat&, const Mat&, const Mat&, GpuMat&, Stream&) { throw_nogpu(); } - -void cv::gpu::solvePnPRansac(const Mat&, const Mat&, const Mat&, const Mat&, Mat&, Mat&, bool, int, float, int, vector*) { throw_nogpu(); } - -#else - -using namespace cv; -using namespace cv::gpu; - -namespace cv { namespace gpu { namespace transform_points -{ - void call(const DevMem2D_ src, const float* rot, const float* transl, DevMem2D_ dst, cudaStream_t stream); -}}} - -namespace -{ - void transformPointsCaller(const GpuMat& src, const Mat& rvec, const Mat& tvec, GpuMat& dst, cudaStream_t stream) - { - CV_Assert(src.rows == 1 && src.cols > 0 && src.type() == CV_32FC3); - CV_Assert(rvec.size() == Size(3, 1) && rvec.type() == CV_32F); - CV_Assert(tvec.size() == Size(3, 1) && tvec.type() == CV_32F); - - // Convert rotation vector into matrix - Mat rot; - Rodrigues(rvec, rot); - - dst.create(src.size(), src.type()); - transform_points::call(src, rot.ptr(), tvec.ptr(), dst, stream); - } -} - -void cv::gpu::transformPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, GpuMat& dst, Stream& stream) -{ - ::transformPointsCaller(src, rvec, tvec, dst, StreamAccessor::getStream(stream)); -} - -namespace cv { namespace gpu { namespace project_points -{ - void call(const DevMem2D_ src, const float* rot, const float* transl, const float* proj, DevMem2D_ dst, cudaStream_t stream); -}}} - - -namespace -{ - void projectPointsCaller(const GpuMat& src, const Mat& rvec, const Mat& tvec, const Mat& camera_mat, const Mat& dist_coef, GpuMat& dst, cudaStream_t stream) - { - CV_Assert(src.rows == 1 && src.cols > 0 && src.type() == CV_32FC3); - CV_Assert(rvec.size() == Size(3, 1) && rvec.type() == CV_32F); - CV_Assert(tvec.size() == Size(3, 1) && tvec.type() == CV_32F); - CV_Assert(camera_mat.size() == Size(3, 3) && camera_mat.type() == CV_32F); - CV_Assert(dist_coef.empty()); // Undistortion isn't supported - - // Convert rotation vector into matrix - Mat rot; - Rodrigues(rvec, rot); - - dst.create(src.size(), CV_32FC2); - project_points::call(src, rot.ptr(), tvec.ptr(), camera_mat.ptr(), dst,stream); - } -} - -void cv::gpu::projectPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, const Mat& camera_mat, const Mat& dist_coef, GpuMat& dst, Stream& stream) -{ - ::projectPointsCaller(src, rvec, tvec, camera_mat, dist_coef, dst, StreamAccessor::getStream(stream)); -} - - -namespace cv { namespace gpu { namespace solve_pnp_ransac -{ - int maxNumIters(); - - void computeHypothesisScores( - const int num_hypotheses, const int num_points, const float* rot_matrices, - const float3* transl_vectors, const float3* object, const float2* image, - const float dist_threshold, int* hypothesis_scores); -}}} - -namespace -{ - // Selects subset_size random different points from [0, num_points - 1] range - void selectRandom(int subset_size, int num_points, vector& subset) - { - subset.resize(subset_size); - for (int i = 0; i < subset_size; ++i) - { - bool was; - do - { - subset[i] = rand() % num_points; - was = false; - for (int j = 0; j < i; ++j) - if (subset[j] == subset[i]) - { - was = true; - break; - } - } while (was); - } - } - - // Computes rotation, translation pair for small subsets if the input data - class TransformHypothesesGenerator - { - public: - TransformHypothesesGenerator(const Mat& object_, const Mat& image_, const Mat& dist_coef_, - const Mat& camera_mat_, int num_points_, int subset_size_, - Mat rot_matrices_, Mat transl_vectors_) - : object(&object_), image(&image_), dist_coef(&dist_coef_), camera_mat(&camera_mat_), - num_points(num_points_), subset_size(subset_size_), rot_matrices(rot_matrices_), - transl_vectors(transl_vectors_) {} - - void operator()(const BlockedRange& range) const - { - // Input data for generation of the current hypothesis - vector subset_indices(subset_size); - Mat_ object_subset(1, subset_size); - Mat_ image_subset(1, subset_size); - - // Current hypothesis data - Mat rot_vec(1, 3, CV_64F); - Mat rot_mat(3, 3, CV_64F); - Mat transl_vec(1, 3, CV_64F); - - for (int iter = range.begin(); iter < range.end(); ++iter) - { - selectRandom(subset_size, num_points, subset_indices); - for (int i = 0; i < subset_size; ++i) - { - object_subset(0, i) = object->at(subset_indices[i]); - image_subset(0, i) = image->at(subset_indices[i]); - } - - solvePnP(object_subset, image_subset, *camera_mat, *dist_coef, rot_vec, transl_vec); - - // Remember translation vector - Mat transl_vec_ = transl_vectors.colRange(iter * 3, (iter + 1) * 3); - transl_vec = transl_vec.reshape(0, 1); - transl_vec.convertTo(transl_vec_, CV_32F); - - // Remember rotation matrix - Rodrigues(rot_vec, rot_mat); - Mat rot_mat_ = rot_matrices.colRange(iter * 9, (iter + 1) * 9).reshape(0, 3); - rot_mat.convertTo(rot_mat_, CV_32F); - } - } - - const Mat* object; - const Mat* image; - const Mat* dist_coef; - const Mat* camera_mat; - int num_points; - int subset_size; - - // Hypotheses storage (global) - Mat rot_matrices; - Mat transl_vectors; - }; -} - +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +#if !defined(HAVE_CUDA) + +void cv::gpu::transformPoints(const GpuMat&, const Mat&, const Mat&, GpuMat&, Stream&) { throw_nogpu(); } + +void cv::gpu::projectPoints(const GpuMat&, const Mat&, const Mat&, const Mat&, const Mat&, GpuMat&, Stream&) { throw_nogpu(); } + +void cv::gpu::solvePnPRansac(const Mat&, const Mat&, const Mat&, const Mat&, Mat&, Mat&, bool, int, float, int, vector*) { throw_nogpu(); } + +#else + +using namespace cv; +using namespace cv::gpu; + +namespace cv { namespace gpu { namespace transform_points +{ + void call(const DevMem2D_ src, const float* rot, const float* transl, DevMem2D_ dst, cudaStream_t stream); +}}} + +namespace +{ + void transformPointsCaller(const GpuMat& src, const Mat& rvec, const Mat& tvec, GpuMat& dst, cudaStream_t stream) + { + CV_Assert(src.rows == 1 && src.cols > 0 && src.type() == CV_32FC3); + CV_Assert(rvec.size() == Size(3, 1) && rvec.type() == CV_32F); + CV_Assert(tvec.size() == Size(3, 1) && tvec.type() == CV_32F); + + // Convert rotation vector into matrix + Mat rot; + Rodrigues(rvec, rot); + + dst.create(src.size(), src.type()); + transform_points::call(src, rot.ptr(), tvec.ptr(), dst, stream); + } +} + +void cv::gpu::transformPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, GpuMat& dst, Stream& stream) +{ + ::transformPointsCaller(src, rvec, tvec, dst, StreamAccessor::getStream(stream)); +} + +namespace cv { namespace gpu { namespace project_points +{ + void call(const DevMem2D_ src, const float* rot, const float* transl, const float* proj, DevMem2D_ dst, cudaStream_t stream); +}}} + + +namespace +{ + void projectPointsCaller(const GpuMat& src, const Mat& rvec, const Mat& tvec, const Mat& camera_mat, const Mat& dist_coef, GpuMat& dst, cudaStream_t stream) + { + CV_Assert(src.rows == 1 && src.cols > 0 && src.type() == CV_32FC3); + CV_Assert(rvec.size() == Size(3, 1) && rvec.type() == CV_32F); + CV_Assert(tvec.size() == Size(3, 1) && tvec.type() == CV_32F); + CV_Assert(camera_mat.size() == Size(3, 3) && camera_mat.type() == CV_32F); + CV_Assert(dist_coef.empty()); // Undistortion isn't supported + + // Convert rotation vector into matrix + Mat rot; + Rodrigues(rvec, rot); + + dst.create(src.size(), CV_32FC2); + project_points::call(src, rot.ptr(), tvec.ptr(), camera_mat.ptr(), dst,stream); + } +} + +void cv::gpu::projectPoints(const GpuMat& src, const Mat& rvec, const Mat& tvec, const Mat& camera_mat, const Mat& dist_coef, GpuMat& dst, Stream& stream) +{ + ::projectPointsCaller(src, rvec, tvec, camera_mat, dist_coef, dst, StreamAccessor::getStream(stream)); +} + + +namespace cv { namespace gpu { namespace solve_pnp_ransac +{ + int maxNumIters(); + + void computeHypothesisScores( + const int num_hypotheses, const int num_points, const float* rot_matrices, + const float3* transl_vectors, const float3* object, const float2* image, + const float dist_threshold, int* hypothesis_scores); +}}} + +namespace +{ + // Selects subset_size random different points from [0, num_points - 1] range + void selectRandom(int subset_size, int num_points, vector& subset) + { + subset.resize(subset_size); + for (int i = 0; i < subset_size; ++i) + { + bool was; + do + { + subset[i] = rand() % num_points; + was = false; + for (int j = 0; j < i; ++j) + if (subset[j] == subset[i]) + { + was = true; + break; + } + } while (was); + } + } + + // Computes rotation, translation pair for small subsets if the input data + class TransformHypothesesGenerator + { + public: + TransformHypothesesGenerator(const Mat& object_, const Mat& image_, const Mat& dist_coef_, + const Mat& camera_mat_, int num_points_, int subset_size_, + Mat rot_matrices_, Mat transl_vectors_) + : object(&object_), image(&image_), dist_coef(&dist_coef_), camera_mat(&camera_mat_), + num_points(num_points_), subset_size(subset_size_), rot_matrices(rot_matrices_), + transl_vectors(transl_vectors_) {} + + void operator()(const BlockedRange& range) const + { + // Input data for generation of the current hypothesis + vector subset_indices(subset_size); + Mat_ object_subset(1, subset_size); + Mat_ image_subset(1, subset_size); + + // Current hypothesis data + Mat rot_vec(1, 3, CV_64F); + Mat rot_mat(3, 3, CV_64F); + Mat transl_vec(1, 3, CV_64F); + + for (int iter = range.begin(); iter < range.end(); ++iter) + { + selectRandom(subset_size, num_points, subset_indices); + for (int i = 0; i < subset_size; ++i) + { + object_subset(0, i) = object->at(subset_indices[i]); + image_subset(0, i) = image->at(subset_indices[i]); + } + + solvePnP(object_subset, image_subset, *camera_mat, *dist_coef, rot_vec, transl_vec); + + // Remember translation vector + Mat transl_vec_ = transl_vectors.colRange(iter * 3, (iter + 1) * 3); + transl_vec = transl_vec.reshape(0, 1); + transl_vec.convertTo(transl_vec_, CV_32F); + + // Remember rotation matrix + Rodrigues(rot_vec, rot_mat); + Mat rot_mat_ = rot_matrices.colRange(iter * 9, (iter + 1) * 9).reshape(0, 3); + rot_mat.convertTo(rot_mat_, CV_32F); + } + } + + const Mat* object; + const Mat* image; + const Mat* dist_coef; + const Mat* camera_mat; + int num_points; + int subset_size; + + // Hypotheses storage (global) + Mat rot_matrices; + Mat transl_vectors; + }; +} + void cv::gpu::solvePnPRansac(const Mat& object, const Mat& image, const Mat& camera_mat, const Mat& dist_coef, Mat& rvec, Mat& tvec, bool use_extrinsic_guess, int num_iters, float max_dist, int min_inlier_count, - vector* inliers) -{ - CV_Assert(object.rows == 1 && object.cols > 0 && object.type() == CV_32FC3); - CV_Assert(image.rows == 1 && image.cols > 0 && image.type() == CV_32FC2); - CV_Assert(object.cols == image.cols); - CV_Assert(camera_mat.size() == Size(3, 3) && camera_mat.type() == CV_32F); - CV_Assert(!use_extrinsic_guess); // We don't support initial guess for now - CV_Assert(num_iters <= solve_pnp_ransac::maxNumIters()); - - const int subset_size = 4; - const int num_points = object.cols; - CV_Assert(num_points >= subset_size); - - // Unapply distortion and intrinsic camera transformations - Mat eye_camera_mat = Mat::eye(3, 3, CV_32F); - Mat empty_dist_coef; - Mat image_normalized; - undistortPoints(image, image_normalized, camera_mat, dist_coef, Mat(), eye_camera_mat); - - // Hypotheses storage (global) - Mat rot_matrices(1, num_iters * 9, CV_32F); - Mat transl_vectors(1, num_iters * 3, CV_32F); - - // Generate set of hypotheses using small subsets of the input data - TransformHypothesesGenerator body(object, image_normalized, empty_dist_coef, eye_camera_mat, - num_points, subset_size, rot_matrices, transl_vectors); - parallel_for(BlockedRange(0, num_iters), body); - - // Compute scores (i.e. number of inliers) for each hypothesis - GpuMat d_object(object); - GpuMat d_image_normalized(image_normalized); - GpuMat d_hypothesis_scores(1, num_iters, CV_32S); - solve_pnp_ransac::computeHypothesisScores( - num_iters, num_points, rot_matrices.ptr(), transl_vectors.ptr(), - d_object.ptr(), d_image_normalized.ptr(), max_dist * max_dist, - d_hypothesis_scores.ptr()); - - // Find the best hypothesis index - Point best_idx; - double best_score; - minMaxLoc(d_hypothesis_scores, NULL, &best_score, NULL, &best_idx); - int num_inliers = static_cast(best_score); - - // Extract the best hypothesis data - - Mat rot_mat = rot_matrices.colRange(best_idx.x * 9, (best_idx.x + 1) * 9).reshape(0, 3); - Rodrigues(rot_mat, rvec); - rvec = rvec.reshape(0, 1); - - tvec = transl_vectors.colRange(best_idx.x * 3, (best_idx.x + 1) * 3).clone(); - tvec = tvec.reshape(0, 1); - - // Build vector of inlier indices - if (inliers != NULL) - { - inliers->clear(); - inliers->reserve(num_inliers); - - Point3f p, p_transf; - Point2f p_proj; - const float* rot = rot_mat.ptr(); - const float* transl = tvec.ptr(); - - for (int i = 0; i < num_points; ++i) - { - p = object.at(0, i); - p_transf.x = rot[0] * p.x + rot[1] * p.y + rot[2] * p.z + transl[0]; - p_transf.y = rot[3] * p.x + rot[4] * p.y + rot[5] * p.z + transl[1]; - p_transf.z = rot[6] * p.x + rot[7] * p.y + rot[8] * p.z + transl[2]; - p_proj.x = p_transf.x / p_transf.z; - p_proj.y = p_transf.y / p_transf.z; - if (norm(p_proj - image_normalized.at(0, i)) < max_dist) - inliers->push_back(i); - } - } -} - -#endif - - + vector* inliers) +{ + CV_Assert(object.rows == 1 && object.cols > 0 && object.type() == CV_32FC3); + CV_Assert(image.rows == 1 && image.cols > 0 && image.type() == CV_32FC2); + CV_Assert(object.cols == image.cols); + CV_Assert(camera_mat.size() == Size(3, 3) && camera_mat.type() == CV_32F); + CV_Assert(!use_extrinsic_guess); // We don't support initial guess for now + CV_Assert(num_iters <= solve_pnp_ransac::maxNumIters()); + + const int subset_size = 4; + const int num_points = object.cols; + CV_Assert(num_points >= subset_size); + + // Unapply distortion and intrinsic camera transformations + Mat eye_camera_mat = Mat::eye(3, 3, CV_32F); + Mat empty_dist_coef; + Mat image_normalized; + undistortPoints(image, image_normalized, camera_mat, dist_coef, Mat(), eye_camera_mat); + + // Hypotheses storage (global) + Mat rot_matrices(1, num_iters * 9, CV_32F); + Mat transl_vectors(1, num_iters * 3, CV_32F); + + // Generate set of hypotheses using small subsets of the input data + TransformHypothesesGenerator body(object, image_normalized, empty_dist_coef, eye_camera_mat, + num_points, subset_size, rot_matrices, transl_vectors); + parallel_for(BlockedRange(0, num_iters), body); + + // Compute scores (i.e. number of inliers) for each hypothesis + GpuMat d_object(object); + GpuMat d_image_normalized(image_normalized); + GpuMat d_hypothesis_scores(1, num_iters, CV_32S); + solve_pnp_ransac::computeHypothesisScores( + num_iters, num_points, rot_matrices.ptr(), transl_vectors.ptr(), + d_object.ptr(), d_image_normalized.ptr(), max_dist * max_dist, + d_hypothesis_scores.ptr()); + + // Find the best hypothesis index + Point best_idx; + double best_score; + minMaxLoc(d_hypothesis_scores, NULL, &best_score, NULL, &best_idx); + int num_inliers = static_cast(best_score); + + // Extract the best hypothesis data + + Mat rot_mat = rot_matrices.colRange(best_idx.x * 9, (best_idx.x + 1) * 9).reshape(0, 3); + Rodrigues(rot_mat, rvec); + rvec = rvec.reshape(0, 1); + + tvec = transl_vectors.colRange(best_idx.x * 3, (best_idx.x + 1) * 3).clone(); + tvec = tvec.reshape(0, 1); + + // Build vector of inlier indices + if (inliers != NULL) + { + inliers->clear(); + inliers->reserve(num_inliers); + + Point3f p, p_transf; + Point2f p_proj; + const float* rot = rot_mat.ptr(); + const float* transl = tvec.ptr(); + + for (int i = 0; i < num_points; ++i) + { + p = object.at(0, i); + p_transf.x = rot[0] * p.x + rot[1] * p.y + rot[2] * p.z + transl[0]; + p_transf.y = rot[3] * p.x + rot[4] * p.y + rot[5] * p.z + transl[1]; + p_transf.z = rot[6] * p.x + rot[7] * p.y + rot[8] * p.z + transl[2]; + p_proj.x = p_transf.x / p_transf.z; + p_proj.y = p_transf.y / p_transf.z; + if (norm(p_proj - image_normalized.at(0, i)) < max_dist) + inliers->push_back(i); + } + } +} + +#endif + + diff --git a/modules/gpu/src/cascadeclassifier.cpp b/modules/gpu/src/cascadeclassifier.cpp index 0ffd10c715..984b33f820 100644 --- a/modules/gpu/src/cascadeclassifier.cpp +++ b/modules/gpu/src/cascadeclassifier.cpp @@ -87,7 +87,7 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl src_seg.begin = src_beg; src_seg.size = src.step * src.rows; - NCVMatrixReuse d_src(src_seg, devProp.textureAlignment, src.cols, src.rows, src.step, true); + NCVMatrixReuse d_src(src_seg, static_cast(devProp.textureAlignment), src.cols, src.rows, static_cast(src.step), true); ncvAssertReturn(d_src.isMemReused(), NCV_ALLOCATOR_BAD_REUSE); CV_Assert(objects.rows == 1); @@ -141,8 +141,8 @@ private: ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), NCV_CUDA_ERROR); // Load the classifier from file (assuming its size is about 1 mb) using a simple allocator - gpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeDevice, devProp.textureAlignment); - cpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeHostPinned, devProp.textureAlignment); + gpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeDevice, static_cast(devProp.textureAlignment)); + cpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeHostPinned, static_cast(devProp.textureAlignment)); ncvAssertPrintReturn(gpuCascadeAllocator->isInitialized(), "Error creating cascade GPU allocator", NCV_CUDA_ERROR); ncvAssertPrintReturn(cpuCascadeAllocator->isInitialized(), "Error creating cascade CPU allocator", NCV_CUDA_ERROR); @@ -189,8 +189,8 @@ private: } // Calculate memory requirements and create real allocators - NCVMemStackAllocator gpuCounter(devProp.textureAlignment); - NCVMemStackAllocator cpuCounter(devProp.textureAlignment); + NCVMemStackAllocator gpuCounter(static_cast(devProp.textureAlignment)); + NCVMemStackAllocator cpuCounter(static_cast(devProp.textureAlignment)); ncvAssertPrintReturn(gpuCounter.isInitialized(), "Error creating GPU memory counter", NCV_CUDA_ERROR); ncvAssertPrintReturn(cpuCounter.isInitialized(), "Error creating CPU memory counter", NCV_CUDA_ERROR); @@ -214,8 +214,8 @@ private: ncvAssertReturnNcvStat(ncvStat); ncvAssertCUDAReturn(cudaStreamSynchronize(0), NCV_CUDA_ERROR); - gpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeDevice, gpuCounter.maxSize(), devProp.textureAlignment); - cpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeHostPinned, cpuCounter.maxSize(), devProp.textureAlignment); + gpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeDevice, gpuCounter.maxSize(), static_cast(devProp.textureAlignment)); + cpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeHostPinned, cpuCounter.maxSize(), static_cast(devProp.textureAlignment)); ncvAssertPrintReturn(gpuAllocator->isInitialized(), "Error creating GPU memory allocator", NCV_CUDA_ERROR); ncvAssertPrintReturn(cpuAllocator->isInitialized(), "Error creating CPU memory allocator", NCV_CUDA_ERROR); @@ -372,7 +372,7 @@ NCVStatus loadFromXML(const std::string &filename, for(int s = 0; s < stagesCound; ++s) // by stages { HaarStage64 curStage; - curStage.setStartClassifierRootNodeOffset(haarClassifierNodes.size()); + curStage.setStartClassifierRootNodeOffset(static_cast(haarClassifierNodes.size())); curStage.setStageThreshold(oldCascade->stage_classifier[s].threshold); @@ -452,7 +452,7 @@ NCVStatus loadFromXML(const std::string &filename, HaarFeatureDescriptor32 tmpFeatureDesc; ncvStat = tmpFeatureDesc.create(haar.bNeedsTiltedII, bIsLeftNodeLeaf, bIsRightNodeLeaf, - featureId, haarFeatures.size() - featureId); + featureId, static_cast(haarFeatures.size()) - featureId); ncvAssertReturn(NCV_SUCCESS == ncvStat, ncvStat); curNode.setFeatureDesc(tmpFeatureDesc); @@ -478,13 +478,13 @@ NCVStatus loadFromXML(const std::string &filename, } //fill in cascade stats - haar.NumStages = haarStages.size(); - haar.NumClassifierRootNodes = haarClassifierNodes.size(); - haar.NumClassifierTotalNodes = haar.NumClassifierRootNodes + h_TmpClassifierNotRootNodes.size(); - haar.NumFeatures = haarFeatures.size(); + haar.NumStages = static_cast(haarStages.size()); + haar.NumClassifierRootNodes = static_cast(haarClassifierNodes.size()); + haar.NumClassifierTotalNodes = static_cast(haar.NumClassifierRootNodes + h_TmpClassifierNotRootNodes.size()); + haar.NumFeatures = static_cast(haarFeatures.size()); //merge root and leaf nodes in one classifiers array - Ncv32u offsetRoot = haarClassifierNodes.size(); + Ncv32u offsetRoot = static_cast(haarClassifierNodes.size()); for (Ncv32u i=0; i::Load(curMask.ptr(queryIdx), trainIdx, val), (val != 0)); } - private: - PtrStep* maskCollection; + const PtrStep* maskCollection; PtrStep curMask; }; class WithOutMask { public: - __device__ __forceinline__ void nextMask() + __device__ __forceinline__ void nextMask() const { } __device__ __forceinline__ bool operator()(int queryIdx, int trainIdx) const @@ -128,9 +124,8 @@ namespace cv { namespace gpu { namespace bfmatcher /////////////////////////////////////////////////////////////////////////////// // Distance - template class L1Dist + template struct L1Dist { - public: typedef int ResultType; typedef int ValueType; @@ -151,12 +146,10 @@ namespace cv { namespace gpu { namespace bfmatcher return mySum; } - private: int mySum; }; - template <> class L1Dist + template <> struct L1Dist { - public: typedef float ResultType; typedef float ValueType; @@ -177,13 +170,11 @@ namespace cv { namespace gpu { namespace bfmatcher return mySum; } - private: float mySum; }; - class L2Dist + struct L2Dist { - public: typedef float ResultType; typedef float ValueType; @@ -205,13 +196,11 @@ namespace cv { namespace gpu { namespace bfmatcher return sqrtf(mySum); } - private: float mySum; }; - class HammingDist + struct HammingDist { - public: typedef int ResultType; typedef int ValueType; @@ -232,7 +221,6 @@ namespace cv { namespace gpu { namespace bfmatcher return mySum; } - private: int mySum; }; @@ -425,10 +413,8 @@ namespace cv { namespace gpu { namespace bfmatcher /////////////////////////////////////////////////////////////////////////////// // ReduceDescCalculator - template - class ReduceDescCalculatorSimple + template struct ReduceDescCalculatorSimple { - public: __device__ __forceinline__ void prepare(const T* queryDescs_, int, void*) { queryDescs = queryDescs_; @@ -440,14 +426,12 @@ namespace cv { namespace gpu { namespace bfmatcher reduceDescDiff(queryDescs, trainDescs, desc_len, dist, sdiff_row); } - private: const T* queryDescs; }; template - class ReduceDescCalculatorCached + struct ReduceDescCalculatorCached { - public: __device__ __forceinline__ void prepare(const T* queryDescs, int desc_len, U* smem) { loadDescsVals(queryDescs, desc_len, queryVals, smem); @@ -459,7 +443,6 @@ namespace cv { namespace gpu { namespace bfmatcher reduceDescDiffCached(queryVals, trainDescs, desc_len, dist, sdiff_row); } - private: U queryVals[MAX_DESCRIPTORS_LEN / BLOCK_DIM_X]; }; @@ -497,10 +480,8 @@ namespace cv { namespace gpu { namespace bfmatcher /////////////////////////////////////////////////////////////////////////////// // Train collection loop strategy - template - class SingleTrain + template struct SingleTrain { - public: explicit SingleTrain(const DevMem2D_& trainDescs_) : trainDescs(trainDescs_) { } @@ -517,14 +498,11 @@ namespace cv { namespace gpu { namespace bfmatcher return trainDescs.cols; } - private: - DevMem2D_ trainDescs; + const DevMem2D_ trainDescs; }; - template - class TrainCollection + template struct TrainCollection { - public: TrainCollection(const DevMem2D_* trainCollection_, int nImg_, int desclen_) : trainCollection(trainCollection_), nImg(nImg_), desclen(desclen_) { @@ -536,7 +514,7 @@ namespace cv { namespace gpu { namespace bfmatcher { for (int imgIdx = 0; imgIdx < nImg; ++imgIdx) { - DevMem2D_ trainDescs = trainCollection[imgIdx]; + const DevMem2D_ trainDescs = trainCollection[imgIdx]; m.nextMask(); matchDescs(queryIdx, imgIdx, trainDescs, m, reduceDescCalc, myMin, myBestTrainIdx, myBestImgIdx, sdiff_row); } @@ -547,7 +525,6 @@ namespace cv { namespace gpu { namespace bfmatcher return desclen; } - private: const DevMem2D_* trainCollection; int nImg; int desclen; @@ -565,7 +542,7 @@ namespace cv { namespace gpu { namespace bfmatcher int myBestTrainIdx = -1; int myBestImgIdx = -1; - typename Dist::ResultType myMin = numeric_limits_gpu::max(); + typename Dist::ResultType myMin = numeric_limits::max(); { typename Dist::ResultType* sdiff_row = smem + BLOCK_DIM_X * threadIdx.y; @@ -646,9 +623,9 @@ namespace cv { namespace gpu { namespace bfmatcher matchCached_caller<16, 16, 64, true, Dist>(queryDescs, train, mask, trainIdx, imgIdx, distance, stream); else if (queryDescs.cols < 128) matchCached_caller<16, 16, 128, false, Dist>(queryDescs, train, mask, trainIdx, imgIdx, distance, stream); - else if (queryDescs.cols == 128) + else if (queryDescs.cols == 128 && cc_12) matchCached_caller<16, 16, 128, true, Dist>(queryDescs, train, mask, trainIdx, imgIdx, distance, stream); - else if (queryDescs.cols < 256) + else if (queryDescs.cols < 256 && cc_12) matchCached_caller<16, 16, 256, false, Dist>(queryDescs, train, mask, trainIdx, imgIdx, distance, stream); else if (queryDescs.cols == 256 && cc_12) matchCached_caller<16, 16, 256, true, Dist>(queryDescs, train, mask, trainIdx, imgIdx, distance, stream); @@ -806,7 +783,7 @@ namespace cv { namespace gpu { namespace bfmatcher // Calc distance kernel template - __global__ void calcDistance(PtrStep_ queryDescs_, DevMem2D_ trainDescs_, Mask mask, PtrStepf distance) + __global__ void calcDistance(const PtrStep_ queryDescs_, const DevMem2D_ trainDescs_, const Mask mask, PtrStepf distance) { __shared__ typename Dist::ResultType sdiff[BLOCK_DIM_X * BLOCK_DIM_Y]; @@ -821,7 +798,7 @@ namespace cv { namespace gpu { namespace bfmatcher { const T* trainDescs = trainDescs_.ptr(trainIdx); - typename Dist::ResultType myDist = numeric_limits_gpu::max(); + typename Dist::ResultType myDist = numeric_limits::max(); if (mask(queryIdx, trainIdx)) { @@ -932,7 +909,7 @@ namespace cv { namespace gpu { namespace bfmatcher { const int tid = threadIdx.x; - T myMin = numeric_limits_gpu::max(); + T myMin = numeric_limits::max(); int myMinIdx = -1; for (int i = tid; i < n; i += BLOCK_SIZE) @@ -989,8 +966,7 @@ namespace cv { namespace gpu { namespace bfmatcher /////////////////////////////////////////////////////////////////////////////// // find knn match kernel - template - __global__ void findBestMatch(DevMem2Df allDist_, int i, PtrStepi trainIdx_, PtrStepf distance_) + template __global__ void findBestMatch(DevMem2Df allDist_, int i, PtrStepi trainIdx_, PtrStepf distance_) { const int SMEM_SIZE = BLOCK_SIZE > 64 ? BLOCK_SIZE : 64; __shared__ float sdist[SMEM_SIZE]; @@ -1007,10 +983,10 @@ namespace cv { namespace gpu { namespace bfmatcher if (threadIdx.x == 0) { float dist = sdist[0]; - if (dist < numeric_limits_gpu::max()) + if (dist < numeric_limits::max()) { int bestIdx = strainIdx[0]; - allDist[bestIdx] = numeric_limits_gpu::max(); + allDist[bestIdx] = numeric_limits::max(); trainIdx[i] = bestIdx; distance[i] = dist; } @@ -1130,8 +1106,8 @@ namespace cv { namespace gpu { namespace bfmatcher // Radius Match kernel template - __global__ void radiusMatch(PtrStep_ queryDescs_, DevMem2D_ trainDescs_, - float maxDistance, Mask mask, DevMem2Di trainIdx_, unsigned int* nMatches, PtrStepf distance) + __global__ void radiusMatch(const PtrStep_ queryDescs_, const DevMem2D_ trainDescs_, + float maxDistance, const Mask mask, DevMem2Di trainIdx_, unsigned int* nMatches, PtrStepf distance) { #if defined (__CUDA_ARCH__) && __CUDA_ARCH__ >= 110 diff --git a/modules/gpu/src/cuda/calib3d.cu b/modules/gpu/src/cuda/calib3d.cu index fedb3504b7..2a30393817 100644 --- a/modules/gpu/src/cuda/calib3d.cu +++ b/modules/gpu/src/cuda/calib3d.cu @@ -42,9 +42,12 @@ #include "internal_shared.hpp" #include "opencv2/gpu/device/transform.hpp" +#include "opencv2/gpu/device/functional.hpp" #define SOLVE_PNP_RANSAC_MAX_NUM_ITERS 200 +using namespace cv::gpu::device; + namespace cv { namespace gpu { namespace transform_points @@ -54,9 +57,9 @@ namespace cv { namespace gpu __constant__ float3 crot2; __constant__ float3 ctransl; - struct TransformOp + struct TransformOp : unary_function { - __device__ __forceinline__ float3 operator()(float3 p) const + __device__ __forceinline__ float3 operator()(const float3& p) const { return make_float3( crot0.x * p.x + crot0.y * p.y + crot0.z * p.z + ctransl.x, @@ -87,9 +90,9 @@ namespace cv { namespace gpu __constant__ float3 cproj0; __constant__ float3 cproj1; - struct ProjectOp + struct ProjectOp : unary_function { - __device__ __forceinline__ float2 operator()(float3 p) const + __device__ __forceinline__ float2 operator()(const float3& p) const { // Rotate and translate in 3D float3 t = make_float3( diff --git a/modules/gpu/src/cuda/canny.cu b/modules/gpu/src/cuda/canny.cu new file mode 100644 index 0000000000..19f9b384c4 --- /dev/null +++ b/modules/gpu/src/cuda/canny.cu @@ -0,0 +1,491 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include +#include "internal_shared.hpp" +#include "opencv2/gpu/device/utility.hpp" + +using namespace cv::gpu; +using namespace cv::gpu::device; + +namespace cv { namespace gpu { namespace canny +{ + __global__ void calcSobelRowPass(const PtrStep src, PtrStepi dx_buf, PtrStepi dy_buf, int rows, int cols) + { + __shared__ int smem[16][18]; + + const int j = blockIdx.x * blockDim.x + threadIdx.x; + const int i = blockIdx.y * blockDim.y + threadIdx.y; + + if (i < rows) + { + smem[threadIdx.y][threadIdx.x + 1] = src.ptr(i)[j]; + if (threadIdx.x == 0) + { + smem[threadIdx.y][0] = src.ptr(i)[max(j - 1, 0)]; + smem[threadIdx.y][17] = src.ptr(i)[min(j + 16, cols - 1)]; + } + __syncthreads(); + + if (j < cols) + { + dx_buf.ptr(i)[j] = -smem[threadIdx.y][threadIdx.x] + smem[threadIdx.y][threadIdx.x + 2]; + dy_buf.ptr(i)[j] = smem[threadIdx.y][threadIdx.x] + 2 * smem[threadIdx.y][threadIdx.x + 1] + smem[threadIdx.y][threadIdx.x + 2]; + } + } + } + + void calcSobelRowPass_gpu(PtrStep src, PtrStepi dx_buf, PtrStepi dy_buf, int rows, int cols) + { + dim3 block(16, 16, 1); + dim3 grid(divUp(cols, block.x), divUp(rows, block.y), 1); + + calcSobelRowPass<<>>(src, dx_buf, dy_buf, rows, cols); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + } + + struct L1 + { + static __device__ __forceinline__ float calc(int x, int y) + { + return abs(x) + abs(y); + } + }; + struct L2 + { + static __device__ __forceinline__ float calc(int x, int y) + { + return sqrtf(x * x + y * y); + } + }; + + template __global__ void calcMagnitude(const PtrStepi dx_buf, const PtrStepi dy_buf, + PtrStepi dx, PtrStepi dy, PtrStepf mag, int rows, int cols) + { + __shared__ int sdx[18][16]; + __shared__ int sdy[18][16]; + + const int j = blockIdx.x * blockDim.x + threadIdx.x; + const int i = blockIdx.y * blockDim.y + threadIdx.y; + + if (j < cols) + { + sdx[threadIdx.y + 1][threadIdx.x] = dx_buf.ptr(i)[j]; + sdy[threadIdx.y + 1][threadIdx.x] = dy_buf.ptr(i)[j]; + if (threadIdx.y == 0) + { + sdx[0][threadIdx.x] = dx_buf.ptr(max(i - 1, 0))[j]; + sdx[17][threadIdx.x] = dx_buf.ptr(min(i + 16, rows - 1))[j]; + + sdy[0][threadIdx.x] = dy_buf.ptr(max(i - 1, 0))[j]; + sdy[17][threadIdx.x] = dy_buf.ptr(min(i + 16, rows - 1))[j]; + } + __syncthreads(); + + if (i < rows) + { + int x = sdx[threadIdx.y][threadIdx.x] + 2 * sdx[threadIdx.y + 1][threadIdx.x] + sdx[threadIdx.y + 2][threadIdx.x]; + int y = -sdy[threadIdx.y][threadIdx.x] + sdy[threadIdx.y + 2][threadIdx.x]; + + dx.ptr(i)[j] = x; + dy.ptr(i)[j] = y; + + mag.ptr(i + 1)[j + 1] = Norm::calc(x, y); + } + } + } + + void calcMagnitude_gpu(PtrStepi dx_buf, PtrStepi dy_buf, PtrStepi dx, PtrStepi dy, PtrStepf mag, int rows, int cols, bool L2Grad) + { + dim3 block(16, 16, 1); + dim3 grid(divUp(cols, block.x), divUp(rows, block.y), 1); + + if (L2Grad) + calcMagnitude<<>>(dx_buf, dy_buf, dx, dy, mag, rows, cols); + else + calcMagnitude<<>>(dx_buf, dy_buf, dx, dy, mag, rows, cols); + + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + } + + template __global__ void calcMagnitude(PtrStepi dx, PtrStepi dy, PtrStepf mag, int rows, int cols) + { + const int j = blockIdx.x * blockDim.x + threadIdx.x; + const int i = blockIdx.y * blockDim.y + threadIdx.y; + + if (i < rows && j < cols) + mag.ptr(i + 1)[j + 1] = Norm::calc(dx.ptr(i)[j], dy.ptr(i)[j]); + } + + void calcMagnitude_gpu(PtrStepi dx, PtrStepi dy, PtrStepf mag, int rows, int cols, bool L2Grad) + { + dim3 block(16, 16, 1); + dim3 grid(divUp(cols, block.x), divUp(rows, block.y), 1); + + if (L2Grad) + calcMagnitude<<>>(dx, dy, mag, rows, cols); + else + calcMagnitude<<>>(dx, dy, mag, rows, cols); + + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + } + +////////////////////////////////////////////////////////////////////////////////////////// + +#define CANNY_SHIFT 15 +#define TG22 (int)(0.4142135623730950488016887242097*(1< low_thresh) + { + const int tg22x = x * TG22; + const int tg67x = tg22x + ((x + x) << CANNY_SHIFT); + + y <<= CANNY_SHIFT; + + if (y < tg22x) + { + if (m > smem[threadIdx.y + 1][threadIdx.x] && m >= smem[threadIdx.y + 1][threadIdx.x + 2]) + edge_type = 1 + (int)(m > high_thresh); + } + else if( y > tg67x ) + { + if (m > smem[threadIdx.y][threadIdx.x + 1] && m >= smem[threadIdx.y + 2][threadIdx.x + 1]) + edge_type = 1 + (int)(m > high_thresh); + } + else + { + if (m > smem[threadIdx.y][threadIdx.x + 1 - s] && m > smem[threadIdx.y + 2][threadIdx.x + 1 + s]) + edge_type = 1 + (int)(m > high_thresh); + } + } + + map.ptr(i + 1)[j + 1] = edge_type; + } + } + +#undef CANNY_SHIFT +#undef TG22 + + void calcMap_gpu(PtrStepi dx, PtrStepi dy, PtrStepf mag, PtrStepi map, int rows, int cols, float low_thresh, float high_thresh) + { + dim3 block(16, 16, 1); + dim3 grid(divUp(cols, block.x), divUp(rows, block.y), 1); + + calcMap<<>>(dx, dy, mag, map, rows, cols, low_thresh, high_thresh); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + } + +////////////////////////////////////////////////////////////////////////////////////////// + + __device__ unsigned int counter = 0; + + __global__ void edgesHysteresisLocal(PtrStepi map, ushort2* st, int rows, int cols) + { + #if __CUDA_ARCH__ >= 120 + + __shared__ int smem[18][18]; + + const int j = blockIdx.x * 16 + threadIdx.x; + const int i = blockIdx.y * 16 + threadIdx.y; + + const int tid = threadIdx.y * 16 + threadIdx.x; + const int lx = tid % 18; + const int ly = tid / 18; + + if (ly < 14) + smem[ly][lx] = map.ptr(blockIdx.y * 16 + ly)[blockIdx.x * 16 + lx]; + + if (ly < 4 && blockIdx.y * 16 + ly + 14 <= rows && blockIdx.x * 16 + lx <= cols) + smem[ly + 14][lx] = map.ptr(blockIdx.y * 16 + ly + 14)[blockIdx.x * 16 + lx]; + + __syncthreads(); + + if (i < rows && j < cols) + { + int n; + + #pragma unroll + for (int k = 0; k < 16; ++k) + { + n = 0; + + if (smem[threadIdx.y + 1][threadIdx.x + 1] == 1) + { + n += smem[threadIdx.y ][threadIdx.x ] == 2; + n += smem[threadIdx.y ][threadIdx.x + 1] == 2; + n += smem[threadIdx.y ][threadIdx.x + 2] == 2; + + n += smem[threadIdx.y + 1][threadIdx.x ] == 2; + n += smem[threadIdx.y + 1][threadIdx.x + 2] == 2; + + n += smem[threadIdx.y + 2][threadIdx.x ] == 2; + n += smem[threadIdx.y + 2][threadIdx.x + 1] == 2; + n += smem[threadIdx.y + 2][threadIdx.x + 2] == 2; + } + + if (n > 0) + smem[threadIdx.y + 1][threadIdx.x + 1] = 2; + } + + const int e = smem[threadIdx.y + 1][threadIdx.x + 1]; + + map.ptr(i + 1)[j + 1] = e; + + n = 0; + + if (e == 2) + { + n += smem[threadIdx.y ][threadIdx.x ] == 1; + n += smem[threadIdx.y ][threadIdx.x + 1] == 1; + n += smem[threadIdx.y ][threadIdx.x + 2] == 1; + + n += smem[threadIdx.y + 1][threadIdx.x ] == 1; + n += smem[threadIdx.y + 1][threadIdx.x + 2] == 1; + + n += smem[threadIdx.y + 2][threadIdx.x ] == 1; + n += smem[threadIdx.y + 2][threadIdx.x + 1] == 1; + n += smem[threadIdx.y + 2][threadIdx.x + 2] == 1; + } + + if (n > 0) + { + const unsigned int ind = atomicInc(&counter, (unsigned int)(-1)); + st[ind] = make_ushort2(j + 1, i + 1); + } + } + + #endif + } + + void edgesHysteresisLocal_gpu(PtrStepi map, ushort2* st1, int rows, int cols) + { + dim3 block(16, 16, 1); + dim3 grid(divUp(cols, block.x), divUp(rows, block.y), 1); + + edgesHysteresisLocal<<>>(map, st1, rows, cols); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + } + + __constant__ int c_dx[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; + __constant__ int c_dy[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; + + __global__ void edgesHysteresisGlobal(PtrStepi map, ushort2* st1, ushort2* st2, int rows, int cols, int count) + { + #if __CUDA_ARCH__ >= 120 + + const int stack_size = 512; + + __shared__ unsigned int s_counter; + __shared__ unsigned int s_ind; + __shared__ ushort2 s_st[stack_size]; + + if (threadIdx.x == 0) + s_counter = 0; + __syncthreads(); + + int ind = blockIdx.y * gridDim.x + blockIdx.x; + + if (ind < count) + { + ushort2 pos = st1[ind]; + + if (pos.x > 0 && pos.x <= cols && pos.y > 0 && pos.y <= rows) + { + if (threadIdx.x < 8) + { + pos.x += c_dx[threadIdx.x]; + pos.y += c_dy[threadIdx.x]; + + if (map.ptr(pos.y)[pos.x] == 1) + { + map.ptr(pos.y)[pos.x] = 2; + + ind = atomicInc(&s_counter, (unsigned int)(-1)); + + s_st[ind] = pos; + } + } + __syncthreads(); + + while (s_counter > 0 && s_counter <= stack_size - blockDim.x) + { + const int subTaskIdx = threadIdx.x >> 3; + const int portion = min(s_counter, blockDim.x >> 3); + + pos.x = pos.y = 0; + + if (subTaskIdx < portion) + pos = s_st[s_counter - 1 - subTaskIdx]; + __syncthreads(); + + if (threadIdx.x == 0) + s_counter -= portion; + __syncthreads(); + + if (pos.x > 0 && pos.x <= cols && pos.y > 0 && pos.y <= rows) + { + pos.x += c_dx[threadIdx.x & 7]; + pos.y += c_dy[threadIdx.x & 7]; + + if (map.ptr(pos.y)[pos.x] == 1) + { + map.ptr(pos.y)[pos.x] = 2; + + ind = atomicInc(&s_counter, (unsigned int)(-1)); + + s_st[ind] = pos; + } + } + __syncthreads(); + } + + if (s_counter > 0) + { + if (threadIdx.x == 0) + { + ind = atomicAdd(&counter, s_counter); + s_ind = ind - s_counter; + } + __syncthreads(); + + ind = s_ind; + + for (int i = threadIdx.x; i < s_counter; i += blockDim.x) + { + st2[ind + i] = s_st[i]; + } + } + } + } + + #endif + } + + void edgesHysteresisGlobal_gpu(PtrStepi map, ushort2* st1, ushort2* st2, int rows, int cols) + { + void* counter_ptr; + cudaSafeCall( cudaGetSymbolAddress(&counter_ptr, "cv::gpu::canny::counter") ); + + unsigned int count; + cudaSafeCall( cudaMemcpy(&count, counter_ptr, sizeof(unsigned int), cudaMemcpyDeviceToHost) ); + + while (count > 0) + { + cudaSafeCall( cudaMemset(counter_ptr, 0, sizeof(unsigned int)) ); + + dim3 block(128, 1, 1); + dim3 grid(min(count, 65535u), divUp(count, 65535), 1); + edgesHysteresisGlobal<<>>(map, st1, st2, rows, cols, count); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + + cudaSafeCall( cudaMemcpy(&count, counter_ptr, sizeof(unsigned int), cudaMemcpyDeviceToHost) ); + + std::swap(st1, st2); + } + } + + __global__ void getEdges(PtrStepi map, PtrStep dst, int rows, int cols) + { + const int j = blockIdx.x * 16 + threadIdx.x; + const int i = blockIdx.y * 16 + threadIdx.y; + + if (i < rows && j < cols) + dst.ptr(i)[j] = (uchar)(-(map.ptr(i + 1)[j + 1] >> 1)); + } + + void getEdges_gpu(PtrStepi map, PtrStep dst, int rows, int cols) + { + dim3 block(16, 16, 1); + dim3 grid(divUp(cols, block.x), divUp(rows, block.y), 1); + + getEdges<<>>(map, dst, rows, cols); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall(cudaThreadSynchronize()); + } +}}} diff --git a/modules/gpu/src/cuda/color.cu b/modules/gpu/src/cuda/color.cu index 9fcd520619..2755fffba8 100644 --- a/modules/gpu/src/cuda/color.cu +++ b/modules/gpu/src/cuda/color.cu @@ -41,1305 +41,168 @@ //M*/ #include "internal_shared.hpp" -#include "opencv2/gpu/device/saturate_cast.hpp" -#include "opencv2/gpu/device/vecmath.hpp" -#include "opencv2/gpu/device/limits_gpu.hpp" #include "opencv2/gpu/device/transform.hpp" +#include "opencv2/gpu/device/color.hpp" using namespace cv::gpu; using namespace cv::gpu::device; -#ifndef CV_DESCALE -#define CV_DESCALE(x, n) (((x) + (1 << ((n)-1))) >> (n)) -#endif - namespace cv { namespace gpu { namespace color { - template struct ColorChannel - { - typedef float worktype_f; - static __device__ __forceinline__ T max() { return numeric_limits_gpu::max(); } - static __device__ __forceinline__ T half() { return (T)(max()/2 + 1); } - }; - template<> struct ColorChannel - { - typedef float worktype_f; - static __device__ __forceinline__ float max() { return 1.f; } - static __device__ __forceinline__ float half() { return 0.5f; } - }; - - template - __device__ __forceinline__ void setAlpha(typename TypeVec::vec_t& vec, T val) - { - } - template - __device__ __forceinline__ void setAlpha(typename TypeVec::vec_t& vec, T val) - { - vec.w = val; - } - template - __device__ __forceinline__ T getAlpha(const typename TypeVec::vec_t& vec) - { - return ColorChannel::max(); - } - template - __device__ __forceinline__ T getAlpha(const typename TypeVec::vec_t& vec) - { - return vec.w; - } - - template - void callConvert(const DevMem2D& src, const DevMem2D& dst, const Cvt& cvt, cudaStream_t stream) - { - typedef typename Cvt::src_t src_t; - typedef typename Cvt::dst_t dst_t; - - transform((DevMem2D_)src, (DevMem2D_)dst, cvt, stream); - } - -////////////////// Various 3/4-channel to 3/4-channel RGB transformations ///////////////// - - template - struct RGB2RGB - { - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - explicit RGB2RGB(int bidx) : bidx(bidx) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - - dst.x = (&src.x)[bidx]; - dst.y = src.y; - dst.z = (&src.x)[bidx ^ 2]; - setAlpha(dst, getAlpha(src)); - - return dst; + #define OPENCV_GPU_IMPLEMENT_CVTCOLOR(name, traits) \ + void name(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream) \ + { \ + traits::functor_type functor = traits::create_functor(); \ + typedef typename traits::functor_type::argument_type src_t; \ + typedef typename traits::functor_type::result_type dst_t; \ + transform((DevMem2D_)src, (DevMem2D_)dst, functor, stream); \ } - private: - int bidx; - }; - - template - void RGB2RGB_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - RGB2RGB cvt(bidx); - callConvert(src, dst, cvt, stream); - } - - void RGB2RGB_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, cudaStream_t stream) - { - typedef void (*RGB2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - static const RGB2RGB_caller_t RGB2RGB_callers[2][2] = - { - {RGB2RGB_caller, RGB2RGB_caller}, - {RGB2RGB_caller, RGB2RGB_caller} - }; - - RGB2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, stream); - } - - void RGB2RGB_gpu_16u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, cudaStream_t stream) - { - typedef void (*RGB2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - static const RGB2RGB_caller_t RGB2RGB_callers[2][2] = - { - {RGB2RGB_caller, RGB2RGB_caller}, - {RGB2RGB_caller, RGB2RGB_caller} - }; - - RGB2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, stream); - } - - void RGB2RGB_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, cudaStream_t stream) - { - typedef void (*RGB2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - static const RGB2RGB_caller_t RGB2RGB_callers[2][2] = - { - {RGB2RGB_caller, RGB2RGB_caller}, - {RGB2RGB_caller, RGB2RGB_caller} - }; - - RGB2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, stream); - } - -/////////// Transforming 16-bit (565 or 555) RGB to/from 24/32-bit (888[8]) RGB ////////// - - template struct RGB5x52RGBConverter; - template <> struct RGB5x52RGBConverter<5> - { - template - static __device__ __forceinline__ void cvt(uint src, D& dst, int bidx) - { - (&dst.x)[bidx] = (uchar)(src << 3); - dst.y = (uchar)((src >> 2) & ~7); - (&dst.x)[bidx ^ 2] = (uchar)((src >> 7) & ~7); - setAlpha(dst, (uchar)(src & 0x8000 ? 255 : 0)); - } - }; - template <> struct RGB5x52RGBConverter<6> - { - template - static __device__ __forceinline__ void cvt(uint src, D& dst, int bidx) - { - (&dst.x)[bidx] = (uchar)(src << 3); - dst.y = (uchar)((src >> 3) & ~3); - (&dst.x)[bidx ^ 2] = (uchar)((src >> 8) & ~7); - setAlpha(dst, (uchar)(255)); - } - }; - - template struct RGB5x52RGB - { - typedef ushort src_t; - typedef typename TypeVec::vec_t dst_t; - - explicit RGB5x52RGB(int bidx) : bidx(bidx) {} - - __device__ __forceinline__ dst_t operator()(ushort src) const - { - dst_t dst; - RGB5x52RGBConverter::cvt((uint)src, dst, bidx); - return dst; - } - - private: - int bidx; - }; - - template struct RGB2RGB5x5Converter; - template<> struct RGB2RGB5x5Converter<6> - { - template - static __device__ __forceinline__ ushort cvt(const T& src, int bidx) - { - return (ushort)(((&src.x)[bidx] >> 3) | ((src.y & ~3) << 3) | (((&src.x)[bidx^2] & ~7) << 8)); - } - }; - template<> struct RGB2RGB5x5Converter<5> - { - static __device__ __forceinline__ ushort cvt(const uchar3& src, int bidx) - { - return (ushort)(((&src.x)[bidx] >> 3) | ((src.y & ~7) << 2) | (((&src.x)[bidx^2] & ~7) << 7)); - } - static __device__ __forceinline__ ushort cvt(const uchar4& src, int bidx) - { - return (ushort)(((&src.x)[bidx] >> 3) | ((src.y & ~7) << 2) | (((&src.x)[bidx^2] & ~7) << 7) | (src.w ? 0x8000 : 0)); - } - }; - - template struct RGB2RGB5x5 - { - typedef typename TypeVec::vec_t src_t; - typedef ushort dst_t; - - explicit RGB2RGB5x5(int bidx) : bidx(bidx) {} - - __device__ __forceinline__ ushort operator()(const src_t& src) - { - return RGB2RGB5x5Converter::cvt(src, bidx); - } - - private: - int bidx; - }; - - template - void RGB5x52RGB_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - RGB5x52RGB cvt(bidx); - callConvert(src, dst, cvt, stream); - } - - void RGB5x52RGB_gpu(const DevMem2D& src, int green_bits, const DevMem2D& dst, int dstcn, int bidx, cudaStream_t stream) - { - typedef void (*RGB5x52RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - static const RGB5x52RGB_caller_t RGB5x52RGB_callers[2][2] = - { - {RGB5x52RGB_caller<5, 3>, RGB5x52RGB_caller<5, 4>}, - {RGB5x52RGB_caller<6, 3>, RGB5x52RGB_caller<6, 4>} - }; - - RGB5x52RGB_callers[green_bits - 5][dstcn - 3](src, dst, bidx, stream); - } - - template - void RGB2RGB5x5_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - RGB2RGB5x5 cvt(bidx); - callConvert(src, dst, cvt, stream); - } - - void RGB2RGB5x5_gpu(const DevMem2D& src, int srccn, const DevMem2D& dst, int green_bits, int bidx, cudaStream_t stream) - { - typedef void (*RGB2RGB5x5_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - static const RGB2RGB5x5_caller_t RGB2RGB5x5_callers[2][2] = - { - {RGB2RGB5x5_caller<3, 5>, RGB2RGB5x5_caller<3, 6>}, - {RGB2RGB5x5_caller<4, 5>, RGB2RGB5x5_caller<4, 6>} - }; - - RGB2RGB5x5_callers[srccn - 3][green_bits - 5](src, dst, bidx, stream); - } - -///////////////////////////////// Grayscale to Color //////////////////////////////// - - template struct Gray2RGB - { - typedef T src_t; - typedef typename TypeVec::vec_t dst_t; - - __device__ __forceinline__ dst_t operator()(const T& src) const - { - dst_t dst; - - dst.z = dst.y = dst.x = src; - setAlpha(dst, ColorChannel::max()); - - return dst; - } - }; - - template struct Gray2RGB5x5Converter; - template<> struct Gray2RGB5x5Converter<6> - { - static __device__ __forceinline__ ushort cvt(uint t) - { - return (ushort)((t >> 3) | ((t & ~3) << 3) | ((t & ~7) << 8)); - } - }; - template<> struct Gray2RGB5x5Converter<5> - { - static __device__ __forceinline__ ushort cvt(uint t) - { - t >>= 3; - return (ushort)(t | (t << 5) | (t << 10)); - } - }; - - template struct Gray2RGB5x5 - { - typedef uchar src_t; - typedef ushort dst_t; - - __device__ __forceinline__ ushort operator()(uchar src) const - { - return Gray2RGB5x5Converter::cvt((uint)src); - } - }; - - template - void Gray2RGB_caller(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream) - { - Gray2RGB cvt; - callConvert(src, dst, cvt, stream); - } - - void Gray2RGB_gpu_8u(const DevMem2D& src, const DevMem2D& dst, int dstcn, cudaStream_t stream) - { - typedef void (*Gray2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream); - static const Gray2RGB_caller_t Gray2RGB_callers[] = {Gray2RGB_caller, Gray2RGB_caller}; - - Gray2RGB_callers[dstcn - 3](src, dst, stream); - } - - void Gray2RGB_gpu_16u(const DevMem2D& src, const DevMem2D& dst, int dstcn, cudaStream_t stream) - { - typedef void (*Gray2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream); - static const Gray2RGB_caller_t Gray2RGB_callers[] = {Gray2RGB_caller, Gray2RGB_caller}; - - Gray2RGB_callers[dstcn - 3](src, dst, stream); - } - - void Gray2RGB_gpu_32f(const DevMem2D& src, const DevMem2D& dst, int dstcn, cudaStream_t stream) - { - typedef void (*Gray2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream); - static const Gray2RGB_caller_t Gray2RGB_callers[] = {Gray2RGB_caller, Gray2RGB_caller}; - - Gray2RGB_callers[dstcn - 3](src, dst, stream); - } - - template - void Gray2RGB5x5_caller(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream) - { - Gray2RGB5x5 cvt; - callConvert(src, dst, cvt, stream); - } - - void Gray2RGB5x5_gpu(const DevMem2D& src, const DevMem2D& dst, int green_bits, cudaStream_t stream) - { - typedef void (*Gray2RGB5x5_caller_t)(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream); - static const Gray2RGB5x5_caller_t Gray2RGB5x5_callers[2] = - { - Gray2RGB5x5_caller<5>, Gray2RGB5x5_caller<6> - }; - - Gray2RGB5x5_callers[green_bits - 5](src, dst, stream); - } - -///////////////////////////////// Color to Grayscale //////////////////////////////// - - #undef R2Y - #undef G2Y - #undef B2Y - - enum - { - yuv_shift = 14, - xyz_shift = 12, - R2Y = 4899, - G2Y = 9617, - B2Y = 1868, - BLOCK_SIZE = 256 - }; - - template struct RGB5x52GrayConverter; - template<> struct RGB5x52GrayConverter<6> - { - static __device__ __forceinline__ uchar cvt(uint t) - { - return (uchar)CV_DESCALE(((t << 3) & 0xf8) * B2Y + ((t >> 3) & 0xfc) * G2Y + ((t >> 8) & 0xf8) * R2Y, yuv_shift); - } - }; - template<> struct RGB5x52GrayConverter<5> - { - static __device__ __forceinline__ uchar cvt(uint t) - { - return (uchar)CV_DESCALE(((t << 3) & 0xf8) * B2Y + ((t >> 2) & 0xf8) * G2Y + ((t >> 7) & 0xf8) * R2Y, yuv_shift); - } - }; - - template struct RGB5x52Gray - { - typedef ushort src_t; - typedef uchar dst_t; - - __device__ __forceinline__ uchar operator()(ushort src) const - { - return RGB5x52GrayConverter::cvt((uint)src); - } - }; - - template - __device__ __forceinline__ T RGB2GrayConvert(const T* src, int bidx) - { - return (T)CV_DESCALE((unsigned)(src[bidx] * B2Y + src[1] * G2Y + src[bidx^2] * R2Y), yuv_shift); - } - __device__ __forceinline__ float RGB2GrayConvert(const float* src, int bidx) - { - const float cr = 0.299f; - const float cg = 0.587f; - const float cb = 0.114f; - - return src[bidx] * cb + src[1] * cg + src[bidx^2] * cr; - } - - template struct RGB2Gray - { - typedef typename TypeVec::vec_t src_t; - typedef T dst_t; - - explicit RGB2Gray(int bidx) : bidx(bidx) {} - - __device__ __forceinline__ T operator()(const src_t& src) - { - return RGB2GrayConvert(&src.x, bidx); - } - - private: - int bidx; - }; - - template - void RGB2Gray_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - RGB2Gray cvt(bidx); - callConvert(src, dst, cvt, stream); - } - - void RGB2Gray_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - typedef void (*RGB2Gray_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - RGB2Gray_caller_t RGB2Gray_callers[] = {RGB2Gray_caller, RGB2Gray_caller}; - - RGB2Gray_callers[srccn - 3](src, dst, bidx, stream); - } - - void RGB2Gray_gpu_16u(const DevMem2D& src, int srccn, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - typedef void (*RGB2Gray_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - RGB2Gray_caller_t RGB2Gray_callers[] = {RGB2Gray_caller, RGB2Gray_caller}; - - RGB2Gray_callers[srccn - 3](src, dst, bidx, stream); - } - - void RGB2Gray_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int bidx, cudaStream_t stream) - { - typedef void (*RGB2Gray_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, cudaStream_t stream); - RGB2Gray_caller_t RGB2Gray_callers[] = {RGB2Gray_caller, RGB2Gray_caller}; - - RGB2Gray_callers[srccn - 3](src, dst, bidx, stream); - } - - template - void RGB5x52Gray_caller(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream) - { - RGB5x52Gray cvt; - callConvert(src, dst, cvt, stream); - } - - void RGB5x52Gray_gpu(const DevMem2D& src, int green_bits, const DevMem2D& dst, cudaStream_t stream) - { - typedef void (*RGB5x52Gray_caller_t)(const DevMem2D& src, const DevMem2D& dst, cudaStream_t stream); - static const RGB5x52Gray_caller_t RGB5x52Gray_callers[2] = - { - RGB5x52Gray_caller<5>, RGB5x52Gray_caller<6> - }; - - RGB5x52Gray_callers[green_bits - 5](src, dst, stream); - } - -///////////////////////////////////// RGB <-> YCrCb ////////////////////////////////////// - - __constant__ int cYCrCbCoeffs_i[5]; - __constant__ float cYCrCbCoeffs_f[5]; - - template - __device__ __forceinline__ void RGB2YCrCbConvert(const T* src, D& dst, int bidx) - { - const int delta = ColorChannel::half() * (1 << yuv_shift); - - const int Y = CV_DESCALE(src[0] * cYCrCbCoeffs_i[0] + src[1] * cYCrCbCoeffs_i[1] + src[2] * cYCrCbCoeffs_i[2], yuv_shift); - const int Cr = CV_DESCALE((src[bidx^2] - Y) * cYCrCbCoeffs_i[3] + delta, yuv_shift); - const int Cb = CV_DESCALE((src[bidx] - Y) * cYCrCbCoeffs_i[4] + delta, yuv_shift); - - dst.x = saturate_cast(Y); - dst.y = saturate_cast(Cr); - dst.z = saturate_cast(Cb); - } - template - static __device__ __forceinline__ void RGB2YCrCbConvert(const float* src, D& dst, int bidx) - { - dst.x = src[0] * cYCrCbCoeffs_f[0] + src[1] * cYCrCbCoeffs_f[1] + src[2] * cYCrCbCoeffs_f[2]; - dst.y = (src[bidx^2] - dst.x) * cYCrCbCoeffs_f[3] + ColorChannel::half(); - dst.z = (src[bidx] - dst.x) * cYCrCbCoeffs_f[4] + ColorChannel::half(); - } - - template struct RGB2YCrCbBase - { - typedef int coeff_t; - - explicit RGB2YCrCbBase(const coeff_t coeffs[5]) - { - cudaSafeCall( cudaMemcpyToSymbol(cYCrCbCoeffs_i, coeffs, 5 * sizeof(int)) ); - } - }; - template<> struct RGB2YCrCbBase - { - typedef float coeff_t; - - explicit RGB2YCrCbBase(const coeff_t coeffs[5]) - { - cudaSafeCall( cudaMemcpyToSymbol(cYCrCbCoeffs_f, coeffs, 5 * sizeof(float)) ); - } - }; - template struct RGB2YCrCb : RGB2YCrCbBase - { - typedef typename RGB2YCrCbBase::coeff_t coeff_t; - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - RGB2YCrCb(int bidx, const coeff_t coeffs[5]) : RGB2YCrCbBase(coeffs), bidx(bidx) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - RGB2YCrCbConvert(&src.x, dst, bidx); - return dst; - } - - private: - int bidx; - }; - - template - __device__ __forceinline__ void YCrCb2RGBConvert(const T& src, D* dst, int bidx) - { - const int b = src.x + CV_DESCALE((src.z - ColorChannel::half()) * cYCrCbCoeffs_i[3], yuv_shift); - const int g = src.x + CV_DESCALE((src.z - ColorChannel::half()) * cYCrCbCoeffs_i[2] + (src.y - ColorChannel::half()) * cYCrCbCoeffs_i[1], yuv_shift); - const int r = src.x + CV_DESCALE((src.y - ColorChannel::half()) * cYCrCbCoeffs_i[0], yuv_shift); - - dst[bidx] = saturate_cast(b); - dst[1] = saturate_cast(g); - dst[bidx^2] = saturate_cast(r); - } - template - __device__ __forceinline__ void YCrCb2RGBConvert(const T& src, float* dst, int bidx) - { - dst[bidx] = src.x + (src.z - ColorChannel::half()) * cYCrCbCoeffs_f[3]; - dst[1] = src.x + (src.z - ColorChannel::half()) * cYCrCbCoeffs_f[2] + (src.y - ColorChannel::half()) * cYCrCbCoeffs_f[1]; - dst[bidx^2] = src.x + (src.y - ColorChannel::half()) * cYCrCbCoeffs_f[0]; - } - - template struct YCrCb2RGBBase - { - typedef int coeff_t; - - explicit YCrCb2RGBBase(const coeff_t coeffs[4]) - { - cudaSafeCall( cudaMemcpyToSymbol(cYCrCbCoeffs_i, coeffs, 4 * sizeof(int)) ); - } - }; - template<> struct YCrCb2RGBBase - { - typedef float coeff_t; - - explicit YCrCb2RGBBase(const coeff_t coeffs[4]) - { - cudaSafeCall( cudaMemcpyToSymbol(cYCrCbCoeffs_f, coeffs, 4 * sizeof(float)) ); - } - }; - template struct YCrCb2RGB : YCrCb2RGBBase - { - typedef typename YCrCb2RGBBase::coeff_t coeff_t; - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - YCrCb2RGB(int bidx, const coeff_t coeffs[4]) : YCrCb2RGBBase(coeffs), bidx(bidx) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - - YCrCb2RGBConvert(src, &dst.x, bidx); - setAlpha(dst, ColorChannel::max()); - - return dst; - } - - private: - int bidx; - }; - - template - void RGB2YCrCb_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef typename RGB2YCrCb::coeff_t coeff_t; - RGB2YCrCb cvt(bidx, (const coeff_t*)coeffs); - callConvert(src, dst, cvt, stream); - } - - void RGB2YCrCb_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef void (*RGB2YCrCb_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream); - static const RGB2YCrCb_caller_t RGB2YCrCb_callers[2][2] = - { - {RGB2YCrCb_caller, RGB2YCrCb_caller}, - {RGB2YCrCb_caller, RGB2YCrCb_caller} - }; - - RGB2YCrCb_callers[srccn-3][dstcn-3](src, dst, bidx, coeffs, stream); - } - - void RGB2YCrCb_gpu_16u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef void (*RGB2YCrCb_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream); - static const RGB2YCrCb_caller_t RGB2YCrCb_callers[2][2] = - { - {RGB2YCrCb_caller, RGB2YCrCb_caller}, - {RGB2YCrCb_caller, RGB2YCrCb_caller} - }; - - RGB2YCrCb_callers[srccn-3][dstcn-3](src, dst, bidx, coeffs, stream); - } - - void RGB2YCrCb_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef void (*RGB2YCrCb_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream); - static const RGB2YCrCb_caller_t RGB2YCrCb_callers[2][2] = - { - {RGB2YCrCb_caller, RGB2YCrCb_caller}, - {RGB2YCrCb_caller, RGB2YCrCb_caller} - }; - - RGB2YCrCb_callers[srccn-3][dstcn-3](src, dst, bidx, coeffs, stream); - } - - template - void YCrCb2RGB_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef typename YCrCb2RGB::coeff_t coeff_t; - YCrCb2RGB cvt(bidx, (const coeff_t*)coeffs); - callConvert(src, dst, cvt, stream); - } - - void YCrCb2RGB_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef void (*YCrCb2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream); - static const YCrCb2RGB_caller_t YCrCb2RGB_callers[2][2] = - { - {YCrCb2RGB_caller, YCrCb2RGB_caller}, - {YCrCb2RGB_caller, YCrCb2RGB_caller} - }; - - YCrCb2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, coeffs, stream); - } - - void YCrCb2RGB_gpu_16u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef void (*YCrCb2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream); - static const YCrCb2RGB_caller_t YCrCb2RGB_callers[2][2] = - { - {YCrCb2RGB_caller, YCrCb2RGB_caller}, - {YCrCb2RGB_caller, YCrCb2RGB_caller} - }; - - YCrCb2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, coeffs, stream); - } - - void YCrCb2RGB_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, const void* coeffs, cudaStream_t stream) - { - typedef void (*YCrCb2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, const void* coeffs, cudaStream_t stream); - static const YCrCb2RGB_caller_t YCrCb2RGB_callers[2][2] = - { - {YCrCb2RGB_caller, YCrCb2RGB_caller}, - {YCrCb2RGB_caller, YCrCb2RGB_caller} - }; - - YCrCb2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, coeffs, stream); - } - -////////////////////////////////////// RGB <-> XYZ /////////////////////////////////////// - - __constant__ int cXYZ_D65i[9]; - __constant__ float cXYZ_D65f[9]; - - template - __device__ __forceinline__ void RGB2XYZConvert(const T* src, D& dst) - { - dst.x = saturate_cast(CV_DESCALE(src[0] * cXYZ_D65i[0] + src[1] * cXYZ_D65i[1] + src[2] * cXYZ_D65i[2], xyz_shift)); - dst.y = saturate_cast(CV_DESCALE(src[0] * cXYZ_D65i[3] + src[1] * cXYZ_D65i[4] + src[2] * cXYZ_D65i[5], xyz_shift)); - dst.z = saturate_cast(CV_DESCALE(src[0] * cXYZ_D65i[6] + src[1] * cXYZ_D65i[7] + src[2] * cXYZ_D65i[8], xyz_shift)); - } - template - __device__ __forceinline__ void RGB2XYZConvert(const float* src, D& dst) - { - dst.x = src[0] * cXYZ_D65f[0] + src[1] * cXYZ_D65f[1] + src[2] * cXYZ_D65f[2]; - dst.y = src[0] * cXYZ_D65f[3] + src[1] * cXYZ_D65f[4] + src[2] * cXYZ_D65f[5]; - dst.z = src[0] * cXYZ_D65f[6] + src[1] * cXYZ_D65f[7] + src[2] * cXYZ_D65f[8]; - } - - template struct RGB2XYZBase - { - typedef int coeff_t; - - explicit RGB2XYZBase(const coeff_t coeffs[9]) - { - cudaSafeCall( cudaMemcpyToSymbol(cXYZ_D65i, coeffs, 9 * sizeof(int)) ); - } - }; - template <> struct RGB2XYZBase - { - typedef float coeff_t; - - explicit RGB2XYZBase(const coeff_t coeffs[9]) - { - cudaSafeCall( cudaMemcpyToSymbol(cXYZ_D65f, coeffs, 9 * sizeof(float)) ); - } - }; - template struct RGB2XYZ : RGB2XYZBase - { - typedef typename RGB2XYZBase::coeff_t coeff_t; - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - explicit RGB2XYZ(const coeff_t coeffs[9]) : RGB2XYZBase(coeffs) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - RGB2XYZConvert(&src.x, dst); - return dst; - } - }; - - template - __device__ __forceinline__ void XYZ2RGBConvert(const T& src, D* dst) - { - dst[0] = saturate_cast(CV_DESCALE(src.x * cXYZ_D65i[0] + src.y * cXYZ_D65i[1] + src.z * cXYZ_D65i[2], xyz_shift)); - dst[1] = saturate_cast(CV_DESCALE(src.x * cXYZ_D65i[3] + src.y * cXYZ_D65i[4] + src.z * cXYZ_D65i[5], xyz_shift)); - dst[2] = saturate_cast(CV_DESCALE(src.x * cXYZ_D65i[6] + src.y * cXYZ_D65i[7] + src.z * cXYZ_D65i[8], xyz_shift)); - } - template - __device__ __forceinline__ void XYZ2RGBConvert(const T& src, float* dst) - { - dst[0] = src.x * cXYZ_D65f[0] + src.y * cXYZ_D65f[1] + src.z * cXYZ_D65f[2]; - dst[1] = src.x * cXYZ_D65f[3] + src.y * cXYZ_D65f[4] + src.z * cXYZ_D65f[5]; - dst[2] = src.x * cXYZ_D65f[6] + src.y * cXYZ_D65f[7] + src.z * cXYZ_D65f[8]; - } - - template struct XYZ2RGBBase - { - typedef int coeff_t; - - explicit XYZ2RGBBase(const coeff_t coeffs[9]) - { - cudaSafeCall( cudaMemcpyToSymbol(cXYZ_D65i, coeffs, 9 * sizeof(int)) ); - } - }; - template <> struct XYZ2RGBBase - { - typedef float coeff_t; - - explicit XYZ2RGBBase(const coeff_t coeffs[9]) - { - cudaSafeCall( cudaMemcpyToSymbol(cXYZ_D65f, coeffs, 9 * sizeof(float)) ); - } - }; - template struct XYZ2RGB : XYZ2RGBBase - { - typedef typename RGB2XYZBase::coeff_t coeff_t; - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - explicit XYZ2RGB(const coeff_t coeffs[9]) : XYZ2RGBBase(coeffs) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - XYZ2RGBConvert(src, &dst.x); - setAlpha(dst, ColorChannel::max()); - return dst; - } - }; - - template - void RGB2XYZ_caller(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream) - { - typedef typename RGB2XYZ::coeff_t coeff_t; - RGB2XYZ cvt((const coeff_t*)coeffs); - callConvert(src, dst, cvt, stream); - } - - void RGB2XYZ_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, const void* coeffs, cudaStream_t stream) - { - typedef void (*RGB2XYZ_caller_t)(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream); - static const RGB2XYZ_caller_t RGB2XYZ_callers[2][2] = - { - {RGB2XYZ_caller, RGB2XYZ_caller}, - {RGB2XYZ_caller, RGB2XYZ_caller} - }; - - RGB2XYZ_callers[srccn-3][dstcn-3](src, dst, coeffs, stream); - } - - void RGB2XYZ_gpu_16u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, const void* coeffs, cudaStream_t stream) - { - typedef void (*RGB2XYZ_caller_t)(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream); - static const RGB2XYZ_caller_t RGB2XYZ_callers[2][2] = - { - {RGB2XYZ_caller, RGB2XYZ_caller}, - {RGB2XYZ_caller, RGB2XYZ_caller} - }; - - RGB2XYZ_callers[srccn-3][dstcn-3](src, dst, coeffs, stream); - } - - void RGB2XYZ_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, const void* coeffs, cudaStream_t stream) - { - typedef void (*RGB2XYZ_caller_t)(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream); - static const RGB2XYZ_caller_t RGB2XYZ_callers[2][2] = - { - {RGB2XYZ_caller, RGB2XYZ_caller}, - {RGB2XYZ_caller, RGB2XYZ_caller} - }; - - RGB2XYZ_callers[srccn-3][dstcn-3](src, dst, coeffs, stream); - } - - template - void XYZ2RGB_caller(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream) - { - typedef typename XYZ2RGB::coeff_t coeff_t; - XYZ2RGB cvt((const coeff_t*)coeffs); - callConvert(src, dst, cvt, stream); - } - - void XYZ2RGB_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, const void* coeffs, cudaStream_t stream) - { - typedef void (*XYZ2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream); - static const XYZ2RGB_caller_t XYZ2RGB_callers[2][2] = - { - {XYZ2RGB_caller, XYZ2RGB_caller}, - {XYZ2RGB_caller, XYZ2RGB_caller} - }; - - XYZ2RGB_callers[srccn-3][dstcn-3](src, dst, coeffs, stream); - } - - void XYZ2RGB_gpu_16u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, const void* coeffs, cudaStream_t stream) - { - typedef void (*XYZ2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream); - static const XYZ2RGB_caller_t XYZ2RGB_callers[2][2] = - { - {XYZ2RGB_caller, XYZ2RGB_caller}, - {XYZ2RGB_caller, XYZ2RGB_caller} - }; - - XYZ2RGB_callers[srccn-3][dstcn-3](src, dst, coeffs, stream); - } - - void XYZ2RGB_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, const void* coeffs, cudaStream_t stream) - { - typedef void (*XYZ2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, const void* coeffs, cudaStream_t stream); - static const XYZ2RGB_caller_t XYZ2RGB_callers[2][2] = - { - {XYZ2RGB_caller, XYZ2RGB_caller}, - {XYZ2RGB_caller, XYZ2RGB_caller} - }; - - XYZ2RGB_callers[srccn-3][dstcn-3](src, dst, coeffs, stream); - } - -////////////////////////////////////// RGB <-> HSV /////////////////////////////////////// - - __constant__ int cHsvDivTable [256] = {0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211, 130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632, 65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412, 43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693, 32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782, 26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223, 21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991, 18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579, 16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711, 14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221, 13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006, 11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995, 10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141, 10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410, 9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777, 8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224, 8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737, 7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304, 7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917, 6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569, 6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254, 6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968, 5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708, 5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468, 5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249, 5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046, 5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858, 4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684, 4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522, 4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370, 4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229, 4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096}; - __constant__ int cHsvDivTable180[256] = {0, 122880, 61440, 40960, 30720, 24576, 20480, 17554, 15360, 13653, 12288, 11171, 10240, 9452, 8777, 8192, 7680, 7228, 6827, 6467, 6144, 5851, 5585, 5343, 5120, 4915, 4726, 4551, 4389, 4237, 4096, 3964, 3840, 3724, 3614, 3511, 3413, 3321, 3234, 3151, 3072, 2997, 2926, 2858, 2793, 2731, 2671, 2614, 2560, 2508, 2458, 2409, 2363, 2318, 2276, 2234, 2194, 2156, 2119, 2083, 2048, 2014, 1982, 1950, 1920, 1890, 1862, 1834, 1807, 1781, 1755, 1731, 1707, 1683, 1661, 1638, 1617, 1596, 1575, 1555, 1536, 1517, 1499, 1480, 1463, 1446, 1429, 1412, 1396, 1381, 1365, 1350, 1336, 1321, 1307, 1293, 1280, 1267, 1254, 1241, 1229, 1217, 1205, 1193, 1182, 1170, 1159, 1148, 1138, 1127, 1117, 1107, 1097, 1087, 1078, 1069, 1059, 1050, 1041, 1033, 1024, 1016, 1007, 999, 991, 983, 975, 968, 960, 953, 945, 938, 931, 924, 917, 910, 904, 897, 890, 884, 878, 871, 865, 859, 853, 847, 842, 836, 830, 825, 819, 814, 808, 803, 798, 793, 788, 783, 778, 773, 768, 763, 759, 754, 749, 745, 740, 736, 731, 727, 723, 719, 714, 710, 706, 702, 698, 694, 690, 686, 683, 679, 675, 671, 668, 664, 661, 657, 654, 650, 647, 643, 640, 637, 633, 630, 627, 624, 621, 617, 614, 611, 608, 605, 602, 599, 597, 594, 591, 588, 585, 582, 580, 577, 574, 572, 569, 566, 564, 561, 559, 556, 554, 551, 549, 546, 544, 541, 539, 537, 534, 532, 530, 527, 525, 523, 521, 518, 516, 514, 512, 510, 508, 506, 504, 502, 500, 497, 495, 493, 492, 490, 488, 486, 484, 482}; - __constant__ int cHsvDivTable256[256] = {0, 174763, 87381, 58254, 43691, 34953, 29127, 24966, 21845, 19418, 17476, 15888, 14564, 13443, 12483, 11651, 10923, 10280, 9709, 9198, 8738, 8322, 7944, 7598, 7282, 6991, 6722, 6473, 6242, 6026, 5825, 5638, 5461, 5296, 5140, 4993, 4855, 4723, 4599, 4481, 4369, 4263, 4161, 4064, 3972, 3884, 3799, 3718, 3641, 3567, 3495, 3427, 3361, 3297, 3236, 3178, 3121, 3066, 3013, 2962, 2913, 2865, 2819, 2774, 2731, 2689, 2648, 2608, 2570, 2533, 2497, 2461, 2427, 2394, 2362, 2330, 2300, 2270, 2241, 2212, 2185, 2158, 2131, 2106, 2081, 2056, 2032, 2009, 1986, 1964, 1942, 1920, 1900, 1879, 1859, 1840, 1820, 1802, 1783, 1765, 1748, 1730, 1713, 1697, 1680, 1664, 1649, 1633, 1618, 1603, 1589, 1574, 1560, 1547, 1533, 1520, 1507, 1494, 1481, 1469, 1456, 1444, 1432, 1421, 1409, 1398, 1387, 1376, 1365, 1355, 1344, 1334, 1324, 1314, 1304, 1295, 1285, 1276, 1266, 1257, 1248, 1239, 1231, 1222, 1214, 1205, 1197, 1189, 1181, 1173, 1165, 1157, 1150, 1142, 1135, 1128, 1120, 1113, 1106, 1099, 1092, 1085, 1079, 1072, 1066, 1059, 1053, 1046, 1040, 1034, 1028, 1022, 1016, 1010, 1004, 999, 993, 987, 982, 976, 971, 966, 960, 955, 950, 945, 940, 935, 930, 925, 920, 915, 910, 906, 901, 896, 892, 887, 883, 878, 874, 869, 865, 861, 857, 853, 848, 844, 840, 836, 832, 828, 824, 820, 817, 813, 809, 805, 802, 798, 794, 791, 787, 784, 780, 777, 773, 770, 767, 763, 760, 757, 753, 750, 747, 744, 741, 737, 734, 731, 728, 725, 722, 719, 716, 713, 710, 708, 705, 702, 699, 696, 694, 691, 688, 685}; - - template __device__ void RGB2HSVConvert(const uchar* src, D& dst, int bidx, int hr) - { - const int hsv_shift = 12; - const int* hdiv_table = hr == 180 ? cHsvDivTable180 : cHsvDivTable256; - - int b = src[bidx], g = src[1], r = src[bidx^2]; - int h, s, v = b; - int vmin = b, diff; - int vr, vg; - - v = max(v, g); - v = max(v, r); - vmin = min(vmin, g); - vmin = min(vmin, r); - - diff = v - vmin; - vr = v == r ? -1 : 0; - vg = v == g ? -1 : 0; - - s = (diff * cHsvDivTable[v] + (1 << (hsv_shift-1))) >> hsv_shift; - h = (vr & (g - b)) + (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff)))); - h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift; - h += h < 0 ? hr : 0; - - dst.x = saturate_cast(h); - dst.y = (uchar)s; - dst.z = (uchar)v; - } - template __device__ void RGB2HSVConvert(const float* src, D& dst, int bidx, int hr) - { - const float hscale = hr * (1.f / 360.f); - - float b = src[bidx], g = src[1], r = src[bidx^2]; - float h, s, v; - - float vmin, diff; - - v = vmin = r; - v = fmax(v, g); - v = fmax(v, b); - vmin = fmin(vmin, g); - vmin = fmin(vmin, b); - - diff = v - vmin; - s = diff / (float)(fabs(v) + numeric_limits_gpu::epsilon()); - diff = (float)(60. / (diff + numeric_limits_gpu::epsilon())); - - if (v == r) - h = (g - b) * diff; - else if (v == g) - h = (b - r) * diff + 120.f; - else - h = (r - g) * diff + 240.f; - - if (h < 0) h += 360.f; - - dst.x = h * hscale; - dst.y = s; - dst.z = v; - } - - template struct RGB2HSV - { - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - RGB2HSV(int bidx, int hr) : bidx(bidx), hr(hr) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - RGB2HSVConvert(&src.x, dst, bidx, hr); - return dst; - } - - private: - int bidx; - int hr; - }; - - __constant__ int cHsvSectorData[6][3] = - { - {1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0} - }; - - template __device__ void HSV2RGBConvert(const T& src, float* dst, int bidx, int hr) - { - const float hscale = 6.f / hr; - - float h = src.x, s = src.y, v = src.z; - float b, g, r; - - if( s == 0 ) - b = g = r = v; - else - { - float tab[4]; - int sector; - h *= hscale; - if( h < 0 ) - do h += 6; while( h < 0 ); - else if( h >= 6 ) - do h -= 6; while( h >= 6 ); - sector = __float2int_rd(h); - h -= sector; - - tab[0] = v; - tab[1] = v*(1.f - s); - tab[2] = v*(1.f - s*h); - tab[3] = v*(1.f - s*(1.f - h)); - - b = tab[cHsvSectorData[sector][0]]; - g = tab[cHsvSectorData[sector][1]]; - r = tab[cHsvSectorData[sector][2]]; - } - - dst[bidx] = b; - dst[1] = g; - dst[bidx^2] = r; - } - template __device__ void HSV2RGBConvert(const T& src, uchar* dst, int bidx, int hr) - { - float3 buf; - - buf.x = src.x; - buf.y = src.y * (1.f/255.f); - buf.z = src.z * (1.f/255.f); - - HSV2RGBConvert(buf, &buf.x, bidx, hr); - - dst[0] = saturate_cast(buf.x * 255.f); - dst[1] = saturate_cast(buf.y * 255.f); - dst[2] = saturate_cast(buf.z * 255.f); - } - - template struct HSV2RGB - { - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - HSV2RGB(int bidx, int hr) : bidx(bidx), hr(hr) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - HSV2RGBConvert(src, &dst.x, bidx, hr); - setAlpha(dst, ColorChannel::max()); - return dst; - } - - private: - int bidx; - int hr; - }; - - template - void RGB2HSV_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream) - { - RGB2HSV cvt(bidx, hrange); - callConvert(src, dst, cvt, stream); - } - - void RGB2HSV_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*RGB2HSV_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const RGB2HSV_caller_t RGB2HSV_callers[2][2] = - { - {RGB2HSV_caller, RGB2HSV_caller}, - {RGB2HSV_caller, RGB2HSV_caller} - }; - - RGB2HSV_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - - void RGB2HSV_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*RGB2HSV_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const RGB2HSV_caller_t RGB2HSV_callers[2][2] = - { - {RGB2HSV_caller, RGB2HSV_caller}, - {RGB2HSV_caller, RGB2HSV_caller} - }; - - RGB2HSV_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - - template - void HSV2RGB_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream) - { - HSV2RGB cvt(bidx, hrange); - callConvert(src, dst, cvt, stream); - } - - void HSV2RGB_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*HSV2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const HSV2RGB_caller_t HSV2RGB_callers[2][2] = - { - {HSV2RGB_caller, HSV2RGB_caller}, - {HSV2RGB_caller, HSV2RGB_caller} - }; - - HSV2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - - void HSV2RGB_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*HSV2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const HSV2RGB_caller_t HSV2RGB_callers[2][2] = - { - {HSV2RGB_caller, HSV2RGB_caller}, - {HSV2RGB_caller, HSV2RGB_caller} - }; - - HSV2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - -/////////////////////////////////////// RGB <-> HLS //////////////////////////////////////// - - template __device__ void RGB2HLSConvert(const float* src, D& dst, int bidx, int hr) - { - const float hscale = hr * (1.f / 360.f); - - float b = src[bidx], g = src[1], r = src[bidx^2]; - float h = 0.f, s = 0.f, l; - float vmin, vmax, diff; - - vmax = vmin = r; - vmax = fmax(vmax, g); - vmax = fmax(vmax, b); - vmin = fmin(vmin, g); - vmin = fmin(vmin, b); - - diff = vmax - vmin; - l = (vmax + vmin) * 0.5f; - - if (diff > numeric_limits_gpu::epsilon()) - { - s = l < 0.5f ? diff / (vmax + vmin) : diff / (2.0f - vmax - vmin); - diff = 60.f / diff; - - if (vmax == r) - h = (g - b)*diff; - else if (vmax == g) - h = (b - r)*diff + 120.f; - else - h = (r - g)*diff + 240.f; - - if (h < 0.f) h += 360.f; - } - - dst.x = h * hscale; - dst.y = l; - dst.z = s; - } - template __device__ void RGB2HLSConvert(const uchar* src, D& dst, int bidx, int hr) - { - float3 buf; - - buf.x = src[0]*(1.f/255.f); - buf.y = src[1]*(1.f/255.f); - buf.z = src[2]*(1.f/255.f); - - RGB2HLSConvert(&buf.x, buf, bidx, hr); - - dst.x = saturate_cast(buf.x); - dst.y = saturate_cast(buf.y*255.f); - dst.z = saturate_cast(buf.z*255.f); - } - - template struct RGB2HLS - { - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - RGB2HLS(int bidx, int hr) : bidx(bidx), hr(hr) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - RGB2HLSConvert(&src.x, dst, bidx, hr); - return dst; - } - - private: - int bidx; - int hr; - }; - - __constant__ int cHlsSectorData[6][3] = - { - {1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0} - }; - - template __device__ void HLS2RGBConvert(const T& src, float* dst, int bidx, int hr) - { - const float hscale = 6.0f / hr; - - float h = src.x, l = src.y, s = src.z; - float b, g, r; - - if (s == 0) - b = g = r = l; - else - { - float tab[4]; - int sector; - - float p2 = l <= 0.5f ? l * (1 + s) : l + s - l * s; - float p1 = 2 * l - p2; - - h *= hscale; - - if( h < 0 ) - do h += 6; while( h < 0 ); - else if( h >= 6 ) - do h -= 6; while( h >= 6 ); - - sector = __float2int_rd(h); - h -= sector; - - tab[0] = p2; - tab[1] = p1; - tab[2] = p1 + (p2 - p1) * (1 - h); - tab[3] = p1 + (p2 - p1) * h; - - b = tab[cHlsSectorData[sector][0]]; - g = tab[cHlsSectorData[sector][1]]; - r = tab[cHlsSectorData[sector][2]]; - } - - dst[bidx] = b; - dst[1] = g; - dst[bidx^2] = r; - } - template __device__ void HLS2RGBConvert(const T& src, uchar* dst, int bidx, int hr) - { - float3 buf; - - buf.x = src.x; - buf.y = src.y*(1.f/255.f); - buf.z = src.z*(1.f/255.f); - - HLS2RGBConvert(buf, &buf.x, bidx, hr); - - dst[0] = saturate_cast(buf.x*255.f); - dst[1] = saturate_cast(buf.y*255.f); - dst[2] = saturate_cast(buf.z*255.f); - } - - template struct HLS2RGB - { - typedef typename TypeVec::vec_t src_t; - typedef typename TypeVec::vec_t dst_t; - - HLS2RGB(int bidx, int hr) : bidx(bidx), hr(hr) {} - - __device__ __forceinline__ dst_t operator()(const src_t& src) const - { - dst_t dst; - HLS2RGBConvert(src, &dst.x, bidx, hr); - setAlpha(dst, ColorChannel::max()); - return dst; - } - - private: - int bidx; - int hr; - }; - - template - void RGB2HLS_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream) - { - RGB2HLS cvt(bidx, hrange); - callConvert(src, dst, cvt, stream); - } - - void RGB2HLS_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*RGB2HLS_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const RGB2HLS_caller_t RGB2HLS_callers[2][2] = - { - {RGB2HLS_caller, RGB2HLS_caller}, - {RGB2HLS_caller, RGB2HLS_caller} - }; - - RGB2HLS_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - - void RGB2HLS_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*RGB2HLS_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const RGB2HLS_caller_t RGB2HLS_callers[2][2] = - { - {RGB2HLS_caller, RGB2HLS_caller}, - {RGB2HLS_caller, RGB2HLS_caller} - }; - - RGB2HLS_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - - - template - void HLS2RGB_caller(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream) - { - HLS2RGB cvt(bidx, hrange); - callConvert(src, dst, cvt, stream); - } - - void HLS2RGB_gpu_8u(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*HLS2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const HLS2RGB_caller_t HLS2RGB_callers[2][2] = - { - {HLS2RGB_caller, HLS2RGB_caller}, - {HLS2RGB_caller, HLS2RGB_caller} - }; - - HLS2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } - - void HLS2RGB_gpu_32f(const DevMem2D& src, int srccn, const DevMem2D& dst, int dstcn, int bidx, int hrange, cudaStream_t stream) - { - typedef void (*HLS2RGB_caller_t)(const DevMem2D& src, const DevMem2D& dst, int bidx, int hrange, cudaStream_t stream); - static const HLS2RGB_caller_t HLS2RGB_callers[2][2] = - { - {HLS2RGB_caller, HLS2RGB_caller}, - {HLS2RGB_caller, HLS2RGB_caller} - }; - - HLS2RGB_callers[srccn-3][dstcn-3](src, dst, bidx, hrange, stream); - } + #define OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(name) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name, name ## _traits) + + #define OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(name) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _8u, name ## _traits) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _16u, name ## _traits) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _32f, name ## _traits) + + #define OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(name) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _8u, name ## _traits) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _32f, name ## _traits) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _full_8u, name ## _full_traits) \ + OPENCV_GPU_IMPLEMENT_CVTCOLOR(name ## _full_32f, name ## _full_traits) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_rgba) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr_to_bgr555) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr_to_bgr565) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(rgb_to_bgr555) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(rgb_to_bgr565) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgra_to_bgr555) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgra_to_bgr565) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(rgba_to_bgr555) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(rgba_to_bgr565) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr555_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr565_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr555_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr565_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr555_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr565_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr555_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr565_to_bgra) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(gray_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(gray_to_bgra) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(gray_to_bgr555) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(gray_to_bgr565) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr555_to_gray) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(bgr565_to_gray) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_gray) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_gray) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_gray) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_gray) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_yuv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_yuv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_yuv4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_yuv4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_yuv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_yuv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_yuv4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_yuv4) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv4_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv4_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv4_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(yuv4_to_bgra) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_YCrCb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_YCrCb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_YCrCb4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_YCrCb4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_YCrCb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_YCrCb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_YCrCb4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_YCrCb4) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_bgra) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_xyz) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_xyz) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgb_to_xyz4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(rgba_to_xyz4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_xyz) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_xyz) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgr_to_xyz4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(bgra_to_xyz4) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz4_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz4_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz4_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL(xyz4_to_bgra) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgb_to_hsv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgba_to_hsv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgb_to_hsv4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgba_to_hsv4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgr_to_hsv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgra_to_hsv) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgr_to_hsv4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgra_to_hsv4) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv4_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv4_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv4_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hsv4_to_bgra) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgb_to_hls) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgba_to_hls) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgb_to_hls4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(rgba_to_hls4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgr_to_hls) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgra_to_hls) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgr_to_hls4) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(bgra_to_hls4) + + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls4_to_rgb) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls4_to_rgba) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls_to_bgra) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls4_to_bgr) + OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F(hls4_to_bgra) + + #undef OPENCV_GPU_IMPLEMENT_CVTCOLOR + #undef OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE + #undef OPENCV_GPU_IMPLEMENT_CVTCOLOR_ALL + #undef OPENCV_GPU_IMPLEMENT_CVTCOLOR_8U32F }}} diff --git a/modules/gpu/src/cuda/element_operations.cu b/modules/gpu/src/cuda/element_operations.cu index de7e865e08..0626d8938a 100644 --- a/modules/gpu/src/cuda/element_operations.cu +++ b/modules/gpu/src/cuda/element_operations.cu @@ -40,8 +40,10 @@ // //M*/ -#include "opencv2/gpu/device/vecmath.hpp" +#include "opencv2/gpu/device/functional.hpp" +#include "opencv2/gpu/device/vec_math.hpp" #include "opencv2/gpu/device/transform.hpp" +#include "opencv2/gpu/device/limits.hpp" #include "opencv2/gpu/device/saturate_cast.hpp" #include "internal_shared.hpp" @@ -54,10 +56,9 @@ namespace cv { namespace gpu { namespace mathfunc ////////////////////////////////////////////////////////////////////////////////////// // Compare - template - struct NotEqual + template struct NotEqual : binary_function { - __device__ __forceinline__ uchar operator()(const T1& src1, const T2& src2) + __device__ __forceinline__ uchar operator()(const T1& src1, const T2& src2) const { return static_cast(static_cast(src1 != src2) * 255); } @@ -169,10 +170,10 @@ namespace cv { namespace gpu { namespace mathfunc } - void bitwiseNotCaller(int rows, int cols, int elem_size1, int cn, + void bitwiseNotCaller(int rows, int cols, size_t elem_size1, int cn, const PtrStep src, PtrStep dst, cudaStream_t stream) { - bitwiseUnOp(rows, cols * elem_size1 * cn, src, dst, stream); + bitwiseUnOp(rows, static_cast(cols * elem_size1 * cn), src, dst, stream); } @@ -294,10 +295,10 @@ namespace cv { namespace gpu { namespace mathfunc } - void bitwiseOrCaller(int rows, int cols, int elem_size1, int cn, const PtrStep src1, + void bitwiseOrCaller(int rows, int cols, size_t elem_size1, int cn, const PtrStep src1, const PtrStep src2, PtrStep dst, cudaStream_t stream) { - bitwiseBinOp(rows, cols * elem_size1 * cn, src1, src2, dst, stream); + bitwiseBinOp(rows, static_cast(cols * elem_size1 * cn), src1, src2, dst, stream); } @@ -313,10 +314,10 @@ namespace cv { namespace gpu { namespace mathfunc template void bitwiseMaskOrCaller(int, int, int, const PtrStep, const PtrStep, const PtrStep, PtrStep, cudaStream_t); - void bitwiseAndCaller(int rows, int cols, int elem_size1, int cn, const PtrStep src1, + void bitwiseAndCaller(int rows, int cols, size_t elem_size1, int cn, const PtrStep src1, const PtrStep src2, PtrStep dst, cudaStream_t stream) { - bitwiseBinOp(rows, cols * elem_size1 * cn, src1, src2, dst, stream); + bitwiseBinOp(rows, static_cast(cols * elem_size1 * cn), src1, src2, dst, stream); } @@ -332,10 +333,10 @@ namespace cv { namespace gpu { namespace mathfunc template void bitwiseMaskAndCaller(int, int, int, const PtrStep, const PtrStep, const PtrStep, PtrStep, cudaStream_t); - void bitwiseXorCaller(int rows, int cols, int elem_size1, int cn, const PtrStep src1, + void bitwiseXorCaller(int rows, int cols, size_t elem_size1, int cn, const PtrStep src1, const PtrStep src2, PtrStep dst, cudaStream_t stream) { - bitwiseBinOp(rows, cols * elem_size1 * cn, src1, src2, dst, stream); + bitwiseBinOp(rows, static_cast(cols * elem_size1 * cn), src1, src2, dst, stream); } @@ -353,114 +354,11 @@ namespace cv { namespace gpu { namespace mathfunc ////////////////////////////////////////////////////////////////////////// // min/max - - struct MinOp - { - template - __device__ __forceinline__ T operator()(T a, T b) - { - return min(a, b); - } - __device__ __forceinline__ float operator()(float a, float b) - { - return fmin(a, b); - } - __device__ __forceinline__ double operator()(double a, double b) - { - return fmin(a, b); - } - }; - - struct MaxOp - { - template - __device__ __forceinline__ T operator()(T a, T b) - { - return max(a, b); - } - __device__ __forceinline__ float operator()(float a, float b) - { - return fmax(a, b); - } - __device__ __forceinline__ double operator()(double a, double b) - { - return fmax(a, b); - } - }; - - template struct ScalarMinOp - { - T s; - - explicit ScalarMinOp(T s_) : s(s_) {} - - __device__ __forceinline__ T operator()(T a) - { - return min(a, s); - } - }; - template <> struct ScalarMinOp - { - float s; - - explicit ScalarMinOp(float s_) : s(s_) {} - - __device__ __forceinline__ float operator()(float a) - { - return fmin(a, s); - } - }; - template <> struct ScalarMinOp - { - double s; - - explicit ScalarMinOp(double s_) : s(s_) {} - - __device__ __forceinline__ double operator()(double a) - { - return fmin(a, s); - } - }; - - template struct ScalarMaxOp - { - T s; - - explicit ScalarMaxOp(T s_) : s(s_) {} - - __device__ __forceinline__ T operator()(T a) - { - return max(a, s); - } - }; - template <> struct ScalarMaxOp - { - float s; - - explicit ScalarMaxOp(float s_) : s(s_) {} - - __device__ __forceinline__ float operator()(float a) - { - return fmax(a, s); - } - }; - template <> struct ScalarMaxOp - { - double s; - - explicit ScalarMaxOp(double s_) : s(s_) {} - - __device__ __forceinline__ double operator()(double a) - { - return fmax(a, s); - } - }; template void min_gpu(const DevMem2D_& src1, const DevMem2D_& src2, const DevMem2D_& dst, cudaStream_t stream) { - MinOp op; - transform(src1, src2, dst, op, stream); + transform(src1, src2, dst, minimum(), stream); } template void min_gpu(const DevMem2D& src1, const DevMem2D& src2, const DevMem2D& dst, cudaStream_t stream); @@ -474,8 +372,7 @@ namespace cv { namespace gpu { namespace mathfunc template void max_gpu(const DevMem2D_& src1, const DevMem2D_& src2, const DevMem2D_& dst, cudaStream_t stream) { - MaxOp op; - transform(src1, src2, dst, op, stream); + transform(src1, src2, dst, maximum(), stream); } template void max_gpu(const DevMem2D& src1, const DevMem2D& src2, const DevMem2D& dst, cudaStream_t stream); @@ -489,8 +386,7 @@ namespace cv { namespace gpu { namespace mathfunc template void min_gpu(const DevMem2D_& src1, T src2, const DevMem2D_& dst, cudaStream_t stream) { - ScalarMinOp op(src2); - transform(src1, dst, op, stream); + transform(src1, dst, device::bind2nd(minimum(), src2), stream); } template void min_gpu(const DevMem2D& src1, uchar src2, const DevMem2D& dst, cudaStream_t stream); @@ -500,12 +396,11 @@ namespace cv { namespace gpu { namespace mathfunc template void min_gpu(const DevMem2D_& src1, int src2, const DevMem2D_& dst, cudaStream_t stream); template void min_gpu(const DevMem2D_& src1, float src2, const DevMem2D_& dst, cudaStream_t stream); template void min_gpu(const DevMem2D_& src1, double src2, const DevMem2D_& dst, cudaStream_t stream); - + template void max_gpu(const DevMem2D_& src1, T src2, const DevMem2D_& dst, cudaStream_t stream) { - ScalarMaxOp op(src2); - transform(src1, dst, op, stream); + transform(src1, dst, device::bind2nd(maximum(), src2), stream); } template void max_gpu(const DevMem2D& src1, uchar src2, const DevMem2D& dst, cudaStream_t stream); @@ -518,100 +413,7 @@ namespace cv { namespace gpu { namespace mathfunc ////////////////////////////////////////////////////////////////////////// - // threshold - - template struct ThreshBinary - { - ThreshBinary(T thresh_, T maxVal_) : thresh(thresh_), maxVal(maxVal_) {} - - __device__ __forceinline__ T operator()(const T& src) const - { - return src > thresh ? maxVal : 0; - } - - private: - T thresh; - T maxVal; - }; - - template struct ThreshBinaryInv - { - ThreshBinaryInv(T thresh_, T maxVal_) : thresh(thresh_), maxVal(maxVal_) {} - - __device__ __forceinline__ T operator()(const T& src) const - { - return src > thresh ? 0 : maxVal; - } - - private: - T thresh; - T maxVal; - }; - - template struct ThreshTrunc - { - ThreshTrunc(T thresh_, T) : thresh(thresh_) {} - - __device__ __forceinline__ T operator()(const T& src) const - { - return min(src, thresh); - } - - private: - T thresh; - }; - template <> struct ThreshTrunc - { - ThreshTrunc(float thresh_, float) : thresh(thresh_) {} - - __device__ __forceinline__ float operator()(const float& src) const - { - return fmin(src, thresh); - } - - private: - float thresh; - }; - template <> struct ThreshTrunc - { - ThreshTrunc(double thresh_, double) : thresh(thresh_) {} - - __device__ __forceinline__ double operator()(const double& src) const - { - return fmin(src, thresh); - } - - private: - double thresh; - }; - - template struct ThreshToZero - { - public: - ThreshToZero(T thresh_, T) : thresh(thresh_) {} - - __device__ __forceinline__ T operator()(const T& src) const - { - return src > thresh ? src : 0; - } - - private: - T thresh; - }; - - template struct ThreshToZeroInv - { - public: - ThreshToZeroInv(T thresh_, T) : thresh(thresh_) {} - - __device__ __forceinline__ T operator()(const T& src) const - { - return src > thresh ? 0 : src; - } - - private: - T thresh; - }; + // threshold template