From d131137a141de8951655f6f92fd9c3f0a0b4ab53 Mon Sep 17 00:00:00 2001 From: WU Jia <35290826+kaingwade@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:10:18 +0800 Subject: [PATCH] Merge pull request #3709 from kaingwade:features2d_parts_to_contrib features2d cleanup: [#24999](https://github.com/opencv/opencv/issues/24999) Main PR: opencv/opencv#25292, which moves KAZE, AKAZE, AgastFeatureDetector, BRISK and BOW to opencv_contrib/xfeatures2d. --- modules/ccalib/CMakeLists.txt | 2 +- .../include/opencv2/ccalib/multicalib.hpp | 4 +- .../include/opencv2/ccalib/randpattern.hpp | 5 +- modules/ccalib/src/precomp.hpp | 1 + modules/xfeatures2d/doc/agast.txt | 7701 +++++++++++++ modules/xfeatures2d/doc/agast_score.txt | 9402 ++++++++++++++++ .../xfeatures2d/doc/read_file_nondiff32.pl | 284 + modules/xfeatures2d/doc/read_file_score32.pl | 244 + modules/xfeatures2d/doc/run_agast_tables.bat | 32 + modules/xfeatures2d/doc/xfeatures2d.bib | 19 + .../include/opencv2/xfeatures2d.hpp | 409 + .../java/test/AGASTFeatureDetectorTest.java | 85 + .../test/AKAZEDescriptorExtractorTest.java | 67 + .../test/BOWImgDescriptorExtractorTest.java | 48 + .../test/BRIEFDescriptorExtractorTest.java | 102 + .../test/BRISKDescriptorExtractorTest.java | 63 + .../test/KAZEDescriptorExtractorTest.java | 66 + modules/xfeatures2d/misc/js/gen_dict.json | 9 + modules/xfeatures2d/misc/objc/gen_dict.json | 3 + .../misc/python/pyopencv_xfeatures2d.hpp | 7 +- .../misc/python/test/test_descriptors.py | 2 +- modules/xfeatures2d/perf/perf_feature2d.cpp | 71 + modules/xfeatures2d/perf/perf_feature2d.hpp | 60 + .../xfeatures2d/perf/perf_feature2d.ocl.cpp | 81 + modules/xfeatures2d/samples/LATCH_match.cpp | 115 + modules/xfeatures2d/src/agast.cpp | 8195 ++++++++++++++ modules/xfeatures2d/src/agast_score.cpp | 9866 +++++++++++++++++ modules/xfeatures2d/src/agast_score.hpp | 71 + modules/xfeatures2d/src/akaze.cpp | 280 + modules/xfeatures2d/src/bagofwords.cpp | 219 + modules/xfeatures2d/src/brisk.cpp | 2435 ++++ modules/xfeatures2d/src/kaze.cpp | 216 + modules/xfeatures2d/src/kaze/AKAZEConfig.h | 69 + .../xfeatures2d/src/kaze/AKAZEFeatures.cpp | 2321 ++++ modules/xfeatures2d/src/kaze/AKAZEFeatures.h | 118 + modules/xfeatures2d/src/kaze/KAZEConfig.h | 60 + modules/xfeatures2d/src/kaze/KAZEFeatures.cpp | 1219 ++ modules/xfeatures2d/src/kaze/KAZEFeatures.h | 67 + modules/xfeatures2d/src/kaze/TEvolution.h | 41 + modules/xfeatures2d/src/kaze/fed.cpp | 192 + modules/xfeatures2d/src/kaze/fed.h | 25 + .../src/kaze/nldiffusion_functions.cpp | 542 + .../src/kaze/nldiffusion_functions.h | 47 + modules/xfeatures2d/src/kaze/utils.h | 42 + modules/xfeatures2d/src/opencl/akaze.cl | 122 + modules/xfeatures2d/src/precomp.hpp | 1 + modules/xfeatures2d/test/test_agast.cpp | 138 + modules/xfeatures2d/test/test_akaze.cpp | 48 + modules/xfeatures2d/test/test_brisk.cpp | 108 + .../xfeatures2d/test/test_feature2d.ocl.cpp | 73 + modules/xfeatures2d/test/test_features2d.cpp | 127 + modules/xfeatures2d/test/test_keypoints.cpp | 27 + .../test_rotation_and_scale_invariance.cpp | 57 +- .../tutorials/py_brief/py_brief.markdown | 92 + .../py_surf_intro/images/surf_boxfilter.jpg | Bin 0 -> 12995 bytes .../py_surf_intro/images/surf_kp1.jpg | Bin 0 -> 27166 bytes .../py_surf_intro/images/surf_kp2.jpg | Bin 0 -> 28476 bytes .../py_surf_intro/images/surf_matching.jpg | Bin 0 -> 11848 bytes .../py_surf_intro/images/surf_orientation.jpg | Bin 0 -> 7887 bytes .../py_surf_intro/py_surf_intro.markdown | 163 + .../table_of_content_xfeatures2d.markdown | 15 + 61 files changed, 45870 insertions(+), 8 deletions(-) create mode 100644 modules/xfeatures2d/doc/agast.txt create mode 100644 modules/xfeatures2d/doc/agast_score.txt create mode 100644 modules/xfeatures2d/doc/read_file_nondiff32.pl create mode 100644 modules/xfeatures2d/doc/read_file_score32.pl create mode 100644 modules/xfeatures2d/doc/run_agast_tables.bat create mode 100644 modules/xfeatures2d/misc/java/test/AGASTFeatureDetectorTest.java create mode 100644 modules/xfeatures2d/misc/java/test/AKAZEDescriptorExtractorTest.java create mode 100644 modules/xfeatures2d/misc/java/test/BOWImgDescriptorExtractorTest.java create mode 100644 modules/xfeatures2d/misc/java/test/BRIEFDescriptorExtractorTest.java create mode 100644 modules/xfeatures2d/misc/java/test/BRISKDescriptorExtractorTest.java create mode 100644 modules/xfeatures2d/misc/java/test/KAZEDescriptorExtractorTest.java create mode 100644 modules/xfeatures2d/misc/js/gen_dict.json create mode 100644 modules/xfeatures2d/perf/perf_feature2d.cpp create mode 100644 modules/xfeatures2d/perf/perf_feature2d.hpp create mode 100644 modules/xfeatures2d/perf/perf_feature2d.ocl.cpp create mode 100644 modules/xfeatures2d/samples/LATCH_match.cpp create mode 100644 modules/xfeatures2d/src/agast.cpp create mode 100644 modules/xfeatures2d/src/agast_score.cpp create mode 100644 modules/xfeatures2d/src/agast_score.hpp create mode 100644 modules/xfeatures2d/src/akaze.cpp create mode 100644 modules/xfeatures2d/src/bagofwords.cpp create mode 100644 modules/xfeatures2d/src/brisk.cpp create mode 100644 modules/xfeatures2d/src/kaze.cpp create mode 100644 modules/xfeatures2d/src/kaze/AKAZEConfig.h create mode 100644 modules/xfeatures2d/src/kaze/AKAZEFeatures.cpp create mode 100644 modules/xfeatures2d/src/kaze/AKAZEFeatures.h create mode 100644 modules/xfeatures2d/src/kaze/KAZEConfig.h create mode 100644 modules/xfeatures2d/src/kaze/KAZEFeatures.cpp create mode 100644 modules/xfeatures2d/src/kaze/KAZEFeatures.h create mode 100644 modules/xfeatures2d/src/kaze/TEvolution.h create mode 100644 modules/xfeatures2d/src/kaze/fed.cpp create mode 100644 modules/xfeatures2d/src/kaze/fed.h create mode 100644 modules/xfeatures2d/src/kaze/nldiffusion_functions.cpp create mode 100644 modules/xfeatures2d/src/kaze/nldiffusion_functions.h create mode 100644 modules/xfeatures2d/src/kaze/utils.h create mode 100644 modules/xfeatures2d/src/opencl/akaze.cl create mode 100644 modules/xfeatures2d/test/test_agast.cpp create mode 100644 modules/xfeatures2d/test/test_akaze.cpp create mode 100644 modules/xfeatures2d/test/test_brisk.cpp create mode 100644 modules/xfeatures2d/test/test_feature2d.ocl.cpp create mode 100644 modules/xfeatures2d/tutorials/py_brief/py_brief.markdown create mode 100644 modules/xfeatures2d/tutorials/py_surf_intro/images/surf_boxfilter.jpg create mode 100644 modules/xfeatures2d/tutorials/py_surf_intro/images/surf_kp1.jpg create mode 100644 modules/xfeatures2d/tutorials/py_surf_intro/images/surf_kp2.jpg create mode 100644 modules/xfeatures2d/tutorials/py_surf_intro/images/surf_matching.jpg create mode 100644 modules/xfeatures2d/tutorials/py_surf_intro/images/surf_orientation.jpg create mode 100644 modules/xfeatures2d/tutorials/py_surf_intro/py_surf_intro.markdown create mode 100644 modules/xfeatures2d/tutorials/table_of_content_xfeatures2d.markdown diff --git a/modules/ccalib/CMakeLists.txt b/modules/ccalib/CMakeLists.txt index b97a01296e9..dd82c1936cb 100644 --- a/modules/ccalib/CMakeLists.txt +++ b/modules/ccalib/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "Custom Calibration Pattern") -ocv_define_module(ccalib opencv_core opencv_imgproc opencv_3d opencv_calib opencv_features2d opencv_highgui opencv_imgcodecs WRAP python) +ocv_define_module(ccalib opencv_core opencv_imgproc opencv_3d opencv_calib opencv_features2d opencv_xfeatures2d opencv_highgui opencv_imgcodecs WRAP python) diff --git a/modules/ccalib/include/opencv2/ccalib/multicalib.hpp b/modules/ccalib/include/opencv2/ccalib/multicalib.hpp index 686d7a52b09..15629997e31 100644 --- a/modules/ccalib/include/opencv2/ccalib/multicalib.hpp +++ b/modules/ccalib/include/opencv2/ccalib/multicalib.hpp @@ -132,8 +132,8 @@ class CV_EXPORTS MultiCameraCalibration MultiCameraCalibration(int cameraType, int nCameras, const std::string& fileName, float patternWidth, float patternHeight, int verbose = 0, int showExtration = 0, int nMiniMatches = 20, int flags = 0, TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 200, 1e-7), - Ptr detector = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.006f), - Ptr descriptor = AKAZE::create(AKAZE::DESCRIPTOR_MLDB,0, 3, 0.006f), + Ptr detector = xfeatures2d::AKAZE::create(xfeatures2d::AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.006f), + Ptr descriptor = xfeatures2d::AKAZE::create(xfeatures2d::AKAZE::DESCRIPTOR_MLDB,0, 3, 0.006f), Ptr matcher = DescriptorMatcher::create("BruteForce-L1")); /* @brief load images diff --git a/modules/ccalib/include/opencv2/ccalib/randpattern.hpp b/modules/ccalib/include/opencv2/ccalib/randpattern.hpp index fb362bd5308..41ffd095a0e 100644 --- a/modules/ccalib/include/opencv2/ccalib/randpattern.hpp +++ b/modules/ccalib/include/opencv2/ccalib/randpattern.hpp @@ -43,6 +43,7 @@ #define __OPENCV_RANDOMPATTERN_HPP__ #include "opencv2/features2d.hpp" +#include "opencv2/xfeatures2d.hpp" #include "opencv2/highgui.hpp" namespace cv { namespace randpattern { @@ -79,8 +80,8 @@ class CV_EXPORTS RandomPatternCornerFinder */ RandomPatternCornerFinder(float patternWidth, float patternHeight, int nminiMatch = 20, int depth = CV_32F, int verbose = 0, int showExtraction = 0, - Ptr detector = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.005f), - Ptr descriptor = AKAZE::create(AKAZE::DESCRIPTOR_MLDB,0, 3, 0.005f), + Ptr detector = xfeatures2d::AKAZE::create(xfeatures2d::AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.005f), + Ptr descriptor = xfeatures2d::AKAZE::create(xfeatures2d::AKAZE::DESCRIPTOR_MLDB,0, 3, 0.005f), Ptr matcher = DescriptorMatcher::create("BruteForce-L1")); /* @brief Load pattern image and compute features for pattern diff --git a/modules/ccalib/src/precomp.hpp b/modules/ccalib/src/precomp.hpp index 53c58cdf618..9ab4181926d 100644 --- a/modules/ccalib/src/precomp.hpp +++ b/modules/ccalib/src/precomp.hpp @@ -47,6 +47,7 @@ #include #include #include +#include "opencv2/xfeatures2d.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" diff --git a/modules/xfeatures2d/doc/agast.txt b/modules/xfeatures2d/doc/agast.txt new file mode 100644 index 00000000000..737b0410e32 --- /dev/null +++ b/modules/xfeatures2d/doc/agast.txt @@ -0,0 +1,7701 @@ +/* This is AGAST and OAST, an optimal and accelerated corner detector + based on the accelerated segment tests + Below is the original copyright and the references */ + +/* +Copyright (C) 2010 Elmar Mair +All rights reserved. + +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. + + *Neither the name of the University of Cambridge nor the names of + its contributors may 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 COPYRIGHT OWNER 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. +*/ + +/* +The references are: + * Adaptive and Generic Corner Detection Based on the Accelerated Segment Test, + Elmar Mair and Gregory D. Hager and Darius Burschka + and Michael Suppa and Gerhard Hirzinger ECCV 2010 + URL: http://www6.in.tum.de/Main/ResearchAgast +*/ + +#include "precomp.hpp" +#include "agast_score.hpp" + +#ifdef _MSC_VER +#pragma warning( disable : 4127 ) +#endif + +namespace cv +{ + +static void AGAST_5_8(InputArray _img, std::vector& keypoints, int threshold) +{ + + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB = xsize - 2; + int ysizeB = ysize - 1; + int width; + + keypoints.resize(0); + + int pixel_5_8_[16]; + makeAgastOffsets(pixel_5_8_, (int)img.step, AgastFeatureDetector::AGAST_5_8); + + short offset0 = (short) pixel_5_8_[0]; + short offset1 = (short) pixel_5_8_[1]; + short offset2 = (short) pixel_5_8_[2]; + short offset3 = (short) pixel_5_8_[3]; + short offset4 = (short) pixel_5_8_[4]; + short offset5 = (short) pixel_5_8_[5]; + short offset6 = (short) pixel_5_8_[6]; + short offset7 = (short) pixel_5_8_[7]; + + width = xsize; + + for(y = 1; y < ysizeB; y++) + { + x = 0; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + goto structured; + } + } +} + +static void AGAST_7_12d(InputArray _img, std::vector& keypoints, int threshold) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB = xsize - 4; + int ysizeB = ysize - 3; + int width; + + keypoints.resize(0); + + int pixel_7_12d_[16]; + makeAgastOffsets(pixel_7_12d_, (int)img.step, AgastFeatureDetector::AGAST_7_12d); + + short offset0 = (short) pixel_7_12d_[0]; + short offset1 = (short) pixel_7_12d_[1]; + short offset2 = (short) pixel_7_12d_[2]; + short offset3 = (short) pixel_7_12d_[3]; + short offset4 = (short) pixel_7_12d_[4]; + short offset5 = (short) pixel_7_12d_[5]; + short offset6 = (short) pixel_7_12d_[6]; + short offset7 = (short) pixel_7_12d_[7]; + short offset8 = (short) pixel_7_12d_[8]; + short offset9 = (short) pixel_7_12d_[9]; + short offset10 = (short) pixel_7_12d_[10]; + short offset11 = (short) pixel_7_12d_[11]; + + width = xsize; + + for(y = 3; y < ysizeB; y++) + { + x = 2; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + if(ptr[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + goto structured; + } + } +} + +static void AGAST_7_12s(InputArray _img, std::vector& keypoints, int threshold) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB=xsize - 3; //2, +1 due to faster test x>xsizeB + int ysizeB=ysize - 2; + int width; + + keypoints.resize(0); + + int pixel_7_12s_[16]; + makeAgastOffsets(pixel_7_12s_, (int)img.step, AgastFeatureDetector::AGAST_7_12s); + + short offset0 = (short) pixel_7_12s_[0]; + short offset1 = (short) pixel_7_12s_[1]; + short offset2 = (short) pixel_7_12s_[2]; + short offset3 = (short) pixel_7_12s_[3]; + short offset4 = (short) pixel_7_12s_[4]; + short offset5 = (short) pixel_7_12s_[5]; + short offset6 = (short) pixel_7_12s_[6]; + short offset7 = (short) pixel_7_12s_[7]; + short offset8 = (short) pixel_7_12s_[8]; + short offset9 = (short) pixel_7_12s_[9]; + short offset10 = (short) pixel_7_12s_[10]; + short offset11 = (short) pixel_7_12s_[11]; + + width = xsize; + + for(y = 2; y < ysizeB; y++) + { + x = 1; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + goto structured; + } + } +} + +static void OAST_9_16(InputArray _img, std::vector& keypoints, int threshold) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB=xsize - 4; + int ysizeB=ysize - 3; + int width; + + keypoints.resize(0); + + int pixel_9_16_[16]; + makeAgastOffsets(pixel_9_16_, (int)img.step, AgastFeatureDetector::OAST_9_16); + + short offset0 = (short) pixel_9_16_[0]; + short offset1 = (short) pixel_9_16_[1]; + short offset2 = (short) pixel_9_16_[2]; + short offset3 = (short) pixel_9_16_[3]; + short offset4 = (short) pixel_9_16_[4]; + short offset5 = (short) pixel_9_16_[5]; + short offset6 = (short) pixel_9_16_[6]; + short offset7 = (short) pixel_9_16_[7]; + short offset8 = (short) pixel_9_16_[8]; + short offset9 = (short) pixel_9_16_[9]; + short offset10 = (short) pixel_9_16_[10]; + short offset11 = (short) pixel_9_16_[11]; + short offset12 = (short) pixel_9_16_[12]; + short offset13 = (short) pixel_9_16_[13]; + short offset14 = (short) pixel_9_16_[14]; + short offset15 = (short) pixel_9_16_[15]; + + width = xsize; + + for(y = 3; y < ysizeB; y++) + { + x = 2; + while(true) + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset14] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset12] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset14] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset10] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset12] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset10] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset12] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] > cb) + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset14] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset6] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset14] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset12] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + {} // goto success_homogeneous; + else + if(ptr[offset10] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + {} // goto success_homogeneous; + else + if(ptr[offset10] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} // goto success_homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + else + continue; // goto homogeneous; + } + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f)); + total++; + } + } +} + + +void AGAST(InputArray _img, std::vector& keypoints, int threshold, bool nonmax_suppression) +{ + AGAST(_img, keypoints, threshold, nonmax_suppression, AgastFeatureDetector::OAST_9_16); +} + + +class AgastFeatureDetector_Impl : public AgastFeatureDetector +{ +public: + AgastFeatureDetector_Impl( int _threshold, bool _nonmaxSuppression, int _type ) + : threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type((short)_type) + {} + + void detect( InputArray _image, std::vector& keypoints, InputArray _mask ) + { + Mat mask = _mask.getMat(), grayImage; + UMat ugrayImage; + _InputArray gray = _image; + if( _image.type() != CV_8U ) + { + _OutputArray ogray = _image.isUMat() ? _OutputArray(ugrayImage) : _OutputArray(grayImage); + cvtColor( _image, ogray, COLOR_BGR2GRAY ); + gray = ogray; + } + AGAST( gray, keypoints, threshold, nonmaxSuppression, type ); + KeyPointsFilter::runByPixelsMask( keypoints, mask ); + } + + void set(int prop, double value) + { + if(prop == THRESHOLD) + threshold = cvRound(value); + else if(prop == NONMAX_SUPPRESSION) + nonmaxSuppression = value != 0; + else + CV_Error(Error::StsBadArg, ""); + } + + double get(int prop) const + { + if(prop == THRESHOLD) + return threshold; + if(prop == NONMAX_SUPPRESSION) + return nonmaxSuppression; + CV_Error(Error::StsBadArg, ""); + return 0; + } + + void setThreshold(int threshold_) { threshold = threshold_; } + int getThreshold() const { return threshold; } + + void setNonmaxSuppression(bool f) { nonmaxSuppression = f; } + bool getNonmaxSuppression() const { return nonmaxSuppression; } + + void setType(int type_) { type = type_; } + int getType() const { return type; } + + int threshold; + bool nonmaxSuppression; + int type; +}; + +Ptr AgastFeatureDetector::create( int threshold, bool nonmaxSuppression, int type ) +{ + return makePtr(threshold, nonmaxSuppression, type); +} + +void AGAST(InputArray _img, std::vector& keypoints, int threshold, bool nonmax_suppression, int type) +{ + + std::vector kpts; + + // detect + switch(type) { + case AgastFeatureDetector::AGAST_5_8: + AGAST_5_8(_img, kpts, threshold); + break; + case AgastFeatureDetector::AGAST_7_12d: + AGAST_7_12d(_img, kpts, threshold); + break; + case AgastFeatureDetector::AGAST_7_12s: + AGAST_7_12s(_img, kpts, threshold); + break; + case AgastFeatureDetector::OAST_9_16: + OAST_9_16(_img, kpts, threshold); + break; + } + + cv::Mat img = _img.getMat(); + + // score + int pixel_[16]; + makeAgastOffsets(pixel_, (int)img.step, type); + + std::vector::iterator kpt; + for(kpt = kpts.begin(); kpt != kpts.end(); kpt++) + { + switch(type) { + case AgastFeatureDetector::AGAST_5_8: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + case AgastFeatureDetector::AGAST_7_12d: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + case AgastFeatureDetector::AGAST_7_12s: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + case AgastFeatureDetector::OAST_9_16: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + } + } + + // suppression + if(nonmax_suppression) + { + size_t j; + size_t curr_idx; + size_t lastRow = 0, next_lastRow = 0; + size_t num_Corners = kpts.size(); + size_t lastRowCorner_ind = 0, next_lastRowCorner_ind = 0; + + std::vector nmsFlags; + std::vector::iterator currCorner_nms; + std::vector::const_iterator currCorner; + + currCorner = kpts.begin(); + + nmsFlags.resize((int)num_Corners); + + // set all flags to MAXIMUM + for(j = 0; j < num_Corners; j++) + nmsFlags[j] = -1; + + for(curr_idx = 0; curr_idx < num_Corners; curr_idx++) + { + int t; + // check above + if(lastRow + 1 < currCorner->pt.y) + { + lastRow = next_lastRow; + lastRowCorner_ind = next_lastRowCorner_ind; + } + if(next_lastRow != currCorner->pt.y) + { + next_lastRow = (size_t) currCorner->pt.y; + next_lastRowCorner_ind = curr_idx; + } + if(lastRow + 1 == currCorner->pt.y) + { + // find the corner above the current one + while( (kpts[lastRowCorner_ind].pt.x < currCorner->pt.x) + && (kpts[lastRowCorner_ind].pt.y == lastRow) ) + lastRowCorner_ind++; + + if( (kpts[lastRowCorner_ind].pt.x == currCorner->pt.x) + && (lastRowCorner_ind != curr_idx) ) + { + size_t w = lastRowCorner_ind; + // find the maximum in this block + while(nmsFlags[w] != -1) + w = nmsFlags[w]; + + if(kpts[curr_idx].response < kpts[w].response) + nmsFlags[curr_idx] = (int)w; + else + nmsFlags[w] = (int)curr_idx; + } + } + + // check left + t = (int)curr_idx - 1; + if( (curr_idx != 0) && (kpts[t].pt.y == currCorner->pt.y) + && (kpts[t].pt.x + 1 == currCorner->pt.x) ) + { + int currCornerMaxAbove_ind = nmsFlags[curr_idx]; + // find the maximum in that area + while(nmsFlags[t] != -1) + t = nmsFlags[t]; + // no maximum above + if(currCornerMaxAbove_ind == -1) + { + if((size_t)t != curr_idx) + { + if ( kpts[curr_idx].response < kpts[t].response ) + nmsFlags[curr_idx] = t; + else + nmsFlags[t] = (int)curr_idx; + } + } + else // maximum above + { + if(t != currCornerMaxAbove_ind) + { + if(kpts[currCornerMaxAbove_ind].response < kpts[t].response) + { + nmsFlags[currCornerMaxAbove_ind] = t; + nmsFlags[curr_idx] = t; + } + else + { + nmsFlags[t] = currCornerMaxAbove_ind; + nmsFlags[curr_idx] = currCornerMaxAbove_ind; + } + } + } + } + currCorner++; + } + + // collecting maximum corners + for(curr_idx = 0; curr_idx < num_Corners; curr_idx++) + { + if (nmsFlags[curr_idx] == -1) + keypoints.push_back(kpts[curr_idx]); + } + } else + { + keypoints = kpts; + } +} + +} // END NAMESPACE CV diff --git a/modules/xfeatures2d/doc/agast_score.txt b/modules/xfeatures2d/doc/agast_score.txt new file mode 100644 index 00000000000..3c0b34741e5 --- /dev/null +++ b/modules/xfeatures2d/doc/agast_score.txt @@ -0,0 +1,9402 @@ +/* This is AGAST and OAST, an optimal and accelerated corner detector + based on the accelerated segment tests + Below is the original copyright and the references */ + +/* +Copyright (C) 2010 Elmar Mair +All rights reserved. + +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. + + *Neither the name of the University of Cambridge nor the names of + its contributors may 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 COPYRIGHT OWNER 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. +*/ + +/* +The references are: + * Adaptive and Generic Corner Detection Based on the Accelerated Segment Test, + Elmar Mair and Gregory D. Hager and Darius Burschka + and Michael Suppa and Gerhard Hirzinger ECCV 2010 + URL: http://www6.in.tum.de/Main/ResearchAgast +*/ + +#include "agast_score.hpp" + +#ifdef _MSC_VER +#pragma warning( disable : 4127 ) +#endif + +namespace cv +{ + +void makeAgastOffsets(int pixel[16], int rowStride, int type) +{ + static const int offsets16[][2] = + { + {-3, 0}, {-3, -1}, {-2, -2}, {-1, -3}, {0, -3}, { 1, -3}, { 2, -2}, { 3, -1}, + { 3, 0}, { 3, 1}, { 2, 2}, { 1, 3}, {0, 3}, {-1, 3}, {-2, 2}, {-3, 1} + }; + + static const int offsets12d[][2] = + { + {-3, 0}, {-2, -1}, {-1, -2}, {0, -3}, { 1, -2}, { 2, -1}, + { 3, 0}, { 2, 1}, { 1, 2}, {0, 3}, {-1, 2}, {-2, 1} + }; + + static const int offsets12s[][2] = + { + {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, { 1, -2}, { 2, -1}, + { 2, 0}, { 2, 1}, { 1, 2}, {0, 2}, {-1, 2}, {-2, 1} + }; + + static const int offsets8[][2] = + { + {-1, 0}, {-1, -1}, {0, -1}, { 1, -1}, + { 1, 0}, { 1, 1}, {0, 1}, {-1, 1} + }; + + const int (*offsets)[2] = type == AgastFeatureDetector::OAST_9_16 ? offsets16 : + type == AgastFeatureDetector::AGAST_7_12d ? offsets12d : + type == AgastFeatureDetector::AGAST_7_12s ? offsets12s : + type == AgastFeatureDetector::AGAST_5_8 ? offsets8 : 0; + + CV_Assert(pixel && offsets); + + int k = 0; + for( ; k < 16; k++ ) + pixel[k] = offsets[k][0] + offsets[k][1] * rowStride; +} + +// 16 pixel mask +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin) / 2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + short offset8 = (short) pixel[8]; + short offset9 = (short) pixel[9]; + short offset10 = (short) pixel[10]; + short offset11 = (short) pixel[11]; + short offset12 = (short) pixel[12]; + short offset13 = (short) pixel[13]; + short offset14 = (short) pixel[14]; + short offset15 = (short) pixel[15]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + goto is_a_corner; + else + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] > cb) + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset14] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + goto is_a_corner; + else + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin = b_test; + goto end; + + is_not_a_corner: + bmax = b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +// 12 pixel mask in diamond format +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + short offset8 = (short) pixel[8]; + short offset9 = (short) pixel[9]; + short offset10 = (short) pixel[10]; + short offset11 = (short) pixel[11]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin = b_test; + goto end; + + is_not_a_corner: + bmax = b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +//12 pixel mask in square format +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + short offset8 = (short) pixel[8]; + short offset9 = (short) pixel[9]; + short offset10 = (short) pixel[10]; + short offset11 = (short) pixel[11]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset2] < c_b) + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset0] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] > cb) + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset2] < c_b) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin = b_test; + goto end; + + is_not_a_corner: + bmax = b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +// 8 pixel mask +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin=b_test; + goto end; + + is_not_a_corner: + bmax=b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +} // namespace cv diff --git a/modules/xfeatures2d/doc/read_file_nondiff32.pl b/modules/xfeatures2d/doc/read_file_nondiff32.pl new file mode 100644 index 00000000000..2ada4c9ea21 --- /dev/null +++ b/modules/xfeatures2d/doc/read_file_nondiff32.pl @@ -0,0 +1,284 @@ +#!/usr/bin/perl +use strict; +use warnings; +use autodie; # die if problem reading or writing a file + +my $filein = "./agast.txt"; +my $fileout = "./agast_new.txt"; +my $i1=1; +my $i2=1; +my $i3=1; +my $tmp; +my $ifcount0=0; +my $ifcount1=0; +my $ifcount2=0; +my $ifcount3=0; +my $ifcount4=0; +my $elsecount; +my $myfirstline = $ARGV[0]; +my $mylastline = $ARGV[1]; +my $tablename = $ARGV[2]; +my @array0 = (); +my @array1 = (); +my @array2 = (); +my @array3 = (); +my $homogeneous; +my $success_homogeneous; +my $structured; +my $success_structured; + + open(my $in1, "<", $filein) or die "Can't open $filein: $!"; + open(my $out, ">", $fileout) or die "Can't open $fileout: $!"; + + + $array0[0] = 0; + $i1=1; + while (my $line1 = <$in1>) + { + chomp $line1; + $array0[$i1] = 0; + if (($i1>=$myfirstline)&&($i1<=$mylastline)) + { + if($line1=~/if\(ptr\[offset(\d+)/) + { + if($line1=~/if\(ptr\[offset(\d+).*\>.*cb/) + { + $tmp=$1; + } + else + { + if($line1=~/if\(ptr\[offset(\d+).*\<.*c\_b/) + { + $tmp=$1+128; + } + else + { + die "invalid array index!" + } + } + $array1[$ifcount1] = $tmp; + $array0[$ifcount1] = $i1; + $ifcount1++; + } + else + { + } + } + $i1++; + } + $homogeneous=$ifcount1; + $success_homogeneous=$ifcount1+1; + $structured=$ifcount1+2; + $success_structured=$ifcount1+3; + + close $in1 or die "Can't close $filein: $!"; + + open($in1, "<", $filein) or die "Can't open $filein: $!"; + + + $i1=1; + while (my $line1 = <$in1>) + { + chomp $line1; + if (($i1>=$myfirstline)&&($i1<=$mylastline)) + { + if ($array0[$ifcount2] == $i1) + { + $array2[$ifcount2]=0; + $array3[$ifcount2]=0; + if ($array0[$ifcount2+1] == ($i1+1)) + { + $array2[$ifcount2]=($ifcount2+1); + } + else + { + open(my $in2, "<", $filein) or die "Can't open $filein: $!"; + $i2=1; + while (my $line2 = <$in2>) + { + chomp $line2; + if ($i2 == $i1) + { + last; + } + $i2++; + } + my $line2 = <$in2>; + chomp $line2; + if ($line2=~/goto (\w+)/) + { + $tmp=$1; + if ($tmp eq "homogeneous") + { + $array2[$ifcount2]=$homogeneous; + } + if ($tmp eq "success_homogeneous") + { + $array2[$ifcount2]=$success_homogeneous; + } + if ($tmp eq "structured") + { + $array2[$ifcount2]=$structured; + } + if ($tmp eq "success_structured") + { + $array2[$ifcount2]=$success_structured; + } + } + else + { + die "goto expected: $!"; + } + close $in2 or die "Can't close $filein: $!"; + } + #find next else and interpret it + open(my $in3, "<", $filein) or die "Can't open $filein: $!"; + $i3=1; + $ifcount3=0; + $elsecount=0; + while (my $line3 = <$in3>) + { + chomp $line3; + $i3++; + if ($i3 == $i1) + { + last; + } + } + while (my $line3 = <$in3>) + { + chomp $line3; + $ifcount3++; + if (($elsecount==0)&&($i3>$i1)) + { + if ($line3=~/goto (\w+)/) + { + $tmp=$1; + if ($tmp eq "homogeneous") + { + $array3[$ifcount2]=$homogeneous; + } + if ($tmp eq "success_homogeneous") + { + $array3[$ifcount2]=$success_homogeneous; + } + if ($tmp eq "structured") + { + $array3[$ifcount2]=$structured; + } + if ($tmp eq "success_structured") + { + $array3[$ifcount2]=$success_structured; + } + } + else + { + if ($line3=~/if\(ptr\[offset/) + { + $ifcount4=0; + while ($array0[$ifcount4]!=$i3) + { + $ifcount4++; + if ($ifcount4==$ifcount1) + { + die "if else match expected: $!"; + } + $array3[$ifcount2]=$ifcount4; + } + } + else + { + die "elseif or elsegoto match expected: $!"; + } + } + last; + } + else + { + if ($line3=~/if\(ptr\[offset/) + { + $elsecount++; + } + else + { + if ($line3=~/else/) + { + $elsecount--; + } + } + } + $i3++; + } + printf("%3d [%3d][0x%08x]\n", $array0[$ifcount2], $ifcount2, (($array1[$ifcount2]&15)<<28)|($array2[$ifcount2]<<16)|(($array1[$ifcount2]&128)<<5)|($array3[$ifcount2])); + close $in3 or die "Can't close $filein: $!"; + $ifcount2++; + } + else + { + } + } + $i1++; + } + + printf(" [%3d][0x%08x]\n", $homogeneous, 252); + printf(" [%3d][0x%08x]\n", $success_homogeneous, 253); + printf(" [%3d][0x%08x]\n", $structured, 254); + printf(" [%3d][0x%08x]\n", $success_structured, 255); + + close $in1 or die "Can't close $filein: $!"; + + $ifcount0=0; + $ifcount2=0; + printf $out " static const unsigned long %s[] = {\n ", $tablename; + while ($ifcount0 < $ifcount1) + { + printf $out "0x%08x, ", (($array1[$ifcount0]&15)<<28)|($array2[$ifcount0]<<16)|(($array1[$ifcount0]&128)<<5)|($array3[$ifcount0]); + + $ifcount0++; + $ifcount2++; + if ($ifcount2==8) + { + $ifcount2=0; + printf $out "\n"; + printf $out " "; + } + + } + printf $out "0x%08x, ", 252; + $ifcount0++; + $ifcount2++; + if ($ifcount2==8) + { + $ifcount2=0; + printf $out "\n"; + printf $out " "; + } + printf $out "0x%08x, ", 253; + $ifcount0++; + $ifcount2++; + if ($ifcount2==8) + { + $ifcount2=0; + printf $out "\n"; + printf $out " "; + } + printf $out "0x%08x, ", 254; + $ifcount0++; + $ifcount2++; + if ($ifcount2==8) + { + $ifcount2=0; + printf $out "\n"; + printf $out " "; + } + printf $out "0x%08x\n", 255; + $ifcount0++; + $ifcount2++; + printf $out " };\n\n"; + + $#array0 = -1; + $#array1 = -1; + $#array2 = -1; + $#array3 = -1; + + close $out or die "Can't close $fileout: $!"; diff --git a/modules/xfeatures2d/doc/read_file_score32.pl b/modules/xfeatures2d/doc/read_file_score32.pl new file mode 100644 index 00000000000..10cb77d0809 --- /dev/null +++ b/modules/xfeatures2d/doc/read_file_score32.pl @@ -0,0 +1,244 @@ +#!/usr/bin/perl +use strict; +use warnings; +use autodie; # die if problem reading or writing a file + +my $filein = "./agast_score.txt"; +my $fileout = "./agast_new.txt"; +my $i1=1; +my $i2=1; +my $i3=1; +my $tmp; +my $ifcount0=0; +my $ifcount1=0; +my $ifcount2=0; +my $ifcount3=0; +my $ifcount4=0; +my $elsecount; +my $myfirstline = $ARGV[0]; +my $mylastline = $ARGV[1]; +my $tablename = $ARGV[2]; +my @array0 = (); +my @array1 = (); +my @array2 = (); +my @array3 = (); +my $is_not_a_corner; +my $is_a_corner; + + open(my $in1, "<", $filein) or die "Can't open $filein: $!"; + open(my $out, ">", $fileout) or die "Can't open $fileout: $!"; + + + $array0[0] = 0; + $i1=1; + while (my $line1 = <$in1>) + { + chomp $line1; + $array0[$i1] = 0; + if (($i1>=$myfirstline)&&($i1<=$mylastline)) + { + if($line1=~/if\(ptr\[offset(\d+)/) + { + if($line1=~/if\(ptr\[offset(\d+).*\>.*cb/) + { + $tmp=$1; + } + else + { + if($line1=~/if\(ptr\[offset(\d+).*\<.*c\_b/) + { + $tmp=$1+128; + } + else + { + die "invalid array index!" + } + } + $array1[$ifcount1] = $tmp; + $array0[$ifcount1] = $i1; + $ifcount1++; + } + else + { + } + } + $i1++; + } + $is_not_a_corner=$ifcount1; + $is_a_corner=$ifcount1+1; + + close $in1 or die "Can't close $filein: $!"; + + open($in1, "<", $filein) or die "Can't open $filein: $!"; + + + $i1=1; + while (my $line1 = <$in1>) + { + chomp $line1; + if (($i1>=$myfirstline)&&($i1<=$mylastline)) + { + if ($array0[$ifcount2] == $i1) + { + $array2[$ifcount2]=0; + $array3[$ifcount2]=0; + if ($array0[$ifcount2+1] == ($i1+1)) + { + $array2[$ifcount2]=($ifcount2+1); + } + else + { + open(my $in2, "<", $filein) or die "Can't open $filein: $!"; + $i2=1; + while (my $line2 = <$in2>) + { + chomp $line2; + if ($i2 == $i1) + { + last; + } + $i2++; + } + my $line2 = <$in2>; + chomp $line2; + if ($line2=~/goto (\w+)/) + { + $tmp=$1; + if ($tmp eq "is_not_a_corner") + { + $array2[$ifcount2]=$is_not_a_corner; + } + if ($tmp eq "is_a_corner") + { + $array2[$ifcount2]=$is_a_corner; + } + } + else + { + die "goto expected: $!"; + } + close $in2 or die "Can't close $filein: $!"; + } + #find next else and interpret it + open(my $in3, "<", $filein) or die "Can't open $filein: $!"; + $i3=1; + $ifcount3=0; + $elsecount=0; + while (my $line3 = <$in3>) + { + chomp $line3; + $i3++; + if ($i3 == $i1) + { + last; + } + } + while (my $line3 = <$in3>) + { + chomp $line3; + $ifcount3++; + if (($elsecount==0)&&($i3>$i1)) + { + if ($line3=~/goto (\w+)/) + { + $tmp=$1; + if ($tmp eq "is_not_a_corner") + { + $array3[$ifcount2]=$is_not_a_corner; + } + if ($tmp eq "is_a_corner") + { + $array3[$ifcount2]=$is_a_corner; + } + } + else + { + if ($line3=~/if\(ptr\[offset/) + { + $ifcount4=0; + while ($array0[$ifcount4]!=$i3) + { + $ifcount4++; + if ($ifcount4==$ifcount1) + { + die "if else match expected: $!"; + } + $array3[$ifcount2]=$ifcount4; + } + } + else + { + die "elseif or elsegoto match expected: $!"; + } + } + last; + } + else + { + if ($line3=~/if\(ptr\[offset/) + { + $elsecount++; + } + else + { + if ($line3=~/else/) + { + $elsecount--; + } + } + } + $i3++; + } + printf("%3d [%3d][0x%08x]\n", $array0[$ifcount2], $ifcount2, (($array1[$ifcount2]&15)<<28)|($array2[$ifcount2]<<16)|(($array1[$ifcount2]&128)<<5)|($array3[$ifcount2])); + close $in3 or die "Can't close $filein: $!"; + $ifcount2++; + } + else + { + } + } + $i1++; + } + + printf(" [%3d][0x%08x]\n", $is_not_a_corner, 254); + printf(" [%3d][0x%08x]\n", $is_a_corner, 255); + + close $in1 or die "Can't close $filein: $!"; + + $ifcount0=0; + $ifcount2=0; + printf $out " static const unsigned long %s[] = {\n ", $tablename; + while ($ifcount0 < $ifcount1) + { + printf $out "0x%08x, ", (($array1[$ifcount0]&15)<<28)|($array2[$ifcount0]<<16)|(($array1[$ifcount0]&128)<<5)|($array3[$ifcount0]); + + $ifcount0++; + $ifcount2++; + if ($ifcount2==8) + { + $ifcount2=0; + printf $out "\n"; + printf $out " "; + } + + } + printf $out "0x%08x, ", 254; + $ifcount0++; + $ifcount2++; + if ($ifcount2==8) + { + $ifcount2=0; + printf $out "\n"; + printf $out " "; + } + printf $out "0x%08x\n", 255; + $ifcount0++; + $ifcount2++; + printf $out " };\n\n"; + + $#array0 = -1; + $#array1 = -1; + $#array2 = -1; + $#array3 = -1; + + close $out or die "Can't close $fileout: $!"; diff --git a/modules/xfeatures2d/doc/run_agast_tables.bat b/modules/xfeatures2d/doc/run_agast_tables.bat new file mode 100644 index 00000000000..004aeca7262 --- /dev/null +++ b/modules/xfeatures2d/doc/run_agast_tables.bat @@ -0,0 +1,32 @@ +perl read_file_score32.pl 9059 9385 table_5_8_corner_struct +move agast_new.txt agast_score_table.txt +perl read_file_score32.pl 2215 3387 table_7_12d_corner_struct +copy /A agast_score_table.txt + agast_new.txt agast_score_table.txt +del agast_new.txt +perl read_file_score32.pl 3428 9022 table_7_12s_corner_struct +copy /A agast_score_table.txt + agast_new.txt agast_score_table.txt +del agast_new.txt +perl read_file_score32.pl 118 2174 table_9_16_corner_struct +copy /A agast_score_table.txt + agast_new.txt agast_score_table.txt +del agast_new.txt + +perl read_file_nondiff32.pl 103 430 table_5_8_struct1 +move agast_new.txt agast_table.txt +perl read_file_nondiff32.pl 440 779 table_5_8_struct2 +copy /A agast_table.txt + agast_new.txt agast_table.txt +del agast_new.txt +perl read_file_nondiff32.pl 869 2042 table_7_12d_struct1 +copy /A agast_table.txt + agast_new.txt agast_table.txt +del agast_new.txt +perl read_file_nondiff32.pl 2052 3225 table_7_12d_struct2 +copy /A agast_table.txt + agast_new.txt agast_table.txt +del agast_new.txt +perl read_file_nondiff32.pl 3315 4344 table_7_12s_struct1 +copy /A agast_table.txt + agast_new.txt agast_table.txt +del agast_new.txt +perl read_file_nondiff32.pl 4354 5308 table_7_12s_struct2 +copy /A agast_table.txt + agast_new.txt agast_table.txt +del agast_new.txt +perl read_file_nondiff32.pl 5400 7454 table_9_16_struct +copy /A agast_table.txt + agast_new.txt agast_table.txt +del agast_new.txt diff --git a/modules/xfeatures2d/doc/xfeatures2d.bib b/modules/xfeatures2d/doc/xfeatures2d.bib index 7d3f146cb94..82836369ea3 100644 --- a/modules/xfeatures2d/doc/xfeatures2d.bib +++ b/modules/xfeatures2d/doc/xfeatures2d.bib @@ -172,4 +172,23 @@ @inproceedings{winder2007learning booktitle= {Computer Vision and Pattern Recognition}, pages={1--8}, year={2007}, +} + +@incollection{ABD12, + author = {Alcantarilla, Pablo Fern{\'a}ndez and Bartoli, Adrien and Davison, Andrew J}, + title = {KAZE features}, + booktitle = {Computer Vision--ECCV 2012}, + year = {2012}, + pages = {214--227}, + publisher = {Springer}, + url = {https://www.doc.ic.ac.uk/~ajd/Publications/alcantarilla_etal_eccv2012.pdf} +} + +@inproceedings{LCS11, + author = {Leutenegger, Stefan and Chli, Margarita and Siegwart, Roland Yves}, + title = {BRISK: Binary robust invariant scalable keypoints}, + booktitle = {Computer Vision (ICCV), 2011 IEEE International Conference on}, + year = {2011}, + pages = {2548--2555}, + publisher = {IEEE} } \ No newline at end of file diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp index e16566f603c..7a51572168a 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp @@ -58,6 +58,10 @@ the use of this software, even if advised of the possibility of such damage. This section describes the following matching strategies: - GMS: Grid-based Motion Statistics, @cite Bian2017gms - LOGOS: Local geometric support for high-outlier spatial verification, @cite Lowry2018LOGOSLG + + @defgroup xfeatures2d_category Object Categorization + + This section describes approaches based on local 2D features and used to categorize objects. @} */ @@ -1211,6 +1215,251 @@ class CV_EXPORTS_W TBMR : public AffineFeature2D CV_WRAP virtual int getNScales() const = 0; }; +/** @brief Class implementing the BRISK keypoint detector and descriptor extractor, described in @cite LCS11 . + */ +class CV_EXPORTS_W BRISK : public Feature2D +{ +public: + /** @brief The BRISK constructor + + @param thresh AGAST detection threshold score. + @param octaves detection octaves. Use 0 to do single scale. + @param patternScale apply this scale to the pattern used for sampling the neighbourhood of a + keypoint. + */ + CV_WRAP static Ptr create(int thresh=30, int octaves=3, float patternScale=1.0f); + + /** @brief The BRISK constructor for a custom pattern + + @param radiusList defines the radii (in pixels) where the samples around a keypoint are taken (for + keypoint scale 1). + @param numberList defines the number of sampling points on the sampling circle. Must be the same + size as radiusList.. + @param dMax threshold for the short pairings used for descriptor formation (in pixels for keypoint + scale 1). + @param dMin threshold for the long pairings used for orientation determination (in pixels for + keypoint scale 1). + @param indexChange index remapping of the bits. */ + CV_WRAP static Ptr create(const std::vector &radiusList, const std::vector &numberList, + float dMax=5.85f, float dMin=8.2f, const std::vector& indexChange=std::vector()); + + /** @brief The BRISK constructor for a custom pattern, detection threshold and octaves + + @param thresh AGAST detection threshold score. + @param octaves detection octaves. Use 0 to do single scale. + @param radiusList defines the radii (in pixels) where the samples around a keypoint are taken (for + keypoint scale 1). + @param numberList defines the number of sampling points on the sampling circle. Must be the same + size as radiusList.. + @param dMax threshold for the short pairings used for descriptor formation (in pixels for keypoint + scale 1). + @param dMin threshold for the long pairings used for orientation determination (in pixels for + keypoint scale 1). + @param indexChange index remapping of the bits. */ + CV_WRAP static Ptr create(int thresh, int octaves, const std::vector &radiusList, + const std::vector &numberList, float dMax=5.85f, float dMin=8.2f, + const std::vector& indexChange=std::vector()); + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; + + /** @brief Set detection threshold. + @param threshold AGAST detection threshold score. + */ + CV_WRAP virtual void setThreshold(int threshold) = 0; + CV_WRAP virtual int getThreshold() const = 0; + + /** @brief Set detection octaves. + @param octaves detection octaves. Use 0 to do single scale. + */ + CV_WRAP virtual void setOctaves(int octaves) = 0; + CV_WRAP virtual int getOctaves() const = 0; + /** @brief Set detection patternScale. + @param patternScale apply this scale to the pattern used for sampling the neighbourhood of a + keypoint. + */ + CV_WRAP virtual void setPatternScale(float patternScale) = 0; + CV_WRAP virtual float getPatternScale() const = 0; +}; + +/** @brief Wrapping class for feature detection using the AGAST method. : + */ +class CV_EXPORTS_W AgastFeatureDetector : public Feature2D +{ +public: + enum //DetectorType + { + AGAST_5_8 = 0, AGAST_7_12d = 1, AGAST_7_12s = 2, OAST_9_16 = 3, + }; + typedef int DetectorType; + + enum + { + THRESHOLD = 10000, NONMAX_SUPPRESSION = 10001, + }; + + CV_WRAP static Ptr create( int threshold=10, + bool nonmaxSuppression=true, + int type = AgastFeatureDetector::OAST_9_16); + + CV_WRAP virtual void setThreshold(int threshold) = 0; + CV_WRAP virtual int getThreshold() const = 0; + + CV_WRAP virtual void setNonmaxSuppression(bool f) = 0; + CV_WRAP virtual bool getNonmaxSuppression() const = 0; + + CV_WRAP virtual void setType(int type) = 0; + CV_WRAP virtual int getType() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @brief Detects corners using the AGAST algorithm + +@param image grayscale image where keypoints (corners) are detected. +@param keypoints keypoints detected on the image. +@param threshold threshold on difference between intensity of the central pixel and pixels of a +circle around this pixel. +@param nonmaxSuppression if true, non-maximum suppression is applied to detected keypoints (corners). +@param type one of the four neighborhoods as defined in the paper: +AgastFeatureDetector::AGAST_5_8, AgastFeatureDetector::AGAST_7_12d, +AgastFeatureDetector::AGAST_7_12s, AgastFeatureDetector::OAST_9_16 + +For non-Intel platforms, there is a tree optimised variant of AGAST with same numerical results. +The 32-bit binary tree tables were generated automatically from original code using perl script. +The perl script and examples of tree generation are placed in features2d/doc folder. +Detects corners using the AGAST algorithm by @cite mair2010_agast . + + */ +CV_EXPORTS void AGAST( InputArray image, CV_OUT std::vector& keypoints, + int threshold, bool nonmaxSuppression=true, AgastFeatureDetector::DetectorType type=AgastFeatureDetector::OAST_9_16 ); + +/** @brief Class implementing the KAZE keypoint detector and descriptor extractor, described in @cite ABD12 . + +@note AKAZE descriptor can only be used with KAZE or AKAZE keypoints .. [ABD12] KAZE Features. Pablo +F. Alcantarilla, Adrien Bartoli and Andrew J. Davison. In European Conference on Computer Vision +(ECCV), Fiorenze, Italy, October 2012. +*/ +class CV_EXPORTS_W KAZE : public Feature2D +{ +public: + enum //DiffusivityType + { + DIFF_PM_G1 = 0, + DIFF_PM_G2 = 1, + DIFF_WEICKERT = 2, + DIFF_CHARBONNIER = 3 + }; + typedef int DiffusivityType; + + /** @brief The KAZE constructor + + @param extended Set to enable extraction of extended (128-byte) descriptor. + @param upright Set to enable use of upright descriptors (non rotation-invariant). + @param threshold Detector response threshold to accept point + @param nOctaves Maximum octave evolution of the image + @param nOctaveLayers Default number of sublevels per scale level + @param diffusivity Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or + DIFF_CHARBONNIER + */ + CV_WRAP static Ptr create(bool extended=false, bool upright=false, + float threshold = 0.001f, + int nOctaves = 4, int nOctaveLayers = 4, + int diffusivity = KAZE::DIFF_PM_G2); + + CV_WRAP virtual void setExtended(bool extended) = 0; + CV_WRAP virtual bool getExtended() const = 0; + + CV_WRAP virtual void setUpright(bool upright) = 0; + CV_WRAP virtual bool getUpright() const = 0; + + CV_WRAP virtual void setThreshold(double threshold) = 0; + CV_WRAP virtual double getThreshold() const = 0; + + CV_WRAP virtual void setNOctaves(int octaves) = 0; + CV_WRAP virtual int getNOctaves() const = 0; + + CV_WRAP virtual void setNOctaveLayers(int octaveLayers) = 0; + CV_WRAP virtual int getNOctaveLayers() const = 0; + + CV_WRAP virtual void setDiffusivity(int diff) = 0; + CV_WRAP virtual int getDiffusivity() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @brief Class implementing the AKAZE keypoint detector and descriptor extractor, described in @cite ANB13. + +@details AKAZE descriptors can only be used with KAZE or AKAZE keypoints. This class is thread-safe. + +@note When you need descriptors use Feature2D::detectAndCompute, which +provides better performance. When using Feature2D::detect followed by +Feature2D::compute scale space pyramid is computed twice. + +@note AKAZE implements T-API. When image is passed as UMat some parts of the algorithm +will use OpenCL. + +@note [ANB13] Fast Explicit Diffusion for Accelerated Features in Nonlinear +Scale Spaces. Pablo F. Alcantarilla, Jesús Nuevo and Adrien Bartoli. In +British Machine Vision Conference (BMVC), Bristol, UK, September 2013. + +*/ +class CV_EXPORTS_W AKAZE : public Feature2D +{ +public: + // AKAZE descriptor type + enum //DescriptorType + { + DESCRIPTOR_KAZE_UPRIGHT = 2, ///< Upright descriptors, not invariant to rotation + DESCRIPTOR_KAZE = 3, + DESCRIPTOR_MLDB_UPRIGHT = 4, ///< Upright descriptors, not invariant to rotation + DESCRIPTOR_MLDB = 5 + }; + typedef int DescriptorType; + + /** @brief The AKAZE constructor + + @param descriptor_type Type of the extracted descriptor: DESCRIPTOR_KAZE, + DESCRIPTOR_KAZE_UPRIGHT, DESCRIPTOR_MLDB or DESCRIPTOR_MLDB_UPRIGHT. + @param descriptor_size Size of the descriptor in bits. 0 -\> Full size + @param descriptor_channels Number of channels in the descriptor (1, 2, 3) + @param threshold Detector response threshold to accept point + @param nOctaves Maximum octave evolution of the image + @param nOctaveLayers Default number of sublevels per scale level + @param diffusivity Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or + DIFF_CHARBONNIER + @param max_points Maximum amount of returned points. In case if image contains + more features, then the features with highest response are returned. + Negative value means no limitation. + */ + CV_WRAP static Ptr create(int descriptor_type = AKAZE::DESCRIPTOR_MLDB, + int descriptor_size = 0, int descriptor_channels = 3, + float threshold = 0.001f, int nOctaves = 4, + int nOctaveLayers = 4, int diffusivity = KAZE::DIFF_PM_G2, + int max_points = -1); + + CV_WRAP virtual void setDescriptorType(int dtype) = 0; + CV_WRAP virtual int getDescriptorType() const = 0; + + CV_WRAP virtual void setDescriptorSize(int dsize) = 0; + CV_WRAP virtual int getDescriptorSize() const = 0; + + CV_WRAP virtual void setDescriptorChannels(int dch) = 0; + CV_WRAP virtual int getDescriptorChannels() const = 0; + + CV_WRAP virtual void setThreshold(double threshold) = 0; + CV_WRAP virtual double getThreshold() const = 0; + + CV_WRAP virtual void setNOctaves(int octaves) = 0; + CV_WRAP virtual int getNOctaves() const = 0; + + CV_WRAP virtual void setNOctaveLayers(int octaveLayers) = 0; + CV_WRAP virtual int getNOctaveLayers() const = 0; + + CV_WRAP virtual void setDiffusivity(int diff) = 0; + CV_WRAP virtual int getDiffusivity() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; + + CV_WRAP virtual void setMaxPoints(int max_points) = 0; + CV_WRAP virtual int getMaxPoints() const = 0; +}; + /** @brief Estimates cornerness for prespecified KeyPoints using the FAST algorithm @param image grayscale image where keypoints (corners) are detected. @@ -1272,6 +1521,166 @@ CV_EXPORTS_W void matchLOGOS(const std::vector& keypoints1, const std: //! @} +/****************************************************************************************\ +* Bag of visual words * +\****************************************************************************************/ + +//! @addtogroup xfeatures2d_category +//! @{ + +/** @brief Abstract base class for training the *bag of visual words* vocabulary from a set of descriptors. + +For details, see, for example, *Visual Categorization with Bags of Keypoints* by Gabriella Csurka, +Christopher R. Dance, Lixin Fan, Jutta Willamowski, Cedric Bray, 2004. : + */ +class CV_EXPORTS_W BOWTrainer +{ +public: + BOWTrainer(); + virtual ~BOWTrainer(); + + /** @brief Adds descriptors to a training set. + + @param descriptors Descriptors to add to a training set. Each row of the descriptors matrix is a + descriptor. + + The training set is clustered using clustermethod to construct the vocabulary. + */ + CV_WRAP void add( const Mat& descriptors ); + + /** @brief Returns a training set of descriptors. + */ + CV_WRAP const std::vector& getDescriptors() const; + + /** @brief Returns the count of all descriptors stored in the training set. + */ + CV_WRAP int descriptorsCount() const; + + CV_WRAP virtual void clear(); + + /** @overload */ + CV_WRAP virtual Mat cluster() const = 0; + + /** @brief Clusters train descriptors. + + @param descriptors Descriptors to cluster. Each row of the descriptors matrix is a descriptor. + Descriptors are not added to the inner train descriptor set. + + The vocabulary consists of cluster centers. So, this method returns the vocabulary. In the first + variant of the method, train descriptors stored in the object are clustered. In the second variant, + input descriptors are clustered. + */ + CV_WRAP virtual Mat cluster( const Mat& descriptors ) const = 0; + +protected: + std::vector descriptors; + int size; +}; + +/** @brief kmeans -based class to train visual vocabulary using the *bag of visual words* approach. : + */ +class CV_EXPORTS_W BOWKMeansTrainer : public BOWTrainer +{ +public: + /** @brief The constructor. + + @see cv::kmeans + */ + CV_WRAP BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(), + int attempts=3, int flags=KMEANS_PP_CENTERS ); + virtual ~BOWKMeansTrainer(); + + // Returns trained vocabulary (i.e. cluster centers). + CV_WRAP virtual Mat cluster() const CV_OVERRIDE; + CV_WRAP virtual Mat cluster( const Mat& descriptors ) const CV_OVERRIDE; + +protected: + + int clusterCount; + TermCriteria termcrit; + int attempts; + int flags; +}; + +/** @brief Class to compute an image descriptor using the *bag of visual words*. + +Such a computation consists of the following steps: + +1. Compute descriptors for a given image and its keypoints set. +2. Find the nearest visual words from the vocabulary for each keypoint descriptor. +3. Compute the bag-of-words image descriptor as is a normalized histogram of vocabulary words +encountered in the image. The i-th bin of the histogram is a frequency of i-th word of the +vocabulary in the given image. + */ +class CV_EXPORTS_W BOWImgDescriptorExtractor +{ +public: + /** @brief The constructor. + + @param dextractor Descriptor extractor that is used to compute descriptors for an input image and + its keypoints. + @param dmatcher Descriptor matcher that is used to find the nearest word of the trained vocabulary + for each keypoint descriptor of the image. + */ + CV_WRAP BOWImgDescriptorExtractor( const Ptr& dextractor, + const Ptr& dmatcher ); + /** @overload */ + BOWImgDescriptorExtractor( const Ptr& dmatcher ); + virtual ~BOWImgDescriptorExtractor(); + + /** @brief Sets a visual vocabulary. + + @param vocabulary Vocabulary (can be trained using the inheritor of BOWTrainer ). Each row of the + vocabulary is a visual word (cluster center). + */ + CV_WRAP void setVocabulary( const Mat& vocabulary ); + + /** @brief Returns the set vocabulary. + */ + CV_WRAP const Mat& getVocabulary() const; + + /** @brief Computes an image descriptor using the set visual vocabulary. + + @param image Image, for which the descriptor is computed. + @param keypoints Keypoints detected in the input image. + @param imgDescriptor Computed output image descriptor. + @param pointIdxsOfClusters Indices of keypoints that belong to the cluster. This means that + pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster (word of vocabulary) + returned if it is non-zero. + @param descriptors Descriptors of the image keypoints that are returned if they are non-zero. + */ + void compute( InputArray image, std::vector& keypoints, OutputArray imgDescriptor, + std::vector >* pointIdxsOfClusters=0, Mat* descriptors=0 ); + /** @overload + @param keypointDescriptors Computed descriptors to match with vocabulary. + @param imgDescriptor Computed output image descriptor. + @param pointIdxsOfClusters Indices of keypoints that belong to the cluster. This means that + pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster (word of vocabulary) + returned if it is non-zero. + */ + void compute( InputArray keypointDescriptors, OutputArray imgDescriptor, + std::vector >* pointIdxsOfClusters=0 ); + // compute() is not constant because DescriptorMatcher::match is not constant + + CV_WRAP_AS(compute) void compute2( const Mat& image, std::vector& keypoints, CV_OUT Mat& imgDescriptor ) + { compute(image,keypoints,imgDescriptor); } + + /** @brief Returns an image descriptor size if the vocabulary is set. Otherwise, it returns 0. + */ + CV_WRAP int descriptorSize() const; + + /** @brief Returns an image descriptor type. + */ + CV_WRAP int descriptorType() const; + +protected: + Mat vocabulary; + Ptr dextractor; + Ptr dmatcher; +}; + +//! @} xfeatures2d_category + } } diff --git a/modules/xfeatures2d/misc/java/test/AGASTFeatureDetectorTest.java b/modules/xfeatures2d/misc/java/test/AGASTFeatureDetectorTest.java new file mode 100644 index 00000000000..eaaf73ad445 --- /dev/null +++ b/modules/xfeatures2d/misc/java/test/AGASTFeatureDetectorTest.java @@ -0,0 +1,85 @@ +package org.opencv.test.features2d; + +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; +import org.opencv.xfeatures2d.AgastFeatureDetector; + +public class AGASTFeatureDetectorTest extends OpenCVTestCase { + + AgastFeatureDetector detector; + + @Override + protected void setUp() throws Exception { + super.setUp(); + detector = AgastFeatureDetector.create(); // default (10,true,3) + } + + public void testCreate() { + assertNotNull(detector); + } + + public void testDetectListOfMatListOfListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectListOfMatListOfListOfKeyPointListOfMat() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPointMat() { + fail("Not yet implemented"); + } + + public void testEmpty() { + fail("Not yet implemented"); + } + + public void testRead() { + String filename = OpenCVTestRunner.getTempFileName("xml"); + writeFile(filename, "\n\nFeature2D.AgastFeatureDetector\n11\n0\n2\n\n"); + + detector.read(filename); + + assertEquals(11, detector.getThreshold()); + assertEquals(false, detector.getNonmaxSuppression()); + assertEquals(2, detector.getType()); + } + + public void testReadYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + writeFile(filename, "%YAML:1.0\n---\nname: \"Feature2D.AgastFeatureDetector\"\nthreshold: 11\nnonmaxSuppression: 0\ntype: 2\n"); + + detector.read(filename); + + assertEquals(11, detector.getThreshold()); + assertEquals(false, detector.getNonmaxSuppression()); + assertEquals(2, detector.getType()); + } + + public void testWrite() { + String filename = OpenCVTestRunner.getTempFileName("xml"); + + detector.write(filename); + + String truth = "\n\nFeature2D.AgastFeatureDetector\n10\n1\n3\n\n"; + String actual = readFile(filename); + actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation + assertEquals(truth, actual); + } + + public void testWriteYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + + detector.write(filename); + + String truth = "%YAML:1.0\n---\nname: \"Feature2D.AgastFeatureDetector\"\nthreshold: 10\nnonmaxSuppression: 1\ntype: 3\n"; + String actual = readFile(filename); + actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation + assertEquals(truth, actual); + } + +} diff --git a/modules/xfeatures2d/misc/java/test/AKAZEDescriptorExtractorTest.java b/modules/xfeatures2d/misc/java/test/AKAZEDescriptorExtractorTest.java new file mode 100644 index 00000000000..fd604cbfa46 --- /dev/null +++ b/modules/xfeatures2d/misc/java/test/AKAZEDescriptorExtractorTest.java @@ -0,0 +1,67 @@ +package org.opencv.test.features2d; + +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; +import org.opencv.xfeatures2d.AKAZE; + +public class AKAZEDescriptorExtractorTest extends OpenCVTestCase { + + AKAZE extractor; + + @Override + protected void setUp() throws Exception { + super.setUp(); + extractor = AKAZE.create(); // default (5,0,3,0.001f,4,4,1) + } + + public void testCreate() { + assertNotNull(extractor); + } + + public void testDetectListOfMatListOfListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectListOfMatListOfListOfKeyPointListOfMat() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPointMat() { + fail("Not yet implemented"); + } + + public void testEmpty() { + fail("Not yet implemented"); + } + + public void testReadYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + writeFile(filename, "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.AKAZE\"\ndescriptor: 4\ndescriptor_channels: 2\ndescriptor_size: 32\nthreshold: 0.125\noctaves: 3\nsublevels: 5\ndiffusivity: 2\n"); + + extractor.read(filename); + + assertEquals(4, extractor.getDescriptorType()); + assertEquals(2, extractor.getDescriptorChannels()); + assertEquals(32, extractor.getDescriptorSize()); + assertEquals(0.125, extractor.getThreshold()); + assertEquals(3, extractor.getNOctaves()); + assertEquals(5, extractor.getNOctaveLayers()); + assertEquals(2, extractor.getDiffusivity()); + } + + public void testWriteYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + + extractor.write(filename); + + String truth = "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.AKAZE\"\ndescriptor: 5\ndescriptor_channels: 3\ndescriptor_size: 0\nthreshold: 0.0010000000474974513\noctaves: 4\nsublevels: 4\ndiffusivity: 1\nmax_points: -1\n"; + String actual = readFile(filename); + actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation + assertEquals(truth, actual); + } + +} diff --git a/modules/xfeatures2d/misc/java/test/BOWImgDescriptorExtractorTest.java b/modules/xfeatures2d/misc/java/test/BOWImgDescriptorExtractorTest.java new file mode 100644 index 00000000000..317aba1671c --- /dev/null +++ b/modules/xfeatures2d/misc/java/test/BOWImgDescriptorExtractorTest.java @@ -0,0 +1,48 @@ +package org.opencv.test.features2d; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfKeyPoint; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.core.KeyPoint; +import org.opencv.features2d.ORB; +import org.opencv.features2d.DescriptorMatcher; +import org.opencv.xfeatures2d.BOWImgDescriptorExtractor; +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; +import org.opencv.imgproc.Imgproc; + +public class BOWImgDescriptorExtractorTest extends OpenCVTestCase { + + ORB extractor; + DescriptorMatcher matcher; + int matSize; + + public static void assertDescriptorsClose(Mat expected, Mat actual, int allowedDistance) { + double distance = Core.norm(expected, actual, Core.NORM_HAMMING); + assertTrue("expected:<" + allowedDistance + "> but was:<" + distance + ">", distance <= allowedDistance); + } + + private Mat getTestImg() { + Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255)); + Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2); + Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2); + + return cross; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + extractor = ORB.create(); + matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE); + matSize = 100; + } + + public void testCreate() { + BOWImgDescriptorExtractor bow = new BOWImgDescriptorExtractor(extractor, matcher); + } + +} diff --git a/modules/xfeatures2d/misc/java/test/BRIEFDescriptorExtractorTest.java b/modules/xfeatures2d/misc/java/test/BRIEFDescriptorExtractorTest.java new file mode 100644 index 00000000000..a8744635ee1 --- /dev/null +++ b/modules/xfeatures2d/misc/java/test/BRIEFDescriptorExtractorTest.java @@ -0,0 +1,102 @@ +package org.opencv.test.features2d; + +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfKeyPoint; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.core.KeyPoint; +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; +import org.opencv.imgproc.Imgproc; +import org.opencv.features2d.Feature2D; + +public class BRIEFDescriptorExtractorTest extends OpenCVTestCase { + + Feature2D extractor; + int matSize; + + private Mat getTestImg() { + Mat cross = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255)); + Imgproc.line(cross, new Point(20, matSize / 2), new Point(matSize - 21, matSize / 2), new Scalar(100), 2); + Imgproc.line(cross, new Point(matSize / 2, 20), new Point(matSize / 2, matSize - 21), new Scalar(100), 2); + + return cross; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null); + matSize = 100; + } + + public void testComputeListOfMatListOfListOfKeyPointListOfMat() { + fail("Not yet implemented"); + } + + public void testComputeMatListOfKeyPointMat() { + KeyPoint point = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1); + MatOfKeyPoint keypoints = new MatOfKeyPoint(point); + Mat img = getTestImg(); + Mat descriptors = new Mat(); + + extractor.compute(img, keypoints, descriptors); + + Mat truth = new Mat(1, 32, CvType.CV_8UC1) { + { + put(0, 0, 96, 0, 76, 24, 47, 182, 68, 137, + 149, 195, 67, 16, 187, 224, 74, 8, + 82, 169, 87, 70, 44, 4, 192, 56, + 13, 128, 44, 106, 146, 72, 194, 245); + } + }; + + assertMatEqual(truth, descriptors); + } + + public void testCreate() { + assertNotNull(extractor); + } + + public void testDescriptorSize() { + assertEquals(32, extractor.descriptorSize()); + } + + public void testDescriptorType() { + assertEquals(CvType.CV_8U, extractor.descriptorType()); + } + + public void testEmpty() { +// assertFalse(extractor.empty()); + fail("Not yet implemented"); // BRIEF does not override empty() method + } + + public void testRead() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + writeFile(filename, "%YAML:1.0\n---\ndescriptorSize: 64\n"); + + extractor.read(filename); + + assertEquals(64, extractor.descriptorSize()); + } + + public void testWrite() { + String filename = OpenCVTestRunner.getTempFileName("xml"); + + extractor.write(filename); + + String truth = "\n\nFeature2D.BRIEF\n32\n0\n\n"; + assertEquals(truth, readFile(filename)); + } + + public void testWriteYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + + extractor.write(filename); + + String truth = "%YAML:1.0\n---\nname: \"Feature2D.BRIEF\"\ndescriptorSize: 32\nuse_orientation: 0\n"; + assertEquals(truth, readFile(filename)); + } + +} diff --git a/modules/xfeatures2d/misc/java/test/BRISKDescriptorExtractorTest.java b/modules/xfeatures2d/misc/java/test/BRISKDescriptorExtractorTest.java new file mode 100644 index 00000000000..ff7c29db8a7 --- /dev/null +++ b/modules/xfeatures2d/misc/java/test/BRISKDescriptorExtractorTest.java @@ -0,0 +1,63 @@ +package org.opencv.test.features2d; + +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; +import org.opencv.xfeatures2d.BRISK; + +public class BRISKDescriptorExtractorTest extends OpenCVTestCase { + + BRISK extractor; + + @Override + protected void setUp() throws Exception { + super.setUp(); + extractor = BRISK.create(); // default (30,3,1) + } + + public void testCreate() { + assertNotNull(extractor); + } + + public void testDetectListOfMatListOfListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectListOfMatListOfListOfKeyPointListOfMat() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPointMat() { + fail("Not yet implemented"); + } + + public void testEmpty() { + fail("Not yet implemented"); + } + + public void testReadYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + writeFile(filename, "%YAML:1.0\n---\nname: \"Feature2D.BRISK\"\nthreshold: 31\noctaves: 4\npatternScale: 1.1\n"); + + extractor.read(filename); + + assertEquals(31, extractor.getThreshold()); + assertEquals(4, extractor.getOctaves()); + assertEquals(1.1f, extractor.getPatternScale()); + } + + public void testWriteYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + + extractor.write(filename); + + String truth = "%YAML:1.0\n---\nname: \"Feature2D.BRISK\"\nthreshold: 30\noctaves: 3\npatternScale: 1.\n"; + String actual = readFile(filename); + actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation + assertEquals(truth, actual); + } + +} diff --git a/modules/xfeatures2d/misc/java/test/KAZEDescriptorExtractorTest.java b/modules/xfeatures2d/misc/java/test/KAZEDescriptorExtractorTest.java new file mode 100644 index 00000000000..37cbb29120f --- /dev/null +++ b/modules/xfeatures2d/misc/java/test/KAZEDescriptorExtractorTest.java @@ -0,0 +1,66 @@ +package org.opencv.test.features2d; + +import org.opencv.test.OpenCVTestCase; +import org.opencv.test.OpenCVTestRunner; +import org.opencv.xfeatures2d.KAZE; + +public class KAZEDescriptorExtractorTest extends OpenCVTestCase { + + KAZE extractor; + + @Override + protected void setUp() throws Exception { + super.setUp(); + extractor = KAZE.create(); // default (false,false,0.001f,4,4,1) + } + + public void testCreate() { + assertNotNull(extractor); + } + + public void testDetectListOfMatListOfListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectListOfMatListOfListOfKeyPointListOfMat() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPoint() { + fail("Not yet implemented"); + } + + public void testDetectMatListOfKeyPointMat() { + fail("Not yet implemented"); + } + + public void testEmpty() { + fail("Not yet implemented"); + } + + public void testReadYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + writeFile(filename, "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.KAZE\"\nextended: 1\nupright: 1\nthreshold: 0.125\noctaves: 3\nsublevels: 5\ndiffusivity: 2\n"); + + extractor.read(filename); + + assertEquals(true, extractor.getExtended()); + assertEquals(true, extractor.getUpright()); + assertEquals(0.125, extractor.getThreshold()); + assertEquals(3, extractor.getNOctaves()); + assertEquals(5, extractor.getNOctaveLayers()); + assertEquals(2, extractor.getDiffusivity()); + } + + public void testWriteYml() { + String filename = OpenCVTestRunner.getTempFileName("yml"); + + extractor.write(filename); + + String truth = "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.KAZE\"\nextended: 0\nupright: 0\nthreshold: 0.0010000000474974513\noctaves: 4\nsublevels: 4\ndiffusivity: 1\n"; + String actual = readFile(filename); + actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation + assertEquals(truth, actual); + } + +} diff --git a/modules/xfeatures2d/misc/js/gen_dict.json b/modules/xfeatures2d/misc/js/gen_dict.json new file mode 100644 index 00000000000..9fd3b5aa991 --- /dev/null +++ b/modules/xfeatures2d/misc/js/gen_dict.json @@ -0,0 +1,9 @@ +{ + "whitelist": + { + "BRISK": ["create", "getDefaultName"], + "AgastFeatureDetector": ["create", "setThreshold", "getThreshold", "setNonmaxSuppression", "getNonmaxSuppression", "setType", "getType", "getDefaultName"], + "KAZE": ["create", "setExtended", "getExtended", "setUpright", "getUpright", "setThreshold", "getThreshold", "setNOctaves", "getNOctaves", "setNOctaveLayers", "getNOctaveLayers", "setDiffusivity", "getDiffusivity", "getDefaultName"], + "AKAZE": ["create", "setDescriptorType", "getDescriptorType", "setDescriptorSize", "getDescriptorSize", "setDescriptorChannels", "getDescriptorChannels", "setThreshold", "getThreshold", "setNOctaves", "getNOctaves", "setNOctaveLayers", "getNOctaveLayers", "setDiffusivity", "getDiffusivity", "getDefaultName"] + } +} diff --git a/modules/xfeatures2d/misc/objc/gen_dict.json b/modules/xfeatures2d/misc/objc/gen_dict.json index 5d278b92c8b..f8fc4d4f1c4 100644 --- a/modules/xfeatures2d/misc/objc/gen_dict.json +++ b/modules/xfeatures2d/misc/objc/gen_dict.json @@ -13,5 +13,8 @@ "PCTSignatures" : { "(PCTSignatures*)create:(NSArray*)initSamplingPoints initSeedCount:(int)initSeedCount" : { "create" : {"name" : "create2"} } } + }, + "enum_fix" : { + "AgastFeatureDetector" : { "DetectorType": "AgastDetectorType" } } } diff --git a/modules/xfeatures2d/misc/python/pyopencv_xfeatures2d.hpp b/modules/xfeatures2d/misc/python/pyopencv_xfeatures2d.hpp index 17d9067465f..e0cc8e1932d 100644 --- a/modules/xfeatures2d/misc/python/pyopencv_xfeatures2d.hpp +++ b/modules/xfeatures2d/misc/python/pyopencv_xfeatures2d.hpp @@ -1,7 +1,12 @@ #ifdef HAVE_OPENCV_XFEATURES2D #include "opencv2/xfeatures2d.hpp" -using cv::xfeatures2d::DAISY; +using namespace cv::xfeatures2d; typedef DAISY::NormalizationType DAISY_NormalizationType; + +typedef AKAZE::DescriptorType AKAZE_DescriptorType; +typedef AgastFeatureDetector::DetectorType AgastFeatureDetector_DetectorType; +typedef KAZE::DiffusivityType KAZE_DiffusivityType; + #endif diff --git a/modules/xfeatures2d/misc/python/test/test_descriptors.py b/modules/xfeatures2d/misc/python/test/test_descriptors.py index 7e69311c860..d217105b5ec 100644 --- a/modules/xfeatures2d/misc/python/test/test_descriptors.py +++ b/modules/xfeatures2d/misc/python/test/test_descriptors.py @@ -24,7 +24,7 @@ class matchLOGOS_test(NewOpenCVTests): def test_basic(self): frame = self.get_sample('python/images/baboon.png', cv.IMREAD_COLOR) - detector = cv.AKAZE_create(threshold = 0.003) + detector = cv.xfeatures2d.AKAZE_create(threshold = 0.003) keypoints1, descrs1 = detector.detectAndCompute(frame, None) keypoints2, descrs2 = detector.detectAndCompute(frame, None) diff --git a/modules/xfeatures2d/perf/perf_feature2d.cpp b/modules/xfeatures2d/perf/perf_feature2d.cpp new file mode 100644 index 00000000000..0756ee071ac --- /dev/null +++ b/modules/xfeatures2d/perf/perf_feature2d.cpp @@ -0,0 +1,71 @@ +#include "perf_feature2d.hpp" + +namespace opencv_test +{ + +PERF_TEST_P(feature2d, detect, testing::Combine(Feature2DType::all(), TEST_IMAGES)) +{ + Ptr detector = getFeature2D(get<0>(GetParam())); + std::string filename = getDataPath(get<1>(GetParam())); + Mat img = imread(filename, IMREAD_GRAYSCALE); + + ASSERT_FALSE(img.empty()); + ASSERT_TRUE(detector); + + declare.in(img); + Mat mask; + vector points; + + TEST_CYCLE() detector->detect(img, points, mask); + + EXPECT_GT(points.size(), 20u); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(feature2d, extract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES)) +{ + Ptr detector = AKAZE::create(); + Ptr extractor = getFeature2D(get<0>(GetParam())); + std::string filename = getDataPath(get<1>(GetParam())); + Mat img = imread(filename, IMREAD_GRAYSCALE); + + ASSERT_FALSE(img.empty()); + ASSERT_TRUE(extractor); + + declare.in(img); + Mat mask; + vector points; + detector->detect(img, points, mask); + + EXPECT_GT(points.size(), 20u); + + Mat descriptors; + + TEST_CYCLE() extractor->compute(img, points, descriptors); + + EXPECT_EQ((size_t)descriptors.rows, points.size()); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(feature2d, detectAndExtract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES)) +{ + Ptr detector = getFeature2D(get<0>(GetParam())); + std::string filename = getDataPath(get<1>(GetParam())); + Mat img = imread(filename, IMREAD_GRAYSCALE); + + ASSERT_FALSE(img.empty()); + ASSERT_TRUE(detector); + + declare.in(img); + Mat mask; + vector points; + Mat descriptors; + + TEST_CYCLE() detector->detectAndCompute(img, mask, points, descriptors, false); + + EXPECT_GT(points.size(), 20u); + EXPECT_EQ((size_t)descriptors.rows, points.size()); + SANITY_CHECK_NOTHING(); +} + +} // namespace diff --git a/modules/xfeatures2d/perf/perf_feature2d.hpp b/modules/xfeatures2d/perf/perf_feature2d.hpp new file mode 100644 index 00000000000..b644a773d88 --- /dev/null +++ b/modules/xfeatures2d/perf/perf_feature2d.hpp @@ -0,0 +1,60 @@ +#ifndef __OPENCV_PERF_FEATURE2D_HPP__ +#define __OPENCV_PERF_FEATURE2D_HPP__ + +#include "perf_precomp.hpp" + +namespace opencv_test { + +/* configuration for tests of detectors/descriptors. shared between ocl and cpu tests. */ + +// detectors/descriptors configurations to test +#define DETECTORS_ONLY \ + AGAST_DEFAULT, AGAST_5_8, AGAST_7_12d, AGAST_7_12s, AGAST_OAST_9_16 + +#define DETECTORS_EXTRACTORS \ + AKAZE_DEFAULT, AKAZE_DESCRIPTOR_KAZE, \ + BRISK_DEFAULT, \ + KAZE_DEFAULT + +#define CV_ENUM_EXPAND(name, ...) CV_ENUM(name, __VA_ARGS__) + +enum Feature2DVals { DETECTORS_ONLY, DETECTORS_EXTRACTORS }; +CV_ENUM_EXPAND(Feature2DType, DETECTORS_ONLY, DETECTORS_EXTRACTORS) + +typedef tuple Feature2DType_String_t; +typedef perf::TestBaseWithParam feature2d; + +#define TEST_IMAGES testing::Values(\ + "cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\ + "stitching/a3.png", \ + "stitching/s2.jpg") + +static inline Ptr getFeature2D(Feature2DType type) +{ + switch(type) { + case AGAST_DEFAULT: + return AgastFeatureDetector::create(); + case AGAST_5_8: + return AgastFeatureDetector::create(70, true, AgastFeatureDetector::AGAST_5_8); + case AGAST_7_12d: + return AgastFeatureDetector::create(70, true, AgastFeatureDetector::AGAST_7_12d); + case AGAST_7_12s: + return AgastFeatureDetector::create(70, true, AgastFeatureDetector::AGAST_7_12s); + case AGAST_OAST_9_16: + return AgastFeatureDetector::create(70, true, AgastFeatureDetector::OAST_9_16); + case AKAZE_DEFAULT: + return AKAZE::create(); + case AKAZE_DESCRIPTOR_KAZE: + return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); + case BRISK_DEFAULT: + return BRISK::create(); + case KAZE_DEFAULT: + return KAZE::create(); + default: + return Ptr(); + } +} + +} // namespace + +#endif // __OPENCV_PERF_FEATURE2D_HPP__ diff --git a/modules/xfeatures2d/perf/perf_feature2d.ocl.cpp b/modules/xfeatures2d/perf/perf_feature2d.ocl.cpp new file mode 100644 index 00000000000..b9f4ff067f3 --- /dev/null +++ b/modules/xfeatures2d/perf/perf_feature2d.ocl.cpp @@ -0,0 +1,81 @@ +#include "perf_precomp.hpp" +#include "opencv2/ts/ocl_perf.hpp" +#include "perf_feature2d.hpp" + +#ifdef HAVE_OPENCL + +namespace opencv_test { +namespace ocl { + +OCL_PERF_TEST_P(feature2d, detect, testing::Combine(Feature2DType::all(), TEST_IMAGES)) +{ + Ptr detector = getFeature2D(get<0>(GetParam())); + std::string filename = getDataPath(get<1>(GetParam())); + Mat mimg = imread(filename, IMREAD_GRAYSCALE); + + ASSERT_FALSE(mimg.empty()); + ASSERT_TRUE(detector); + + UMat img, mask; + mimg.copyTo(img); + declare.in(img); + vector points; + + OCL_TEST_CYCLE() detector->detect(img, points, mask); + + EXPECT_GT(points.size(), 20u); + SANITY_CHECK_NOTHING(); +} + +OCL_PERF_TEST_P(feature2d, extract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES)) +{ + Ptr detector = AKAZE::create(); + Ptr extractor = getFeature2D(get<0>(GetParam())); + std::string filename = getDataPath(get<1>(GetParam())); + Mat mimg = imread(filename, IMREAD_GRAYSCALE); + + ASSERT_FALSE(mimg.empty()); + ASSERT_TRUE(extractor); + + UMat img, mask; + mimg.copyTo(img); + declare.in(img); + vector points; + detector->detect(img, points, mask); + + EXPECT_GT(points.size(), 20u); + + UMat descriptors; + + OCL_TEST_CYCLE() extractor->compute(img, points, descriptors); + + EXPECT_EQ((size_t)descriptors.rows, points.size()); + SANITY_CHECK_NOTHING(); +} + +OCL_PERF_TEST_P(feature2d, detectAndExtract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES)) +{ + Ptr detector = getFeature2D(get<0>(GetParam())); + std::string filename = getDataPath(get<1>(GetParam())); + Mat mimg = imread(filename, IMREAD_GRAYSCALE); + + ASSERT_FALSE(mimg.empty()); + ASSERT_TRUE(detector); + + UMat img, mask; + mimg.copyTo(img); + declare.in(img); + vector points; + UMat descriptors; + + OCL_TEST_CYCLE() detector->detectAndCompute(img, mask, points, descriptors, false); + + EXPECT_GT(points.size(), 20u); + EXPECT_EQ((size_t)descriptors.rows, points.size()); + SANITY_CHECK_NOTHING(); +} + +} // ocl +} // cvtest + +#endif // HAVE_OPENCL diff --git a/modules/xfeatures2d/samples/LATCH_match.cpp b/modules/xfeatures2d/samples/LATCH_match.cpp new file mode 100644 index 00000000000..e7889f08ea5 --- /dev/null +++ b/modules/xfeatures2d/samples/LATCH_match.cpp @@ -0,0 +1,115 @@ +#include + +#include "opencv2/opencv_modules.hpp" + +#ifdef HAVE_OPENCV_XFEATURES2D + +#include +#include +#include +#include +#include +#include +#include + +// If you find this code useful, please add a reference to the following paper in your work: +// Gil Levi and Tal Hassner, "LATCH: Learned Arrangements of Three Patch Codes", arXiv preprint arXiv:1501.03719, 15 Jan. 2015 + +using namespace std; +using namespace cv; + +const float inlier_threshold = 2.5f; // Distance threshold to identify inliers +const float nn_match_ratio = 0.8f; // Nearest neighbor matching ratio + +int main(int argc, char* argv[]) +{ + CommandLineParser parser(argc, argv, + "{@img1 | graf1.png | input image 1}" + "{@img2 | graf3.png | input image 2}" + "{@homography | H1to3p.xml | homography matrix}"); + Mat img1 = imread( samples::findFile( parser.get("@img1") ), IMREAD_GRAYSCALE); + Mat img2 = imread( samples::findFile( parser.get("@img2") ), IMREAD_GRAYSCALE); + + Mat homography; + FileStorage fs( samples::findFile( parser.get("@homography") ), FileStorage::READ); + fs.getFirstTopLevelNode() >> homography; + + vector kpts1, kpts2; + Mat desc1, desc2; + + Ptr orb_detector = cv::ORB::create(10000); + + Ptr latch = xfeatures2d::LATCH::create(); + + + orb_detector->detect(img1, kpts1); + latch->compute(img1, kpts1, desc1); + + orb_detector->detect(img2, kpts2); + latch->compute(img2, kpts2, desc2); + + BFMatcher matcher(NORM_HAMMING); + vector< vector > nn_matches; + matcher.knnMatch(desc1, desc2, nn_matches, 2); + + vector matched1, matched2, inliers1, inliers2; + vector good_matches; + for (size_t i = 0; i < nn_matches.size(); i++) { + DMatch first = nn_matches[i][0]; + float dist1 = nn_matches[i][0].distance; + float dist2 = nn_matches[i][1].distance; + + if (dist1 < nn_match_ratio * dist2) { + matched1.push_back(kpts1[first.queryIdx]); + matched2.push_back(kpts2[first.trainIdx]); + } + } + + for (unsigned i = 0; i < matched1.size(); i++) { + Mat col = Mat::ones(3, 1, CV_64F); + col.at(0) = matched1[i].pt.x; + col.at(1) = matched1[i].pt.y; + + col = homography * col; + col /= col.at(2); + double dist = sqrt(pow(col.at(0) - matched2[i].pt.x, 2) + + pow(col.at(1) - matched2[i].pt.y, 2)); + + if (dist < inlier_threshold) { + int new_i = static_cast(inliers1.size()); + inliers1.push_back(matched1[i]); + inliers2.push_back(matched2[i]); + good_matches.push_back(DMatch(new_i, new_i, 0)); + } + } + + Mat res; + drawMatches(img1, inliers1, img2, inliers2, good_matches, res); + imwrite("latch_result.png", res); + + + double inlier_ratio = inliers1.size() * 1.0 / matched1.size(); + cout << "LATCH Matching Results" << endl; + cout << "*******************************" << endl; + cout << "# Keypoints 1: \t" << kpts1.size() << endl; + cout << "# Keypoints 2: \t" << kpts2.size() << endl; + cout << "# Matches: \t" << matched1.size() << endl; + cout << "# Inliers: \t" << inliers1.size() << endl; + cout << "# Inliers Ratio: \t" << inlier_ratio << endl; + cout << endl; + + imshow("result", res); + waitKey(); + + return 0; +} + +#else + +int main() +{ + std::cerr << "OpenCV was built without xfeatures2d module" << std::endl; + return 0; +} + +#endif diff --git a/modules/xfeatures2d/src/agast.cpp b/modules/xfeatures2d/src/agast.cpp new file mode 100644 index 00000000000..b6c87ad23ff --- /dev/null +++ b/modules/xfeatures2d/src/agast.cpp @@ -0,0 +1,8195 @@ +/* This is AGAST and OAST, an optimal and accelerated corner detector + based on the accelerated segment tests + Below is the original copyright and the references */ + +/* +Copyright (C) 2010 Elmar Mair +All rights reserved. + +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. + + *Neither the name of the University of Cambridge nor the names of + its contributors may 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 COPYRIGHT OWNER 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. +*/ + +/* +The references are: + * Adaptive and Generic Corner Detection Based on the Accelerated Segment Test, + Elmar Mair and Gregory D. Hager and Darius Burschka + and Michael Suppa and Gerhard Hirzinger ECCV 2010 + URL: http://www6.in.tum.de/Main/ResearchAgast +*/ + +#include "precomp.hpp" +#include "agast_score.hpp" + +namespace cv +{ +namespace xfeatures2d +{ + +#if (defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) + +static void AGAST_5_8(InputArray _img, std::vector& keypoints, int threshold) +{ + + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB = xsize - 2; + int ysizeB = ysize - 1; + int width; + + keypoints.resize(0); + + int pixel_5_8_[16]; + makeAgastOffsets(pixel_5_8_, (int)img.step, AgastFeatureDetector::AGAST_5_8); + + short offset0 = (short) pixel_5_8_[0]; + short offset1 = (short) pixel_5_8_[1]; + short offset2 = (short) pixel_5_8_[2]; + short offset3 = (short) pixel_5_8_[3]; + short offset4 = (short) pixel_5_8_[4]; + short offset5 = (short) pixel_5_8_[5]; + short offset6 = (short) pixel_5_8_[6]; + short offset7 = (short) pixel_5_8_[7]; + + width = xsize; + + for(y = 1; y < ysizeB; y++) + { + x = 0; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto structured; + } + } +} + +static void AGAST_7_12d(InputArray _img, std::vector& keypoints, int threshold) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB = xsize - 4; + int ysizeB = ysize - 3; + int width; + + keypoints.resize(0); + + int pixel_7_12d_[16]; + makeAgastOffsets(pixel_7_12d_, (int)img.step, AgastFeatureDetector::AGAST_7_12d); + + short offset0 = (short) pixel_7_12d_[0]; + short offset1 = (short) pixel_7_12d_[1]; + short offset2 = (short) pixel_7_12d_[2]; + short offset3 = (short) pixel_7_12d_[3]; + short offset4 = (short) pixel_7_12d_[4]; + short offset5 = (short) pixel_7_12d_[5]; + short offset6 = (short) pixel_7_12d_[6]; + short offset7 = (short) pixel_7_12d_[7]; + short offset8 = (short) pixel_7_12d_[8]; + short offset9 = (short) pixel_7_12d_[9]; + short offset10 = (short) pixel_7_12d_[10]; + short offset11 = (short) pixel_7_12d_[11]; + + width = xsize; + + for(y = 3; y < ysizeB; y++) + { + x = 2; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + if(ptr[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto structured; + } + } +} + + +static void AGAST_7_12s(InputArray _img, std::vector& keypoints, int threshold) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB=xsize - 3; //2, +1 due to faster test x>xsizeB + int ysizeB=ysize - 2; + int width; + + keypoints.resize(0); + + int pixel_7_12s_[16]; + makeAgastOffsets(pixel_7_12s_, (int)img.step, AgastFeatureDetector::AGAST_7_12s); + + short offset0 = (short) pixel_7_12s_[0]; + short offset1 = (short) pixel_7_12s_[1]; + short offset2 = (short) pixel_7_12s_[2]; + short offset3 = (short) pixel_7_12s_[3]; + short offset4 = (short) pixel_7_12s_[4]; + short offset5 = (short) pixel_7_12s_[5]; + short offset6 = (short) pixel_7_12s_[6]; + short offset7 = (short) pixel_7_12s_[7]; + short offset8 = (short) pixel_7_12s_[8]; + short offset9 = (short) pixel_7_12s_[9]; + short offset10 = (short) pixel_7_12s_[10]; + short offset11 = (short) pixel_7_12s_[11]; + + width = xsize; + + for(y = 2; y < ysizeB; y++) + { + x = 1; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_homogeneous; + else + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_homogeneous; + else + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_homogeneous; + else + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_homogeneous; + else + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset7] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + if(ptr[offset11] > cb) + goto success_structured; + else + goto homogeneous; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto success_structured; + else + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto success_structured; + else + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto success_structured; + else + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto success_structured; + else + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto success_structured; + else + goto structured; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto structured; + } + } +} + +static void OAST_9_16(InputArray _img, std::vector& keypoints, int threshold) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB=xsize - 4; + int ysizeB=ysize - 3; + int width; + + keypoints.resize(0); + + int pixel_9_16_[16]; + makeAgastOffsets(pixel_9_16_, (int)img.step, AgastFeatureDetector::OAST_9_16); + + short offset0 = (short) pixel_9_16_[0]; + short offset1 = (short) pixel_9_16_[1]; + short offset2 = (short) pixel_9_16_[2]; + short offset3 = (short) pixel_9_16_[3]; + short offset4 = (short) pixel_9_16_[4]; + short offset5 = (short) pixel_9_16_[5]; + short offset6 = (short) pixel_9_16_[6]; + short offset7 = (short) pixel_9_16_[7]; + short offset8 = (short) pixel_9_16_[8]; + short offset9 = (short) pixel_9_16_[9]; + short offset10 = (short) pixel_9_16_[10]; + short offset11 = (short) pixel_9_16_[11]; + short offset12 = (short) pixel_9_16_[12]; + short offset13 = (short) pixel_9_16_[13]; + short offset14 = (short) pixel_9_16_[14]; + short offset15 = (short) pixel_9_16_[15]; + + width = xsize; + + for(y = 3; y < ysizeB; y++) + { + x = 2; + while(true) + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + {} + else + if(ptr[offset15] > cb) + {} + else + continue; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset7] < c_b) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset13] > cb) + {} + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset14] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset13] > cb) + {} + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset5] < c_b) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + {} + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + {} + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + {} + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + {} + else + if(ptr[offset12] < c_b) + {} + else + continue; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + {} + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + {} + else + if(ptr[offset14] < c_b) + {} + else + continue; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + {} + else + if(ptr[offset10] < c_b) + {} + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + {} + else + if(ptr[offset12] < c_b) + {} + else + continue; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + {} + else + if(ptr[offset10] > cb) + {} + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset2] < c_b) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + {} + else + if(ptr[offset12] > cb) + {} + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + {} + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset4] < c_b) + if(ptr[offset5] > cb) + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + {} + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset5] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset14] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset13] < c_b) + {} + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + {} + else + if(ptr[offset15] < c_b) + {} + else + continue; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + {} + else + if(ptr[offset13] < c_b) + {} + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset6] > cb) + {} + else + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + {} + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + {} + else + if(ptr[offset14] > cb) + {} + else + continue; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + {} + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + {} + else + if(ptr[offset12] > cb) + {} + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + {} + else + if(ptr[offset10] > cb) + {} + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + {} + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + {} + else + if(ptr[offset10] < c_b) + {} + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + {} + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + } + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + } + } +} + + + +#else // !(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) + +static void AGAST_ALL(InputArray _img, std::vector& keypoints, int threshold, AgastFeatureDetector::DetectorType agasttype) +{ + cv::Mat img; + if(!_img.getMat().isContinuous()) + img = _img.getMat().clone(); + else + img = _img.getMat(); + + int agastbase; + int result; + uint32_t *table_struct1; + uint32_t *table_struct2; + static const uint32_t table_5_8_struct1[] = + { + 0x00010026,0x20020017,0x3003000c,0x50040009,0x10050007,0x406f0006,0x706f006c,0x4008006c, + 0x606f006c,0x100a006c,0x406d000b,0x706d006c,0x700d0012,0x600e006c,0x500f0011,0x106f0010, + 0x406f006c,0x106d006c,0x5013106c,0x3014106c,0x7015106c,0x4016106c,0x606f106e,0x5018001c, + 0x7019006c,0x601a006c,0x106d001b,0x406d006c,0x501d106c,0x301e106c,0x201f1023,0x10201021, + 0x406f106c,0x4022106c,0x606f106c,0x7024106c,0x4025106c,0x606f106c,0x00271058,0x20281049, + 0x70290035,0x302a1031,0x502b102f,0x102c102d,0x406f106e,0x402e106c,0x606f106e,0x1030106c, + 0x406f106c,0x5032006c,0x3033006c,0x4034006c,0x606f006e,0x70361041,0x3037103c,0x5038103b, + 0x106f1039,0x403a106c,0x606f106e,0x106d106c,0x603d106c,0x503e1040,0x106f103f,0x406f106c, + 0x106d106c,0x3042106c,0x50431047,0x10441045,0x406f106c,0x4046106c,0x606f106c,0x1048106c, + 0x406d106c,0x504a0053,0x304b006c,0x204c0050,0x104d004e,0x406f006c,0x404f006c,0x606f006c, + 0x7051006c,0x4052006c,0x606f006c,0x5054106c,0x7055106c,0x6056106c,0x106d1057,0x406d106c, + 0x30590062,0x505a006c,0x205b005f,0x105c005d,0x406d006c,0x405e006c,0x606d006c,0x7060006c, + 0x4061006c,0x606d006c,0x3063106c,0x5064106c,0x20651069,0x10661067,0x406d106c,0x4068106c, + 0x606d106c,0x706a106c,0x406b106c,0x606d106c,0x000000fc,0x000000fd,0x000000fe,0x000000ff + }; + + static const uint32_t table_5_8_struct2[] = + { + 0x0001002a,0x2002001b,0x30030010,0x5004000c,0x70050008,0x10730006,0x40070072,0x60730072, + 0x1009000a,0x40730072,0x400b0072,0x60730072,0x700d000e,0x10730072,0x100f0072,0x40730072, + 0x70110016,0x60120072,0x50130015,0x10730014,0x40730072,0x10730072,0x50171072,0x30181070, + 0x70191070,0x401a1072,0x60731072,0x501c0020,0x701d0072,0x601e0072,0x1073001f,0x40730072, + 0x50211070,0x30221072,0x20231027,0x10241025,0x40731072,0x40261072,0x60731072,0x70281070, + 0x40291070,0x60711070,0x002b105c,0x202c104d,0x702d0039,0x302e1035,0x502f1033,0x10301031, + 0x40731072,0x40321072,0x60731072,0x10341072,0x40731072,0x50360072,0x30370070,0x40380072, + 0x60730072,0x703a1045,0x303b1040,0x503c103f,0x1073103d,0x403e1072,0x60731072,0x10731072, + 0x60411072,0x50421044,0x10731043,0x40731072,0x10731072,0x30461070,0x5047104b,0x10481049, + 0x40711070,0x404a1070,0x60711070,0x104c1070,0x40711070,0x504e0057,0x304f0072,0x20500054, + 0x10510052,0x40730072,0x40530072,0x60730072,0x70550070,0x40560070,0x60710070,0x50581070, + 0x70591072,0x605a1072,0x1073105b,0x40731072,0x305d0066,0x505e0070,0x205f0063,0x10600061, + 0x40710070,0x40620070,0x60710070,0x70640070,0x40650070,0x60710070,0x30671070,0x50681070, + 0x2069106d,0x106a106b,0x40711070,0x406c1070,0x60711070,0x706e1070,0x406f1070,0x60711070, + 0x000000fc,0x000000fd,0x000000fe,0x000000ff + }; + + static const uint32_t table_7_12d_struct1[] = + { + 0x000100b5,0x50020036,0x20030025,0x9004001d,0x10050015,0x6006000f,0x3007000a,0x41870008, + 0xa0090186,0xb1890186,0x800b0186,0xa00c0186,0xb189000d,0x400e0186,0x71890188,0xb0100186, + 0x30110013,0x41870012,0xa1870186,0x80140186,0xa1870186,0x60160186,0x70170186,0x80180186, + 0x4019001b,0x3189001a,0xa1890186,0xa01c0186,0xb1890186,0x301e0186,0x401f0186,0x10200022, + 0x61870021,0xb1870186,0x60230186,0x70240186,0x81870186,0x90260186,0x70270186,0x80280186, + 0x10290030,0xa02a002d,0xb187002b,0x602c0186,0x41890186,0x602e0186,0x302f0186,0x41890186, + 0x60310186,0x40320034,0x31870033,0xa1870186,0xa0350186,0xb1870186,0x503710a1,0x9038006b, + 0x3039105b,0x403a1053,0xb03b004d,0x103c0044,0x803d0040,0xa03e0186,0x2189003f,0x71890188, + 0x60411186,0x20421186,0x70431188,0x81891188,0x60450048,0x70460186,0x80470186,0xa1890188, + 0x60491186,0x204a1186,0x704b1186,0x1189104c,0x81891188,0x204e1186,0x704f1186,0x10501051, + 0x61891186,0x60521186,0x81891186,0xb0540186,0x80550186,0xa0560186,0x10570059,0x21890058, + 0x71890186,0x605a0186,0x71890186,0xb05c0186,0xa05d0186,0x305e0065,0x105f0062,0x21870060, + 0x70610186,0x81890186,0x60630186,0x70640186,0x81890186,0x80660186,0x10670069,0x21870068, + 0x71870186,0x606a0186,0x71870186,0x906c1093,0x206d0087,0x106e007f,0x406f0077,0xa0700072, + 0x30710186,0xb1890186,0x60731186,0x70741186,0x80751186,0xb0761188,0xa1891188,0x60781186, + 0x70791186,0x807a1186,0xa07b107d,0x4189107c,0xb1891188,0x307e1186,0x41891188,0x60801186, + 0x70811186,0x80821186,0x40831085,0x31891084,0xa1891186,0xa0861186,0xb1891186,0x60881186, + 0x70891186,0x808a108f,0x408b108d,0x3187108c,0xa1871186,0xa08e1186,0xb1871186,0x20901186, + 0x10911186,0x30921186,0x41891186,0x20940099,0x10950186,0x30960186,0x40970186,0xa0980186, + 0xb1870186,0x209a1186,0x309b1186,0x409c1186,0x709d1186,0x109e109f,0x61871186,0x60a01186, + 0x81871186,0x20a200ae,0xa0a30186,0xb0a40186,0x90a500ab,0x10a600a8,0x318700a7,0x81870186, + 0x60a90186,0x70aa0186,0x81870186,0x10ac0186,0x30ad0186,0x41870186,0x90af0186,0x70b00186, + 0x80b10186,0xa0b20186,0xb0b30186,0x118700b4,0x61870186,0x00b6115a,0x20b700e2,0x50b800cc, + 0x70b900c5,0x60ba0186,0x40bb00c1,0x30bc00be,0x118700bd,0x81870186,0x90bf0186,0x80c00186, + 0xa1890186,0x90c20186,0x80c30186,0xa0c40186,0xb1890186,0x90c61186,0x80c71186,0xa0c81186, + 0xb0c91186,0x70ca1186,0x118910cb,0x61891186,0x90cd1186,0x70ce1186,0x80cf1186,0x50d010de, + 0x10d110d8,0xa0d210d5,0xb18910d3,0x60d41186,0x41891188,0x60d61186,0x30d71186,0x41891188, + 0x60d91186,0x40da10dc,0x318910db,0xa1891186,0xa0dd1186,0xb1891186,0xa0df1186,0xb0e01186, + 0x118710e1,0x61871186,0x20e3113a,0x90e4010b,0x50e500ff,0x10e610f7,0x40e710ef,0xa0e810ea, + 0x30e91186,0xb1891186,0x60eb0186,0x70ec0186,0x80ed0186,0xb0ee0188,0xa1890188,0x60f00186, + 0x70f10186,0x80f20186,0xa0f300f5,0x418900f4,0xb1890188,0x30f60186,0x41890188,0x60f80186, + 0x70f90186,0x80fa0186,0x40fb00fd,0x318900fc,0xa1890186,0xa0fe0186,0xb1890186,0x31001186, + 0x41011186,0x51021108,0x11031105,0x61871104,0xb1871186,0x61061186,0x71071186,0x81891186, + 0x11091186,0xa10a1186,0xb1871186,0x910c112e,0x510d1126,0x110e111e,0x610f1118,0x31101113, + 0x41871111,0xa1121186,0xb1891186,0x81141186,0xa1151186,0xb1891116,0x41171186,0x71891188, + 0xb1191186,0x311a111c,0x4187111b,0xa1871186,0x811d1186,0xa1871186,0x611f1186,0x71201186, + 0x81211186,0x41221124,0x31891123,0xa1891186,0xa1251186,0xb1891186,0xa1271186,0xb1281186, + 0x1129112b,0x3187112a,0x81871186,0x612c1186,0x712d1186,0x81871186,0x312f1186,0x41301186, + 0x51311137,0x11321134,0x61871133,0xb1871186,0x61351186,0x71361186,0x81871186,0x11381186, + 0xa1391186,0xb1871186,0x913b1150,0x713c1186,0x813d1186,0x513e114c,0x113f1146,0xa1401143, + 0xb1871141,0x61421186,0x41891186,0x61441186,0x31451186,0x41891186,0x61471186,0x4148114a, + 0x31871149,0xa1871186,0xa14b1186,0xb1871186,0xa14d1186,0xb14e1186,0x1187114f,0x61871186, + 0x51510186,0x91520186,0x61530186,0x71540186,0x81550186,0x41560158,0x31870157,0xa1870186, + 0xa1590186,0xb1870186,0x515b0170,0x915c0168,0x615d0186,0x715e0186,0x415f0165,0x31600163, + 0x81870161,0x11620186,0x21870186,0x81640186,0xa1870186,0xb1660186,0x81670186,0xa1870186, + 0x21690186,0x316a0186,0x416b0186,0x716c0186,0x116d016e,0x61870186,0x616f0186,0x81870186, + 0x51711186,0x9172117e,0x61731186,0x71741186,0x4175117b,0x31761179,0x81871177,0x11781186, + 0x21871186,0x817a1186,0xa1871186,0xb17c1186,0x817d1186,0xa1871186,0x217f1186,0x31801186, + 0x41811186,0x71821186,0x11831184,0x61871186,0x61851186,0x81871186,0x000000fc,0x000000fd, + 0x000000fe,0x000000ff + }; + + static const uint32_t table_7_12d_struct2[] = + { + 0x000100b5,0x50020036,0x20030025,0x9004001d,0x10050015,0x6006000f,0x3007000a,0x41890008, + 0xa0090188,0xb1890188,0x800b0188,0xa00c0188,0xb189000d,0x400e0188,0x71890188,0xb0100188, + 0x30110013,0x41890012,0xa1890188,0x80140188,0xa1890188,0x60160188,0x70170188,0x80180188, + 0x4019001b,0x3189001a,0xa1890188,0xa01c0188,0xb1890188,0x301e0188,0x401f0188,0x10200022, + 0x61890021,0xb1890188,0x60230188,0x70240188,0x81890188,0x90260188,0x70270188,0x80280188, + 0x10290030,0xa02a002d,0xb189002b,0x602c0188,0x41890188,0x602e0188,0x302f0188,0x41890188, + 0x60310188,0x40320034,0x31890033,0xa1890188,0xa0350188,0xb1890188,0x503710a1,0x9038006b, + 0x3039105b,0x403a1053,0xb03b004d,0x103c0044,0x803d0040,0xa03e0188,0x2189003f,0x71890188, + 0x60411188,0x20421188,0x70431188,0x81891188,0x60450048,0x70460188,0x80470188,0xa1890188, + 0x60491188,0x204a1188,0x704b1188,0x1189104c,0x81891188,0x204e1188,0x704f1188,0x10501051, + 0x61891188,0x60521188,0x81891188,0xb0540188,0x80550188,0xa0560188,0x10570059,0x21890058, + 0x71890188,0x605a0188,0x71890188,0xb05c0188,0xa05d0188,0x305e0065,0x105f0062,0x21890060, + 0x70610188,0x81890188,0x60630188,0x70640188,0x81890188,0x80660188,0x10670069,0x21890068, + 0x71890188,0x606a0188,0x71890188,0x906c1093,0x206d0087,0x106e007f,0x406f0077,0xa0700072, + 0x30710188,0xb1890188,0x60731188,0x70741188,0x80751188,0xb0761188,0xa1891188,0x60781188, + 0x70791188,0x807a1188,0xa07b107d,0x4189107c,0xb1891188,0x307e1188,0x41891188,0x60801188, + 0x70811188,0x80821188,0x40831085,0x31891084,0xa1891188,0xa0861188,0xb1891188,0x60881188, + 0x70891188,0x808a108f,0x408b108d,0x3189108c,0xa1891188,0xa08e1188,0xb1891188,0x20901188, + 0x10911188,0x30921188,0x41891188,0x20940099,0x10950188,0x30960188,0x40970188,0xa0980188, + 0xb1890188,0x209a1186,0x309b1188,0x409c1188,0x709d1188,0x109e109f,0x61891188,0x60a01188, + 0x81891188,0x20a200ae,0xa0a30188,0xb0a40188,0x90a500ab,0x10a600a8,0x318900a7,0x81890188, + 0x60a90188,0x70aa0188,0x81890188,0x10ac0188,0x30ad0188,0x41890188,0x90af0188,0x70b00188, + 0x80b10188,0xa0b20188,0xb0b30188,0x118900b4,0x61890188,0x00b6115a,0x20b700e2,0x50b800cc, + 0x70b900c5,0x60ba0188,0x40bb00c1,0x30bc00be,0x118900bd,0x81890188,0x90bf0188,0x80c00188, + 0xa1890188,0x90c20188,0x80c30188,0xa0c40188,0xb1890188,0x90c61188,0x80c71188,0xa0c81188, + 0xb0c91188,0x70ca1188,0x118910cb,0x61891188,0x90cd1188,0x70ce1188,0x80cf1188,0x50d010de, + 0x10d110d8,0xa0d210d5,0xb18910d3,0x60d41188,0x41891188,0x60d61188,0x30d71188,0x41891188, + 0x60d91188,0x40da10dc,0x318910db,0xa1891188,0xa0dd1188,0xb1891188,0xa0df1188,0xb0e01188, + 0x118910e1,0x61891188,0x20e3113a,0x90e4010b,0x50e500ff,0x10e610f7,0x40e710ef,0xa0e810ea, + 0x30e91188,0xb1891188,0x60eb0188,0x70ec0188,0x80ed0188,0xb0ee0188,0xa1890188,0x60f00188, + 0x70f10188,0x80f20188,0xa0f300f5,0x418900f4,0xb1890188,0x30f60188,0x41890188,0x60f80188, + 0x70f90188,0x80fa0188,0x40fb00fd,0x318900fc,0xa1890188,0xa0fe0188,0xb1890188,0x31001188, + 0x41011188,0x51021108,0x11031105,0x61891104,0xb1891188,0x61061188,0x71071188,0x81891188, + 0x11091188,0xa10a1188,0xb1891188,0x910c112e,0x510d1126,0x110e111e,0x610f1118,0x31101113, + 0x41891111,0xa1121188,0xb1891188,0x81141188,0xa1151188,0xb1891116,0x41171188,0x71891188, + 0xb1191188,0x311a111c,0x4189111b,0xa1891188,0x811d1188,0xa1891188,0x611f1188,0x71201188, + 0x81211188,0x41221124,0x31891123,0xa1891188,0xa1251188,0xb1891188,0xa1271188,0xb1281188, + 0x1129112b,0x3189112a,0x81891188,0x612c1188,0x712d1188,0x81891188,0x312f1188,0x41301188, + 0x51311137,0x11321134,0x61891133,0xb1891188,0x61351188,0x71361188,0x81891188,0x11381188, + 0xa1391188,0xb1891188,0x913b1150,0x713c1188,0x813d1188,0x513e114c,0x113f1146,0xa1401143, + 0xb1891141,0x61421188,0x41891188,0x61441188,0x31451188,0x41891188,0x61471188,0x4148114a, + 0x31891149,0xa1891188,0xa14b1188,0xb1891188,0xa14d1188,0xb14e1188,0x1189114f,0x61891188, + 0x51510188,0x91520186,0x61530188,0x71540188,0x81550188,0x41560158,0x31890157,0xa1890188, + 0xa1590188,0xb1890188,0x515b0170,0x915c0168,0x615d0188,0x715e0188,0x415f0165,0x31600163, + 0x81890161,0x11620188,0x21890188,0x81640188,0xa1890188,0xb1660188,0x81670188,0xa1890188, + 0x21690188,0x316a0188,0x416b0188,0x716c0188,0x116d016e,0x61890188,0x616f0188,0x81890188, + 0x51711186,0x9172117e,0x61731188,0x71741188,0x4175117b,0x31761179,0x81891177,0x11781188, + 0x21891188,0x817a1188,0xa1891188,0xb17c1188,0x817d1188,0xa1891188,0x217f1188,0x31801188, + 0x41811188,0x71821188,0x11831184,0x61891188,0x61851188,0x81891188,0x000000fc,0x000000fd, + 0x000000fe,0x000000ff + }; + + static const uint32_t table_7_12s_struct1[] = + { + 0x00010091,0x20020064,0x50030031,0x90040026,0x7005001c,0x10060015,0x6007000f,0x3008000b, + 0x41590009,0xa00a0156,0xb1590158,0x800c0156,0xa00d0156,0x4159000e,0xb1590158,0xb0100156, + 0x30110013,0x41590012,0xa1590156,0x80140156,0xa1590156,0x60160156,0x80170156,0x4018001a, + 0x31590019,0xa1590156,0xa01b0156,0xb1590156,0x101d0156,0xb01e0023,0x301f0021,0x41570020, + 0xa1570156,0x80220156,0xa1570156,0x60240156,0x30250156,0x41570156,0x30270156,0x40280156, + 0x7029002e,0x102a002c,0x6157002b,0xb1570156,0x602d0156,0x81570156,0x102f0156,0x61570030, + 0xb1570156,0x90321055,0x70331050,0x5034104b,0x10350044,0x4036003d,0xa0370039,0x30380156, + 0xb1590158,0x603a1156,0x803b1156,0xb03c1158,0xa1591158,0x603e1156,0x803f1156,0xa0401042, + 0x41591041,0xb1591158,0x30431156,0x41591158,0x60451156,0x80461156,0x40471049,0x31591048, + 0xa1591156,0xa04a1156,0xb1591156,0x104c0156,0x304d0156,0x404e0156,0xa04f0156,0xb1590156, + 0x10510156,0x30520156,0x40530156,0xa0540156,0xb1570156,0xa0560156,0xb0570156,0x90580061, + 0x7059005e,0x105a005c,0x3157005b,0x81570156,0x605d0156,0x81570156,0x105f0156,0x31570060, + 0x81570156,0x10620156,0x30630156,0x41570156,0x7065007a,0x90660156,0x80670156,0x50680076, + 0x10690070,0xa06a006d,0xb157006b,0x606c0156,0x41590156,0x606e0156,0x306f0156,0x41590156, + 0x60710156,0x40720074,0x31570073,0xa1570156,0xa0750156,0xb1570156,0xa0770156,0xb0780156, + 0x11570079,0x61570156,0x707b1156,0x507c1156,0x207d1089,0x607e1156,0x407f1085,0x30801082, + 0x11571081,0x81571156,0x90831156,0x80841156,0xa1591156,0x90861156,0x80871156,0xa0881156, + 0xb1591156,0x908a1156,0x608b1156,0x808c1156,0x408d108f,0x3157108e,0xa1571156,0xa0901156, + 0xb1571156,0x0092112c,0x209310ff,0x909410c2,0x509510b7,0x709610ad,0x109710a6,0x609810a0, + 0x3099109c,0x4159109a,0xa09b1156,0xb1591158,0x809d1156,0xa09e1156,0x4159109f,0xb1591158, + 0xb0a11156,0x30a210a4,0x415910a3,0xa1591156,0x80a51156,0xa1591156,0x60a71156,0x80a81156, + 0x40a910ab,0x315910aa,0xa1591156,0xa0ac1156,0xb1591156,0x10ae1156,0xb0af10b4,0x30b010b2, + 0x415710b1,0xa1571156,0x80b31156,0xa1571156,0x60b51156,0x30b61156,0x41571156,0xa0b81156, + 0xb0b91156,0x70ba10bf,0x10bb10bd,0x315710bc,0x81571156,0x60be1156,0x81571156,0x10c01156, + 0x315710c1,0x81571156,0x90c300f0,0x50c400e1,0x70c500dc,0x10c610d5,0x40c710ce,0xa0c810ca, + 0x30c91156,0xb1591158,0x60cb0156,0x80cc0156,0xb0cd0158,0xa1590158,0x60cf0156,0x80d00156, + 0xa0d100d3,0x415900d2,0xb1590158,0x30d40156,0x41590158,0x60d60156,0x80d70156,0x40d800da, + 0x315900d9,0xa1590156,0xa0db0156,0xb1590156,0x10dd1156,0x30de1156,0x40df1156,0xa0e01156, + 0xb1591156,0x30e21156,0x40e31156,0x50e410ed,0x70e510ea,0x10e610e8,0x615910e7,0xb1591156, + 0x60e91156,0x81591156,0x10eb1156,0x615710ec,0xb1571156,0x10ee1156,0xa0ef1156,0xb1571156, + 0x30f11156,0x40f21156,0x50f310fc,0x70f410f9,0x10f510f7,0x615710f6,0xb1571156,0x60f81156, + 0x81571156,0x10fa1156,0x615710fb,0xb1571156,0x10fd1156,0xa0fe1156,0xb1571156,0x71000116, + 0x51010156,0x2102010e,0x61030156,0x4104010a,0x31050107,0x11570106,0x81570156,0x91080156, + 0x81090156,0xa1590156,0x910b0156,0x810c0156,0xa10d0156,0xb1590156,0x910f0156,0x61100156, + 0x81110156,0x41120114,0x31570113,0xa1570156,0xa1150156,0xb1570156,0x71171156,0x91181156, + 0x81191156,0x511a1128,0x111b1122,0xa11c111f,0xb157111d,0x611e1156,0x41591156,0x61201156, + 0x31211156,0x41591156,0x61231156,0x41241126,0x31571125,0xa1571156,0xa1271156,0xb1571156, + 0xa1291156,0xb12a1156,0x1157112b,0x61571156,0x512d0141,0x712e0156,0x912f013a,0x61300156, + 0x41310137,0x31320135,0x81570133,0x11340156,0x21570156,0x81360156,0xa1570156,0xb1380156, + 0x81390156,0xa1570156,0x213b0156,0x313c0156,0x413d0156,0x113e013f,0x61570156,0x61400156, + 0x81570156,0x51421156,0x71431156,0x9144114f,0x61451156,0x4146114c,0x3147114a,0x81571148, + 0x11491156,0x21571156,0x814b1156,0xa1571156,0xb14d1156,0x814e1156,0xa1571156,0x21501156, + 0x31511156,0x41521156,0x11531154,0x61571156,0x61551156,0x81571156,0x000000fc,0x000000fd, + 0x000000fe,0x000000ff + }; + + static const uint32_t table_7_12s_struct2[] = + { + 0x00010092,0x20020065,0x50030031,0x90040026,0x7005001c,0x10060015,0x6007000f,0x3008000b, + 0x41400009,0xa00a013f,0xb140013f,0x800c013f,0xa00d013f,0x4140000e,0xb140013f,0xb010013f, + 0x30110013,0x41400012,0xa140013f,0x8014013f,0xa140013f,0x6016013f,0x8017013f,0x4018001a, + 0x31400019,0xa140013f,0xa01b013f,0xb140013f,0x101d013f,0xb01e0023,0x301f0021,0x41400020, + 0xa140013f,0x8022013f,0xa140013f,0x6024013f,0x3025013f,0x4140013f,0x3027013f,0x4028013f, + 0x7029002e,0x102a002c,0x6140002b,0xb140013f,0x602d013f,0x8140013f,0x102f013f,0x61400030, + 0xb140013f,0x70321059,0x90331050,0x5034104b,0x10350044,0x4036003d,0xa0370039,0x3038013f, + 0xb140013f,0x603a113f,0x803b113f,0xb03c113f,0xa140113f,0x603e113f,0x803f113f,0xa0401042, + 0x41401041,0xb140113f,0x3043113f,0x4140113f,0x6045113f,0x8046113f,0x40471049,0x31401048, + 0xa140113f,0xa04a113f,0xb140113f,0x104c013f,0x304d013f,0x404e013f,0xa04f013f,0xb140013f, + 0xa051013f,0xb052013f,0x90530056,0x1054013f,0x31400055,0x8140013f,0x1057013f,0x3058013f, + 0x4140013f,0xa05a013f,0xb05b013f,0x905c0062,0x105d005f,0x3140005e,0x8140013f,0x6060013f, + 0x8061013f,0x7140013f,0x1063013f,0x3064013f,0x4140013f,0x7066007b,0x9067013f,0x8068013f, + 0x50690077,0x106a0071,0xa06b006e,0xb140006c,0x606d013f,0x4140013f,0x606f013f,0x3070013f, + 0x4140013f,0x6072013f,0x40730075,0x31400074,0xa140013f,0xa076013f,0xb140013f,0xa078013f, + 0xb079013f,0x1140007a,0x6140013f,0x707c113f,0x507d113f,0x207e108a,0x607f113f,0x40801086, + 0x30811083,0x11401082,0x8140113f,0x9084113f,0x8085113f,0xa140113f,0x9087113f,0x8088113f, + 0xa089113f,0xb140113f,0x908b113f,0x608c113f,0x808d113f,0x408e1090,0x3140108f,0xa140113f, + 0xa091113f,0xb140113f,0x00931113,0x209410e6,0xb09510c8,0x309610b9,0x509710a9,0x909810a3, + 0x709910a0,0x109a109c,0x4140109b,0xa140113f,0x609d113f,0x809e113f,0x4140109f,0xa140113f, + 0x10a1113f,0x414010a2,0xa140113f,0x40a4113f,0x70a510a8,0x114010a6,0x60a7113f,0x8140113f, + 0x1140113f,0xa0aa10b2,0x90ab10b0,0x70ac10af,0x114010ad,0x60ae113f,0x8140113f,0x1140113f, + 0x10b1113f,0x4140113f,0x70b3013f,0x90b4013f,0x50b5013f,0x40b6013f,0x60b7013f,0x80b8013f, + 0xa140013f,0x90ba10c0,0x80bb113f,0xa0bc113f,0x70bd10bf,0x114010be,0x6140113f,0x1140113f, + 0x50c1013f,0x70c2013f,0x90c3013f,0x40c4013f,0x60c5013f,0x80c6013f,0x314000c7,0xa140013f, + 0x40c910dc,0x50ca10d5,0x70cb10d2,0x60cc113f,0x30cd10cf,0x114010ce,0x8140113f,0x90d0113f, + 0x80d1113f,0xa140113f,0x10d3113f,0x60d4113f,0x3140113f,0x70d6013f,0x90d7013f,0x50d8013f, + 0x60d9013f,0x80da013f,0xa0db013f,0xb140013f,0x50dd013f,0x70de013f,0x90df013f,0x60e0013f, + 0x80e1013f,0xa0e200e4,0x414000e3,0xb140013d,0x30e5013f,0x4140013f,0x70e700fd,0x50e8013f, + 0x20e900f5,0x60ea013f,0x40eb00f1,0x30ec00ee,0x114000ed,0x8140013f,0x90ef013f,0x80f0013f, + 0xa140013f,0x90f2013f,0x80f3013f,0xa0f4013f,0xb140013f,0x90f6013f,0x60f7013f,0x80f8013f, + 0x40f900fb,0x314000fa,0xa140013f,0xa0fc013f,0xb140013f,0x70fe113f,0x90ff113f,0x8100113f, + 0x5101110f,0x11021109,0xa1031106,0xb1401104,0x6105113f,0x4140113f,0x6107113f,0x3108113f, + 0x4140113f,0x610a113f,0x410b110d,0x3140110c,0xa140113f,0xa10e113f,0xb140113f,0xa110113f, + 0xb111113f,0x11401112,0x6140113f,0x51140128,0x7115013f,0x91160121,0x6117013f,0x4118011e, + 0x3119011c,0x8140011a,0x111b013f,0x2140013f,0x811d013f,0xa140013f,0xb11f013f,0x8120013f, + 0xa140013f,0x2122013f,0x3123013f,0x4124013f,0x11250126,0x6140013f,0x6127013f,0x8140013f, + 0x5129113d,0x712a113f,0x912b1136,0x612c113f,0x412d1133,0x312e1131,0x8140112f,0x1130113f, + 0x2140113f,0x8132113f,0xa140113f,0xb134113f,0x8135113f,0xa140113f,0x2137113f,0x3138113f, + 0x4139113f,0x113a113b,0x6140113f,0x613c113f,0x8140113f,0x000000fc,0x000000fd,0x000000fe, + 0x000000ff + }; + + static const uint32_t table_9_16_struct[] = + { + 0x00010138,0x200200d3,0x4003008a,0x50040051,0x70050027,0x30060016,0x1007000d,0x6008000a, + 0x82ad0009,0xf2ad02ac,0xd00b02ac,0xe00c02ac,0xf2ad02ac,0x800e02ac,0x900f02ac,0xa01002ac, + 0x62ad0011,0xb01202ac,0xc01302ac,0xd01402ac,0xe01502ac,0xf2ad02ac,0xa01702ac,0xb01802ac, + 0xc01902ac,0x801a0023,0x901b001f,0x62ad001c,0xd01d02ac,0xe01e02ac,0xf2ad02ac,0x102002ac, + 0xd02102ac,0xe02202ac,0xf2ad02ac,0x102402ac,0xd02502ac,0xe02602ac,0xf2ad02ac,0x70281041, + 0xe0290038,0xf02a02ac,0x102b0032,0x302c002e,0x62ad002d,0xd2ad02ac,0xa02f02ac,0xb03002ac, + 0xc03102ac,0xd2ad02ac,0x803302ac,0x903402ac,0xa03502ac,0xb03602ac,0xc03702ac,0xd2ad02ac, + 0xe03912ac,0x803a12ac,0x903b12ac,0xa03c12ac,0xb03d12ac,0xc03e12ac,0xd03f12ac,0x62ad1040, + 0xf2ad12ac,0xe04202ac,0xf04302ac,0x1044004b,0x30450047,0x62ad0046,0xd2ad02ac,0xa04802ac, + 0xb04902ac,0xc04a02ac,0xd2ad02ac,0x804c02ac,0x904d02ac,0xa04e02ac,0xb04f02ac,0xc05002ac, + 0xd2ad02ac,0x5052106e,0xc0530064,0xd05402ac,0xe05502ac,0xf056005e,0x1057005a,0x32ad0058, + 0xa05902ac,0xb2ad02ac,0x805b02ac,0x905c02ac,0xa05d02ac,0xb2ad02ac,0x605f02ac,0x706002ac, + 0x806102ac,0x906202ac,0xa06302ac,0xb2ad02ac,0xc06512ac,0x706612ac,0x806712ac,0x906812ac, + 0xa06912ac,0xb06a12ac,0xd06b12ac,0x62ad106c,0xe06d12ac,0xf2ad12ac,0xc06f0080,0xd07002ac, + 0xe07102ac,0xf072007a,0x10730076,0x32ad0074,0xa07502ac,0xb2ad02ac,0x807702ac,0x907802ac, + 0xa07902ac,0xb2ad02ac,0x607b02ac,0x707c02ac,0x807d02ac,0x907e02ac,0xa07f02ac,0xb2ad02ac, + 0xc08112ac,0x708212ac,0x808312ac,0x908412ac,0xa08512ac,0xb08612ac,0xd08712ac,0xe08812ac, + 0x62ad1089,0xf2ad12ac,0x408b10b1,0xb08c00a1,0xc08d02ac,0xd08e02ac,0xa08f009d,0xe0900098, + 0xf0910094,0x12ad0092,0x809302ac,0x92ad02ac,0x609502ac,0x709602ac,0x809702ac,0x92ad02ac, + 0x509902ac,0x609a02ac,0x709b02ac,0x809c02ac,0x92ad02ac,0x109e02ac,0x309f02ac,0xe0a002ac, + 0xf2ad02ac,0xb0a212ac,0x70a312ac,0x80a412ac,0x90a512ac,0xa0a612ac,0x60a710ad,0x50a810aa, + 0x32ad10a9,0xc2ad12ac,0xc0ab12ac,0xd0ac12ac,0xe2ad12ac,0xc0ae12ac,0xd0af12ac,0xe0b012ac, + 0xf2ad12ac,0xb0b200c7,0xc0b302ac,0xd0b402ac,0xa0b500c3,0xe0b600be,0xf0b700ba,0x12ad00b8, + 0x80b902ac,0x92ad02ac,0x60bb02ac,0x70bc02ac,0x80bd02ac,0x92ad02ac,0x50bf02ac,0x60c002ac, + 0x70c102ac,0x80c202ac,0x92ad02ac,0x10c402ac,0x30c502ac,0xe0c602ac,0xf2ad02ac,0xb0c812ac, + 0x70c912ac,0x80ca12ac,0x90cb12ac,0xa0cc12ac,0xc0cd12ac,0xd0ce12ac,0x60cf10d1,0x52ad10d0, + 0xe2ad12ac,0xe0d212ac,0xf2ad12ac,0x20d4110a,0x90d500ef,0xa0d602ac,0xb0d702ac,0x80d800ea, + 0xc0d900e5,0xd0da00e1,0xe0db00de,0xf2ad00dc,0x60dd02ac,0x72ad02ac,0x50df02ac,0x60e002ac, + 0x72ad02ac,0x40e202ac,0x50e302ac,0x60e402ac,0x72ad02ac,0x30e602ac,0x40e702ac,0x50e802ac, + 0x60e902ac,0x72ad02ac,0x10eb02ac,0xc0ec02ac,0xd0ed02ac,0xe0ee02ac,0xf2ad02ac,0x90f012ac, + 0x70f112ac,0x80f212ac,0x60f31104,0x50f410ff,0x40f510fb,0x30f610f8,0x12ad10f7,0xa2ad12ac, + 0xa0f912ac,0xb0fa12ac,0xc2ad12ac,0xa0fc12ac,0xb0fd12ac,0xc0fe12ac,0xd2ad12ac,0xa10012ac, + 0xb10112ac,0xc10212ac,0xd10312ac,0xe2ad12ac,0xa10512ac,0xb10612ac,0xc10712ac,0xd10812ac, + 0xe10912ac,0xf2ad12ac,0x910b0125,0xa10c02ac,0xb10d02ac,0x810e0120,0xc10f011b,0xd1100117, + 0xe1110114,0xf2ad0112,0x611302ac,0x72ad02ac,0x511502ac,0x611602ac,0x72ad02ac,0x411802ac, + 0x511902ac,0x611a02ac,0x72ad02ac,0x311c02ac,0x411d02ac,0x511e02ac,0x611f02ac,0x72ad02ac, + 0x112102ac,0xc12202ac,0xd12302ac,0xe12402ac,0xf2ad02ac,0x912612ac,0x712712ac,0x812812ac, + 0xa12912ac,0xb12a12ac,0x612b1134,0x512c1131,0x412d112f,0x32ad112e,0xc2ad12ac,0xc13012ac, + 0xd2ad12ac,0xc13212ac,0xd13312ac,0xe2ad12ac,0xc13512ac,0xd13612ac,0xe13712ac,0xf2ad12ac, + 0x01391270,0x213a0170,0x913b0155,0x713c02ac,0x813d02ac,0x613e014f,0x513f014a,0x41400146, + 0x31410143,0x12ad0142,0xa2ad02ac,0xa14402ac,0xb14502ac,0xc2ad02ac,0xa14702ac,0xb14802ac, + 0xc14902ac,0xd2ad02ac,0xa14b02ac,0xb14c02ac,0xc14d02ac,0xd14e02ac,0xe2ad02ac,0xa15002ac, + 0xb15102ac,0xc15202ac,0xd15302ac,0xe15402ac,0xf2ad02ac,0x915612ac,0xa15712ac,0xb15812ac, + 0x8159116b,0xc15a1166,0xd15b1162,0xe15c115f,0xf2ad115d,0x615e12ac,0x72ad12ac,0x516012ac, + 0x616112ac,0x72ad12ac,0x416312ac,0x516412ac,0x616512ac,0x72ad12ac,0x316712ac,0x416812ac, + 0x516912ac,0x616a12ac,0x72ad12ac,0x116c12ac,0xc16d12ac,0xd16e12ac,0xe16f12ac,0xf2ad12ac, + 0x21711242,0x41720198,0xb1730182,0x717402ac,0x817502ac,0x917602ac,0xa17702ac,0x6178017e, + 0x5179017b,0x32ad017a,0xc2ad02ac,0xc17c02ac,0xd17d02ac,0xe2ad02ac,0xc17f02ac,0xd18002ac, + 0xe18102ac,0xf2ad02ac,0xb18312ac,0xc18412ac,0xd18512ac,0xa1861194,0xe187118f,0xf188118b, + 0x12ad1189,0x818a12ac,0x92ad12ac,0x618c12ac,0x718d12ac,0x818e12ac,0x92ad12ac,0x519012ac, + 0x619112ac,0x719212ac,0x819312ac,0x92ad12ac,0x119512ac,0x319612ac,0xe19712ac,0xf2ad12ac, + 0x41991220,0x519a01b6,0xc19b01a4,0x719c02ac,0x819d02ac,0x919e02ac,0xa19f02ac,0xb1a002ac, + 0xd1a102ac,0x62ad01a2,0xe1a302ac,0xf2ad02ac,0xc1a512ac,0xd1a612ac,0xe1a712ac,0xf1a811b0, + 0x11a911ac,0x32ad11aa,0xa1ab12ac,0xb2ad12ac,0x81ad12ac,0x91ae12ac,0xa1af12ac,0xb2ad12ac, + 0x61b112ac,0x71b212ac,0x81b312ac,0x91b412ac,0xa1b512ac,0xb2ad12ac,0x51b71204,0x71b801d1, + 0xe1b901c1,0x81ba02ac,0x91bb02ac,0xa1bc02ac,0xb1bd02ac,0xc1be02ac,0xd1bf02ac,0x62ad01c0, + 0xf2ad02ac,0xe1c212ac,0xf1c312ac,0x11c411cb,0x31c511c7,0x62ad11c6,0xd2ad12ac,0xa1c812ac, + 0xb1c912ac,0xc1ca12ac,0xd2ad12ac,0x81cc12ac,0x91cd12ac,0xa1ce12ac,0xb1cf12ac,0xc1d012ac, + 0xd2ad12ac,0x71d211f4,0x31d311e3,0x11d411da,0x61d511d7,0x82ad11d6,0xf2ad12ac,0xd1d812ac, + 0xe1d912ac,0xf2ad12ac,0x81db12ac,0x91dc12ac,0xa1dd12ac,0x62ad11de,0xb1df12ac,0xc1e012ac, + 0xd1e112ac,0xe1e212ac,0xf2ad12ac,0xa1e412ac,0xb1e512ac,0xc1e612ac,0x81e711f0,0x91e811ec, + 0x62ad11e9,0xd1ea12ac,0xe1eb12ac,0xf2ad12ac,0x11ed12ac,0xd1ee12ac,0xe1ef12ac,0xf2ad12ac, + 0x11f112ac,0xd1f212ac,0xe1f312ac,0xf2ad12ac,0xe1f512ac,0xf1f612ac,0x11f711fe,0x31f811fa, + 0x62ad11f9,0xd2ad12ac,0xa1fb12ac,0xb1fc12ac,0xc1fd12ac,0xd2ad12ac,0x81ff12ac,0x920012ac, + 0xa20112ac,0xb20212ac,0xc20312ac,0xd2ad12ac,0xc205020e,0x720602ac,0x820702ac,0x920802ac, + 0xa20902ac,0xb20a02ac,0xd20b02ac,0xe20c02ac,0x62ad020d,0xf2ad02ac,0xc20f12ac,0xd21012ac, + 0xe21112ac,0xf212121a,0x12131216,0x32ad1214,0xa21512ac,0xb2ad12ac,0x821712ac,0x921812ac, + 0xa21912ac,0xb2ad12ac,0x621b12ac,0x721c12ac,0x821d12ac,0x921e12ac,0xa21f12ac,0xb2ad12ac, + 0xb221022c,0x722202ac,0x822302ac,0x922402ac,0xa22502ac,0xc22602ac,0xd22702ac,0x6228022a, + 0x52ad0229,0xe2ad02ac,0xe22b02ac,0xf2ad02ac,0xb22d12ac,0xc22e12ac,0xd22f12ac,0xa230123e, + 0xe2311239,0xf2321235,0x12ad1233,0x823412ac,0x92ad12ac,0x623612ac,0x723712ac,0x823812ac, + 0x92ad12ac,0x523a12ac,0x623b12ac,0x723c12ac,0x823d12ac,0x92ad12ac,0x123f12ac,0x324012ac, + 0xe24112ac,0xf2ad12ac,0x92430255,0x724402ac,0x824502ac,0xa24602ac,0xb24702ac,0x62480251, + 0x5249024e,0x424a024c,0x32ad024b,0xc2ad02ac,0xc24d02ac,0xd2ad02ac,0xc24f02ac,0xd25002ac, + 0xe2ad02ac,0xc25202ac,0xd25302ac,0xe25402ac,0xf2ad02ac,0x925612ac,0xa25712ac,0xb25812ac, + 0x8259126b,0xc25a1266,0xd25b1262,0xe25c125f,0xf2ad125d,0x625e12ac,0x72ad12ac,0x526012ac, + 0x626112ac,0x72ad12ac,0x426312ac,0x526412ac,0x626512ac,0x72ad12ac,0x326712ac,0x426812ac, + 0x526912ac,0x626a12ac,0x72ad12ac,0x126c12ac,0xc26d12ac,0xd26e12ac,0xe26f12ac,0xf2ad12ac, + 0x7271028e,0x827202ac,0x927302ac,0x62740288,0x52750283,0x4276027f,0x3277027c,0x2278027a, + 0x12ad0279,0xa2ad02ac,0xa27b02ac,0xb2ad02ac,0xa27d02ac,0xb27e02ac,0xc2ad02ac,0xa28002ac, + 0xb28102ac,0xc28202ac,0xd2ad02ac,0xa28402ac,0xb28502ac,0xc28602ac,0xd28702ac,0xe2ad02ac, + 0xa28902ac,0xb28a02ac,0xc28b02ac,0xd28c02ac,0xe28d02ac,0xf2ad02ac,0x728f12ac,0x829012ac, + 0x929112ac,0x629212a6,0x529312a1,0x4294129d,0x3295129a,0x22961298,0x12ad1297,0xa2ad12ac, + 0xa29912ac,0xb2ad12ac,0xa29b12ac,0xb29c12ac,0xc2ad12ac,0xa29e12ac,0xb29f12ac,0xc2a012ac, + 0xd2ad12ac,0xa2a212ac,0xb2a312ac,0xc2a412ac,0xd2a512ac,0xe2ad12ac,0xa2a712ac,0xb2a812ac, + 0xc2a912ac,0xd2aa12ac,0xe2ab12ac,0xf2ad12ac,0x000000fc,0x000000fd,0x000000fe,0x000000ff + }; + switch(agasttype) { + case AgastFeatureDetector::AGAST_5_8: + agastbase=0; + table_struct1=(uint32_t *)(table_5_8_struct1); + table_struct2=(uint32_t *)(table_5_8_struct2); + break; + case AgastFeatureDetector::AGAST_7_12d: + agastbase=2; + table_struct1=(uint32_t *)(table_7_12d_struct1); + table_struct2=(uint32_t *)(table_7_12d_struct2); + break; + case AgastFeatureDetector::AGAST_7_12s: + agastbase=1; + table_struct1=(uint32_t *)(table_7_12s_struct1); + table_struct2=(uint32_t *)(table_7_12s_struct2); + break; + case AgastFeatureDetector::OAST_9_16: + default: + agastbase=2; + table_struct1=(uint32_t *)(table_9_16_struct); + table_struct2=(uint32_t *)(table_9_16_struct); + break; + } + + size_t total = 0; + int xsize = img.cols; + int ysize = img.rows; + size_t nExpectedCorners = keypoints.capacity(); + int x, y; + int xsizeB = xsize - (agastbase + 2); + int ysizeB = ysize - (agastbase + 1); + int width; + + keypoints.resize(0); + + int pixel[16]; + makeAgastOffsets(pixel, (int)img.step, agasttype); + + width = xsize; + + for(y = agastbase+1; y < ysizeB; y++) + { + x = agastbase; + while(true) + { + homogeneous: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + result = agast_tree_search(table_struct1, pixel, ptr, threshold); + switch (result) + { + case 252: + goto homogeneous; + case 253: + goto success_homogeneous; + case 254: + goto structured; + case 255: + goto success_structured; + } + } + } + structured: + { + x++; + if(x > xsizeB) + break; + else + { + const unsigned char* const ptr = img.ptr() + y*width + x; + result = agast_tree_search(table_struct2, pixel, ptr, threshold); + switch (result) + { + case 252: + goto homogeneous; + case 253: + goto success_homogeneous; + case 254: + goto structured; + case 255: + goto success_structured; + } + } + } + success_homogeneous: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto homogeneous; + success_structured: + if(total == nExpectedCorners) + { + if(nExpectedCorners == 0) + { + nExpectedCorners = 512; + keypoints.reserve(nExpectedCorners); + } + else + { + nExpectedCorners *= 2; + keypoints.reserve(nExpectedCorners); + } + } + keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f)); + total++; + goto structured; + } + } +} + +static void AGAST_5_8(InputArray _img, std::vector& keypoints, int threshold) +{ + AGAST_ALL(_img, keypoints, threshold, AgastFeatureDetector::AGAST_5_8); +} + +static void AGAST_7_12d(InputArray _img, std::vector& keypoints, int threshold) +{ + AGAST_ALL(_img, keypoints, threshold, AgastFeatureDetector::AGAST_7_12d); +} + +static void AGAST_7_12s(InputArray _img, std::vector& keypoints, int threshold) +{ + AGAST_ALL(_img, keypoints, threshold, AgastFeatureDetector::AGAST_7_12s); +} + +static void OAST_9_16(InputArray _img, std::vector& keypoints, int threshold) +{ + AGAST_ALL(_img, keypoints, threshold, AgastFeatureDetector::OAST_9_16); +} + +#endif // !(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) + +class AgastFeatureDetector_Impl CV_FINAL : public AgastFeatureDetector +{ +public: + AgastFeatureDetector_Impl( int _threshold, bool _nonmaxSuppression, DetectorType _type ) + : threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type(_type) + {} + + void read( const FileNode& fn) CV_OVERRIDE + { + // if node is empty, keep previous value + if (!fn["threshold"].empty()) + fn["threshold"] >> threshold; + if (!fn["nonmaxSuppression"].empty()) + fn["nonmaxSuppression"] >> nonmaxSuppression; + if (!fn["type"].empty()) + fn["type"] >> type; + } + void write( FileStorage& fs) const CV_OVERRIDE + { + if(fs.isOpened()) + { + fs << "name" << getDefaultName(); + fs << "threshold" << threshold; + fs << "nonmaxSuppression" << nonmaxSuppression; + fs << "type" << type; + } + } + + void detect( InputArray _image, std::vector& keypoints, InputArray _mask ) CV_OVERRIDE + { + CV_INSTRUMENT_REGION(); + + if(_image.empty()) + { + keypoints.clear(); + return; + } + + Mat mask = _mask.getMat(), grayImage; + UMat ugrayImage; + _InputArray gray = _image; + if( _image.type() != CV_8U ) + { + _OutputArray ogray = _image.isUMat() ? _OutputArray(ugrayImage) : _OutputArray(grayImage); + cvtColor( _image, ogray, COLOR_BGR2GRAY ); + gray = ogray; + } + keypoints.clear(); + AGAST( gray, keypoints, threshold, nonmaxSuppression, type ); + KeyPointsFilter::runByPixelsMask( keypoints, mask ); + } + + void set(int prop, double value) + { + if(prop == THRESHOLD) + threshold = cvRound(value); + else if(prop == NONMAX_SUPPRESSION) + nonmaxSuppression = value != 0; + else + CV_Error(Error::StsBadArg, ""); + } + + double get(int prop) const + { + if(prop == THRESHOLD) + return threshold; + if(prop == NONMAX_SUPPRESSION) + return nonmaxSuppression; + CV_Error(Error::StsBadArg, ""); + return 0; + } + + void setThreshold(int threshold_) CV_OVERRIDE { threshold = threshold_; } + int getThreshold() const CV_OVERRIDE { return threshold; } + + void setNonmaxSuppression(bool f) CV_OVERRIDE { nonmaxSuppression = f; } + bool getNonmaxSuppression() const CV_OVERRIDE { return nonmaxSuppression; } + + void setType(int type_) CV_OVERRIDE{ type = type_; } + int getType() const CV_OVERRIDE{ return type; } + + int threshold; + bool nonmaxSuppression; + int type; +}; + +Ptr AgastFeatureDetector::create( int threshold, bool nonmaxSuppression, AgastFeatureDetector::DetectorType type ) +{ + return makePtr(threshold, nonmaxSuppression, type); +} + +void AGAST(InputArray _img, std::vector& keypoints, int threshold, bool nonmax_suppression, AgastFeatureDetector::DetectorType type) +{ + CV_INSTRUMENT_REGION(); + + std::vector kpts; + + // detect + switch(type) { + case AgastFeatureDetector::AGAST_5_8: + AGAST_5_8(_img, kpts, threshold); + break; + case AgastFeatureDetector::AGAST_7_12d: + AGAST_7_12d(_img, kpts, threshold); + break; + case AgastFeatureDetector::AGAST_7_12s: + AGAST_7_12s(_img, kpts, threshold); + break; + case AgastFeatureDetector::OAST_9_16: + OAST_9_16(_img, kpts, threshold); + break; + } + + cv::Mat img = _img.getMat(); + + // score + int pixel_[16]; + makeAgastOffsets(pixel_, (int)img.step, type); + + std::vector::iterator kpt; + for(kpt = kpts.begin(); kpt != kpts.end(); ++kpt) + { + switch(type) { + case AgastFeatureDetector::AGAST_5_8: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + case AgastFeatureDetector::AGAST_7_12d: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + case AgastFeatureDetector::AGAST_7_12s: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + case AgastFeatureDetector::OAST_9_16: + kpt->response = (float)agast_cornerScore + (&img.at((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold); + break; + } + } + + // suppression + if(nonmax_suppression) + { + size_t j; + size_t curr_idx; + size_t lastRow = 0, next_lastRow = 0; + size_t num_Corners = kpts.size(); + size_t lastRowCorner_ind = 0, next_lastRowCorner_ind = 0; + + std::vector nmsFlags; + std::vector::const_iterator currCorner; + + currCorner = kpts.begin(); + + nmsFlags.resize((int)num_Corners); + + // set all flags to MAXIMUM + for(j = 0; j < num_Corners; j++) + nmsFlags[j] = -1; + + for(curr_idx = 0; curr_idx < num_Corners; curr_idx++) + { + int t; + // check above + if(lastRow + 1 < currCorner->pt.y) + { + lastRow = next_lastRow; + lastRowCorner_ind = next_lastRowCorner_ind; + } + if(next_lastRow != currCorner->pt.y) + { + next_lastRow = (size_t) currCorner->pt.y; + next_lastRowCorner_ind = curr_idx; + } + if(lastRow + 1 == currCorner->pt.y) + { + // find the corner above the current one + while( (kpts[lastRowCorner_ind].pt.x < currCorner->pt.x) + && (kpts[lastRowCorner_ind].pt.y == lastRow) ) + lastRowCorner_ind++; + + if( (kpts[lastRowCorner_ind].pt.x == currCorner->pt.x) + && (lastRowCorner_ind != curr_idx) ) + { + size_t w = lastRowCorner_ind; + // find the maximum in this block + while(nmsFlags[w] != -1) + w = nmsFlags[w]; + + if(kpts[curr_idx].response < kpts[w].response) + nmsFlags[curr_idx] = (int)w; + else + nmsFlags[w] = (int)curr_idx; + } + } + + // check left + t = (int)curr_idx - 1; + if( (curr_idx != 0) && (kpts[t].pt.y == currCorner->pt.y) + && (kpts[t].pt.x + 1 == currCorner->pt.x) ) + { + int currCornerMaxAbove_ind = nmsFlags[curr_idx]; + // find the maximum in that area + while(nmsFlags[t] != -1) + t = nmsFlags[t]; + // no maximum above + if(currCornerMaxAbove_ind == -1) + { + if((size_t)t != curr_idx) + { + if ( kpts[curr_idx].response < kpts[t].response ) + nmsFlags[curr_idx] = t; + else + nmsFlags[t] = (int)curr_idx; + } + } + else // maximum above + { + if(t != currCornerMaxAbove_ind) + { + if(kpts[currCornerMaxAbove_ind].response < kpts[t].response) + { + nmsFlags[currCornerMaxAbove_ind] = t; + nmsFlags[curr_idx] = t; + } + else + { + nmsFlags[t] = currCornerMaxAbove_ind; + nmsFlags[curr_idx] = currCornerMaxAbove_ind; + } + } + } + } + ++currCorner; + } + + // collecting maximum corners + for(curr_idx = 0; curr_idx < num_Corners; curr_idx++) + { + if (nmsFlags[curr_idx] == -1) + keypoints.push_back(kpts[curr_idx]); + } + } else + { + keypoints = kpts; + } +} + +String AgastFeatureDetector::getDefaultName() const +{ + return(Feature2D::getDefaultName() + ".AgastFeatureDetector"); +} + +} +} // END NAMESPACE CV diff --git a/modules/xfeatures2d/src/agast_score.cpp b/modules/xfeatures2d/src/agast_score.cpp new file mode 100644 index 00000000000..913cc778942 --- /dev/null +++ b/modules/xfeatures2d/src/agast_score.cpp @@ -0,0 +1,9866 @@ +/* This is AGAST and OAST, an optimal and accelerated corner detector + based on the accelerated segment tests + Below is the original copyright and the references */ + +/* +Copyright (C) 2010 Elmar Mair +All rights reserved. + +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. + + *Neither the name of the University of Cambridge nor the names of + its contributors may 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 COPYRIGHT OWNER 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. +*/ + +/* +The references are: + * Adaptive and Generic Corner Detection Based on the Accelerated Segment Test, + Elmar Mair and Gregory D. Hager and Darius Burschka + and Michael Suppa and Gerhard Hirzinger ECCV 2010 + URL: http://www6.in.tum.de/Main/ResearchAgast +*/ + +#include "agast_score.hpp" + +namespace cv +{ +namespace xfeatures2d +{ + +void makeAgastOffsets(int pixel[16], int rowStride, AgastFeatureDetector::DetectorType type) +{ + static const int offsets16[][2] = + { + {-3, 0}, {-3, -1}, {-2, -2}, {-1, -3}, {0, -3}, { 1, -3}, { 2, -2}, { 3, -1}, + { 3, 0}, { 3, 1}, { 2, 2}, { 1, 3}, {0, 3}, {-1, 3}, {-2, 2}, {-3, 1} + }; + + static const int offsets12d[][2] = + { + {-3, 0}, {-2, -1}, {-1, -2}, {0, -3}, { 1, -2}, { 2, -1}, + { 3, 0}, { 2, 1}, { 1, 2}, {0, 3}, {-1, 2}, {-2, 1} + }; + + static const int offsets12s[][2] = + { + {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, { 1, -2}, { 2, -1}, + { 2, 0}, { 2, 1}, { 1, 2}, {0, 2}, {-1, 2}, {-2, 1} + }; + + static const int offsets8[][2] = + { + {-1, 0}, {-1, -1}, {0, -1}, { 1, -1}, + { 1, 0}, { 1, 1}, {0, 1}, {-1, 1} + }; + + const int (*offsets)[2] = type == AgastFeatureDetector::OAST_9_16 ? offsets16 : + type == AgastFeatureDetector::AGAST_7_12d ? offsets12d : + type == AgastFeatureDetector::AGAST_7_12s ? offsets12s : + type == AgastFeatureDetector::AGAST_5_8 ? offsets8 : 0; + + const int offsets_len = type == AgastFeatureDetector::OAST_9_16 ? 16 : + type == AgastFeatureDetector::AGAST_7_12d ? 12 : + type == AgastFeatureDetector::AGAST_7_12s ? 12 : + type == AgastFeatureDetector::AGAST_5_8 ? 8 : 0; + + CV_Assert(pixel && offsets); + + int k = 0; + for( ; k < offsets_len; k++ ) + pixel[k] = offsets[k][0] + offsets[k][1] * rowStride; +} + +#if (defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) +// 16 pixel mask +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin) / 2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + short offset8 = (short) pixel[8]; + short offset9 = (short) pixel[9]; + short offset10 = (short) pixel[10]; + short offset11 = (short) pixel[11]; + short offset12 = (short) pixel[12]; + short offset13 = (short) pixel[13]; + short offset14 = (short) pixel[14]; + short offset15 = (short) pixel[15]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset7] < c_b) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset14] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset5] < c_b) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset12] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset10] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + goto is_a_corner; + else + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset5] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset2] < c_b) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset4] < c_b) + if(ptr[offset5] > cb) + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset5] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset14] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset10] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + goto is_a_corner; + else + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset9] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset12] > cb) + if(ptr[offset13] > cb) + if(ptr[offset14] > cb) + if(ptr[offset15] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset12] < c_b) + if(ptr[offset13] < c_b) + if(ptr[offset14] < c_b) + if(ptr[offset15] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin = b_test; + goto end; + + is_not_a_corner: + bmax = b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +// 12 pixel mask in diamond format +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + short offset8 = (short) pixel[8]; + short offset9 = (short) pixel[9]; + short offset10 = (short) pixel[10]; + short offset11 = (short) pixel[11]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset0] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset9] > cb) + if(ptr[offset6] > cb) + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset2] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset2] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin = b_test; + goto end; + + is_not_a_corner: + bmax = b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +//12 pixel mask in square format +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + short offset8 = (short) pixel[8]; + short offset9 = (short) pixel[9]; + short offset10 = (short) pixel[10]; + short offset11 = (short) pixel[11]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset2] < c_b) + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset3] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset0] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] < c_b) + if(ptr[offset10] > cb) + if(ptr[offset8] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset7] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] > cb) + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset2] > cb) + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] < c_b) + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] < c_b) + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset8] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset8] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset3] < c_b) + goto is_a_corner; + else + if(ptr[offset10] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] < c_b) + if(ptr[offset11] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset2] < c_b) + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset2] > cb) + if(ptr[offset9] < c_b) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset8] > cb) + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset8] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset9] < c_b) + goto is_not_a_corner; + else + if(ptr[offset9] > cb) + if(ptr[offset1] > cb) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + goto is_not_a_corner; + else + if(ptr[offset6] > cb) + if(ptr[offset8] > cb) + if(ptr[offset4] > cb) + if(ptr[offset3] > cb) + goto is_a_corner; + else + if(ptr[offset10] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset10] > cb) + if(ptr[offset11] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin = b_test; + goto end; + + is_not_a_corner: + bmax = b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +// 8 pixel mask +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + + short offset0 = (short) pixel[0]; + short offset1 = (short) pixel[1]; + short offset2 = (short) pixel[2]; + short offset3 = (short) pixel[3]; + short offset4 = (short) pixel[4]; + short offset5 = (short) pixel[5]; + short offset6 = (short) pixel[6]; + short offset7 = (short) pixel[7]; + + while(true) + { + const int cb = *ptr + b_test; + const int c_b = *ptr - b_test; + if(ptr[offset0] > cb) + if(ptr[offset2] > cb) + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + if(ptr[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset5] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset7] > cb) + if(ptr[offset6] > cb) + if(ptr[offset1] > cb) + goto is_a_corner; + else + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(ptr[offset0] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset7] > cb) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset6] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] > cb) + if(ptr[offset3] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset5] < c_b) + if(ptr[offset7] < c_b) + if(ptr[offset6] < c_b) + if(ptr[offset1] < c_b) + goto is_a_corner; + else + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] > cb) + if(ptr[offset5] > cb) + if(ptr[offset2] > cb) + if(ptr[offset1] > cb) + if(ptr[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] > cb) + if(ptr[offset4] > cb) + if(ptr[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset3] < c_b) + if(ptr[offset5] < c_b) + if(ptr[offset2] < c_b) + if(ptr[offset1] < c_b) + if(ptr[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(ptr[offset7] < c_b) + if(ptr[offset4] < c_b) + if(ptr[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin=b_test; + goto end; + + is_not_a_corner: + bmax=b_test; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} +#else // !(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) + + +int agast_tree_search(const uint32_t table_struct32[], int pixel_[], const unsigned char* const ptr, int threshold) +{ + const int cb = *ptr + threshold; + const int c_b = *ptr - threshold; + int index; + int offset; + int cmpresult; + index = 0; + while ((table_struct32[index]>>16)!=0) + { + offset=(int) pixel_[table_struct32[index]>>28]; + if ((table_struct32[index]&(1<<12))!=0) + cmpresult=(ptr[offset] < c_b); + else + cmpresult=(ptr[offset] > cb); + if (cmpresult) + index =(table_struct32[index]>>16)&0xfff; + else + index =table_struct32[index]&0xfff; + } + return (int)(table_struct32[index]&0xff); +} + +// universal pixel mask +int AGAST_ALL_SCORE(const uchar* ptr, const int pixel[], int threshold, AgastFeatureDetector::DetectorType agasttype) +{ + int bmin = threshold; + int bmax = 255; + int b_test = (bmax + bmin)/2; + uint32_t *table_struct; + + int result; + static const uint32_t table_5_8_corner_struct[] = + { 0x00010026,0x20020017,0x3003000c,0x50040009,0x10050007,0x406d0006,0x706d006c,0x4008006c, + 0x606d006c,0x100a006c,0x406d000b,0x706d006c,0x700d0012,0x600e006c,0x500f0011,0x106d0010, + 0x406d006c,0x106d006c,0x5013106c,0x3014106c,0x7015106c,0x4016106c,0x606d106c,0x5018001c, + 0x7019006c,0x601a006c,0x106d001b,0x406d006c,0x501d106c,0x301e106c,0x201f1023,0x10201021, + 0x406d106c,0x4022106c,0x606d106c,0x7024106c,0x4025106c,0x606d106c,0x00271058,0x20281049, + 0x70290035,0x302a1031,0x502b102f,0x102c102d,0x406d106c,0x402e106c,0x606d106c,0x1030106c, + 0x406d106c,0x5032006c,0x3033006c,0x4034006c,0x606d006c,0x70361041,0x3037103c,0x5038103b, + 0x106d1039,0x403a106c,0x606d106c,0x106d106c,0x603d106c,0x503e1040,0x106d103f,0x406d106c, + 0x106d106c,0x3042106c,0x50431047,0x10441045,0x406d106c,0x4046106c,0x606d106c,0x1048106c, + 0x406d106c,0x504a0053,0x304b006c,0x204c0050,0x104d004e,0x406d006c,0x404f006c,0x606d006c, + 0x7051006c,0x4052006c,0x606d006c,0x5054106c,0x7055106c,0x6056106c,0x106d1057,0x406d106c, + 0x30590062,0x505a006c,0x205b005f,0x105c005d,0x406d006c,0x405e006c,0x606d006c,0x7060006c, + 0x4061006c,0x606d006c,0x3063106c,0x5064106c,0x20651069,0x10661067,0x406d106c,0x4068106c, + 0x606d106c,0x706a106c,0x406b106c,0x606d106c,0x000000fe,0x000000ff}; + + static const uint32_t table_7_12d_corner_struct[] = + { 0x000100b5,0x50020036,0x20030025,0x9004001d,0x10050015,0x6006000f,0x3007000a,0x41870008, + 0xa0090186,0xb1870186,0x800b0186,0xa00c0186,0xb187000d,0x400e0186,0x71870186,0xb0100186, + 0x30110013,0x41870012,0xa1870186,0x80140186,0xa1870186,0x60160186,0x70170186,0x80180186, + 0x4019001b,0x3187001a,0xa1870186,0xa01c0186,0xb1870186,0x301e0186,0x401f0186,0x10200022, + 0x61870021,0xb1870186,0x60230186,0x70240186,0x81870186,0x90260186,0x70270186,0x80280186, + 0x10290030,0xa02a002d,0xb187002b,0x602c0186,0x41870186,0x602e0186,0x302f0186,0x41870186, + 0x60310186,0x40320034,0x31870033,0xa1870186,0xa0350186,0xb1870186,0x503710a1,0x9038006b, + 0x3039105b,0x403a1053,0xb03b004d,0x103c0044,0x803d0040,0xa03e0186,0x2187003f,0x71870186, + 0x60411186,0x20421186,0x70431186,0x81871186,0x60450048,0x70460186,0x80470186,0xa1870186, + 0x60491186,0x204a1186,0x704b1186,0x1187104c,0x81871186,0x204e1186,0x704f1186,0x10501051, + 0x61871186,0x60521186,0x81871186,0xb0540186,0x80550186,0xa0560186,0x10570059,0x21870058, + 0x71870186,0x605a0186,0x71870186,0xb05c0186,0xa05d0186,0x305e0065,0x105f0062,0x21870060, + 0x70610186,0x81870186,0x60630186,0x70640186,0x81870186,0x80660186,0x10670069,0x21870068, + 0x71870186,0x606a0186,0x71870186,0x906c1093,0x206d0087,0x106e007f,0x406f0077,0xa0700072, + 0x30710186,0xb1870186,0x60731186,0x70741186,0x80751186,0xb0761186,0xa1871186,0x60781186, + 0x70791186,0x807a1186,0xa07b107d,0x4187107c,0xb1871186,0x307e1186,0x41871186,0x60801186, + 0x70811186,0x80821186,0x40831085,0x31871084,0xa1871186,0xa0861186,0xb1871186,0x60881186, + 0x70891186,0x808a108f,0x408b108d,0x3187108c,0xa1871186,0xa08e1186,0xb1871186,0x20901186, + 0x10911186,0x30921186,0x41871186,0x20940099,0x10950186,0x30960186,0x40970186,0xa0980186, + 0xb1870186,0x209a1186,0x309b1186,0x409c1186,0x709d1186,0x109e109f,0x61871186,0x60a01186, + 0x81871186,0x20a200ae,0xa0a30186,0xb0a40186,0x90a500ab,0x10a600a8,0x318700a7,0x81870186, + 0x60a90186,0x70aa0186,0x81870186,0x10ac0186,0x30ad0186,0x41870186,0x90af0186,0x70b00186, + 0x80b10186,0xa0b20186,0xb0b30186,0x118700b4,0x61870186,0x00b6115a,0x20b700e2,0x50b800cc, + 0x70b900c5,0x60ba0186,0x40bb00c1,0x30bc00be,0x118700bd,0x81870186,0x90bf0186,0x80c00186, + 0xa1870186,0x90c20186,0x80c30186,0xa0c40186,0xb1870186,0x90c61186,0x80c71186,0xa0c81186, + 0xb0c91186,0x70ca1186,0x118710cb,0x61871186,0x90cd1186,0x70ce1186,0x80cf1186,0x50d010de, + 0x10d110d8,0xa0d210d5,0xb18710d3,0x60d41186,0x41871186,0x60d61186,0x30d71186,0x41871186, + 0x60d91186,0x40da10dc,0x318710db,0xa1871186,0xa0dd1186,0xb1871186,0xa0df1186,0xb0e01186, + 0x118710e1,0x61871186,0x20e3113a,0x90e4010b,0x50e500ff,0x10e610f7,0x40e710ef,0xa0e810ea, + 0x30e91186,0xb1871186,0x60eb0186,0x70ec0186,0x80ed0186,0xb0ee0186,0xa1870186,0x60f00186, + 0x70f10186,0x80f20186,0xa0f300f5,0x418700f4,0xb1870186,0x30f60186,0x41870186,0x60f80186, + 0x70f90186,0x80fa0186,0x40fb00fd,0x318700fc,0xa1870186,0xa0fe0186,0xb1870186,0x31001186, + 0x41011186,0x51021108,0x11031105,0x61871104,0xb1871186,0x61061186,0x71071186,0x81871186, + 0x11091186,0xa10a1186,0xb1871186,0x910c112e,0x510d1126,0x110e111e,0x610f1118,0x31101113, + 0x41871111,0xa1121186,0xb1871186,0x81141186,0xa1151186,0xb1871116,0x41171186,0x71871186, + 0xb1191186,0x311a111c,0x4187111b,0xa1871186,0x811d1186,0xa1871186,0x611f1186,0x71201186, + 0x81211186,0x41221124,0x31871123,0xa1871186,0xa1251186,0xb1871186,0xa1271186,0xb1281186, + 0x1129112b,0x3187112a,0x81871186,0x612c1186,0x712d1186,0x81871186,0x312f1186,0x41301186, + 0x51311137,0x11321134,0x61871133,0xb1871186,0x61351186,0x71361186,0x81871186,0x11381186, + 0xa1391186,0xb1871186,0x913b1150,0x713c1186,0x813d1186,0x513e114c,0x113f1146,0xa1401143, + 0xb1871141,0x61421186,0x41871186,0x61441186,0x31451186,0x41871186,0x61471186,0x4148114a, + 0x31871149,0xa1871186,0xa14b1186,0xb1871186,0xa14d1186,0xb14e1186,0x1187114f,0x61871186, + 0x51510186,0x91520186,0x61530186,0x71540186,0x81550186,0x41560158,0x31870157,0xa1870186, + 0xa1590186,0xb1870186,0x515b0170,0x915c0168,0x615d0186,0x715e0186,0x415f0165,0x31600163, + 0x81870161,0x11620186,0x21870186,0x81640186,0xa1870186,0xb1660186,0x81670186,0xa1870186, + 0x21690186,0x316a0186,0x416b0186,0x716c0186,0x116d016e,0x61870186,0x616f0186,0x81870186, + 0x51711186,0x9172117e,0x61731186,0x71741186,0x4175117b,0x31761179,0x81871177,0x11781186, + 0x21871186,0x817a1186,0xa1871186,0xb17c1186,0x817d1186,0xa1871186,0x217f1186,0x31801186, + 0x41811186,0x71821186,0x11831184,0x61871186,0x61851186,0x81871186,0x000000fe,0x000000ff}; + + static const uint32_t table_7_12s_corner_struct[] = + { 0x0001032b,0x50020104,0x20031026,0x70040748,0x97481005,0x90060748,0x1007100f,0x67481008, + 0x60090748,0x800a0748,0x400b000d,0x3749000c,0xa7490748,0xa00e0748,0xb7490748,0x1010001e, + 0x60111014,0x80120748,0xa0130748,0xb7490748,0x6015001b,0x80160748,0x40170019,0x37490018, + 0xa7490748,0xa01a0748,0xb7490748,0x801c0748,0xa01d0748,0xb7490748,0x6748101f,0x60200748, + 0x80210748,0x40220024,0x37490023,0xa7490748,0xa0250748,0xb7490748,0x202700e1,0x70281059, + 0x90291035,0x1748102a,0x102b0748,0x602c002e,0x302d0748,0x47490748,0x602f1032,0x30300748, + 0x40310748,0xb7490748,0x30330748,0x40340748,0xb7490748,0x9036004d,0x17481037,0x10380748, + 0x6039103f,0xb03a0748,0x303b003d,0x4749003c,0xa7490748,0x803e0748,0xa7490748,0x60400047, + 0x30410044,0x47490042,0xa0430748,0xb7490748,0x80450748,0xa0460748,0xb7490748,0xb0480748, + 0x3049004b,0x4749004a,0xa7490748,0x804c0748,0xa7490748,0x1748104e,0x104f0748,0x60500052, + 0x30510748,0x47490748,0x60531056,0x30540748,0x40550748,0xb7490748,0x30570748,0x40580748, + 0xb7490748,0x905a107d,0x705b0071,0x105c1061,0x6748105d,0x605e0748,0x305f0748,0x40600748, + 0x87490748,0x1062006c,0x60630065,0x30640748,0x47490748,0x60661069,0x30670748,0x40680748, + 0xb7490748,0x306a0748,0x406b0748,0xb7490748,0x6748106d,0x606e0748,0x306f0748,0x40700748, + 0x87490748,0x17481072,0x10730748,0x60740076,0x30750748,0x47490748,0x6077107a,0x30780748, + 0x40790748,0xb7490748,0x307b0748,0x407c0748,0xb7490748,0x707e00bd,0x907f00a7,0x10801088, + 0x67481081,0x60820748,0x80830748,0x40840086,0x37490085,0xa7490748,0xa0870748,0xb7490748, + 0x1089009f,0x608a1090,0xb08b0748,0x308c008e,0x4749008d,0xa7490748,0x808f0748,0xa7490748, + 0x60910099,0x30920095,0x47490093,0xa0940748,0xb7490748,0x80960748,0xa0970748,0x47490098, + 0xb7490748,0xb09a0748,0x309b009d,0x4749009c,0xa7490748,0x809e0748,0xa7490748,0x674810a0, + 0x60a10748,0x80a20748,0x40a300a5,0x374900a4,0xa7490748,0xa0a60748,0xb7490748,0x10a810ad, + 0x674810a9,0x60aa0748,0x30ab0748,0x40ac0748,0x87490748,0x10ae00b8,0x60af00b1,0x30b00748, + 0x47490748,0x60b210b5,0x30b30748,0x40b40748,0xb7490748,0x30b60748,0x40b70748,0xb7490748, + 0x674810b9,0x60ba0748,0x30bb0748,0x40bc0748,0x87490748,0x90be00d5,0x174810bf,0x10c00748, + 0x60c110c7,0xb0c20748,0x30c300c5,0x474900c4,0xa7490748,0x80c60748,0xa7490748,0x60c800cf, + 0x30c900cc,0x474900ca,0xa0cb0748,0xb7490748,0x80cd0748,0xa0ce0748,0xb7490748,0xb0d00748, + 0x30d100d3,0x474900d2,0xa7490748,0x80d40748,0xa7490748,0x174810d6,0x10d70748,0x60d800da, + 0x30d90748,0x47490748,0x60db10de,0x30dc0748,0x40dd0748,0xb7490748,0x30df0748,0x40e00748, + 0xb7490748,0x70e20748,0x974810e3,0x90e40748,0x10e510ed,0x674810e6,0x60e70748,0x80e80748, + 0x40e900eb,0x374900ea,0xa7490748,0xa0ec0748,0xb7490748,0x10ee00fc,0x60ef10f2,0x80f00748, + 0xa0f10748,0xb7490748,0x60f300f9,0x80f40748,0x40f500f7,0x374900f6,0xa7490748,0xa0f80748, + 0xb7490748,0x80fa0748,0xa0fb0748,0xb7490748,0x674810fd,0x60fe0748,0x80ff0748,0x41000102, + 0x37490101,0xa7490748,0xa1030748,0xb7490748,0x51051253,0x9106118c,0x71070119,0x27481108, + 0x21090748,0x1748110a,0x110b0748,0x610c0110,0x310d0748,0x410e0748,0xa10f0748,0xb7490748, + 0x61111115,0x31120748,0x41130748,0xa1140748,0xb7490748,0x31160748,0x41170748,0xa1180748, + 0xb7490748,0x711a117a,0x211b1136,0x111c0124,0x6748011d,0x611e1748,0x811f1748,0x41201122, + 0x37491121,0xa7491748,0xa1231748,0xb7491748,0x1125112e,0x67480126,0x61271748,0x4128112b, + 0x37491129,0x812a1748,0xa7491748,0x812c1748,0xa12d1748,0xb7491748,0x6748012f,0x61301748, + 0x81311748,0x41321134,0x37491133,0xa7491748,0xa1351748,0xb7491748,0x21370160,0x11381140, + 0x67480139,0x613a1748,0x813b1748,0x413c113e,0x3749113d,0xa7491748,0xa13f1748,0xb7491748, + 0x11410158,0x61420146,0x31430748,0x41440748,0xa1450748,0xb7490748,0x61471154,0x4148014e, + 0xa149014b,0x314a0748,0xb7490748,0x814c1748,0xb14d1748,0xa7491748,0x814f1748,0xa1501152, + 0x47491151,0xb7491748,0x31531748,0x47491748,0x31550748,0x41560748,0xa1570748,0xb7490748, + 0x67480159,0x615a1748,0x815b1748,0x415c115e,0x3749115d,0xa7491748,0xa15f1748,0xb7491748, + 0x11610169,0x67480162,0x61631748,0x81641748,0x41651167,0x37491166,0xa7491748,0xa1681748, + 0xb7491748,0x116a1172,0x6748016b,0x616c1748,0x816d1748,0x416e1170,0x3749116f,0xa7491748, + 0xa1711748,0xb7491748,0x67480173,0x61741748,0x81751748,0x41761178,0x37491177,0xa7491748, + 0xa1791748,0xb7491748,0x2748117b,0x217c0748,0x1748117d,0x117e0748,0x617f0183,0x31800748, + 0x41810748,0xa1820748,0xb7490748,0x61841188,0x31850748,0x41860748,0xa1870748,0xb7490748, + 0x31890748,0x418a0748,0xa18b0748,0xb7490748,0x918d020d,0x718e11b0,0x218f019f,0x17481190, + 0x11910748,0x61920196,0xa1930748,0xb1940748,0x37490195,0x87490748,0x6197119b,0xa1980748, + 0xb1990748,0x3749019a,0x87490748,0xa19c0748,0xb19d0748,0x3749019e,0x87490748,0x21a01748, + 0x11a111a5,0x674801a2,0x61a31748,0x31a41748,0x47491748,0x11a601ab,0x674801a7,0x61a81748, + 0x31a91748,0x41aa1748,0x87491748,0x674801ac,0x61ad1748,0x31ae1748,0x41af1748,0x87491748, + 0x71b101fb,0x21b211c9,0x11b311b8,0x674811b4,0x61b50748,0x81b60748,0xa1b70748,0xb7490748, + 0x11b901c4,0x61ba01bd,0x81bb0748,0xa1bc0748,0xb7490748,0x61be11c1,0x81bf0748,0xa1c00748, + 0xb7490748,0x81c20748,0xa1c30748,0xb7490748,0x674811c5,0x61c60748,0x81c70748,0xa1c80748, + 0xb7490748,0x21ca01e4,0x11cb11d0,0x674811cc,0x61cd0748,0x81ce0748,0xa1cf0748,0xb7490748, + 0x11d101df,0x61d201d6,0xa1d30748,0xb1d40748,0x374901d5,0x87490748,0x61d711db,0xa1d80748, + 0xb1d90748,0x374901da,0x87490748,0xa1dc0748,0xb1dd0748,0x374901de,0x87490748,0x674811e0, + 0x61e10748,0x81e20748,0xa1e30748,0xb7490748,0x11e511ea,0x674811e6,0x61e70748,0x81e80748, + 0xa1e90748,0xb7490748,0x11eb01f6,0x61ec01ef,0x81ed0748,0xa1ee0748,0xb7490748,0x61f011f3, + 0x81f10748,0xa1f20748,0xb7490748,0x81f40748,0xa1f50748,0xb7490748,0x674811f7,0x61f80748, + 0x81f90748,0xa1fa0748,0xb7490748,0x274811fc,0x21fd0748,0x174811fe,0x11ff0748,0x62000204, + 0xa2010748,0xb2020748,0x37490203,0x87490748,0x62051209,0xa2060748,0xb2070748,0x37490208, + 0x87490748,0xa20a0748,0xb20b0748,0x3749020c,0x87490748,0x220e1220,0x7748020f,0x72101748, + 0x12111215,0x67480212,0x62131748,0x32141748,0x47491748,0x1216021b,0x67480217,0x62181748, + 0x32191748,0x421a1748,0x87491748,0x6748021c,0x621d1748,0x321e1748,0x421f1748,0x87491748, + 0x22210748,0x72220232,0x17481223,0x12240748,0x62250229,0x32260748,0x42270748,0xa2280748, + 0xb7490748,0x622a122e,0x322b0748,0x422c0748,0xa22d0748,0xb7490748,0x322f0748,0x42300748, + 0xa2310748,0xb7490748,0x72331243,0x17481234,0x12350748,0x6236023a,0x32370748,0x42380748, + 0xa2390748,0xb7490748,0x623b123f,0x323c0748,0x423d0748,0xa23e0748,0xb7490748,0x32400748, + 0x42410748,0xa2420748,0xb7490748,0x17481244,0x12450748,0x6246024a,0x32470748,0x42480748, + 0xa2490748,0xb7490748,0x624b124f,0x324c0748,0x424d0748,0xa24e0748,0xb7490748,0x32500748, + 0x42510748,0xa2520748,0xb7490748,0x2254126e,0x72550748,0x97481256,0x92570748,0x1258125d, + 0x67481259,0x625a0748,0x825b0748,0xa25c0748,0xb7490748,0x125e0269,0x625f0262,0x82600748, + 0xa2610748,0xb7490748,0x62631266,0x82640748,0xa2650748,0xb7490748,0x82670748,0xa2680748, + 0xb7490748,0x6748126a,0x626b0748,0x826c0748,0xa26d0748,0xb7490748,0x226f0311,0x727012a2, + 0x92711281,0x17481272,0x12730748,0x62740278,0x32750748,0x42760748,0xa2770748,0xb7490748, + 0x6279127d,0x327a0748,0x427b0748,0xa27c0748,0xb7490748,0x327e0748,0x427f0748,0xa2800748, + 0xb7490748,0x92820292,0x17481283,0x12840748,0x62850289,0xa2860748,0xb2870748,0x37490288, + 0x87490748,0x628a128e,0xa28b0748,0xb28c0748,0x3749028d,0x87490748,0xa28f0748,0xb2900748, + 0x37490291,0x87490748,0x17481293,0x12940748,0x62950299,0x32960748,0x42970748,0xa2980748, + 0xb7490748,0x629a129e,0x329b0748,0x429c0748,0xa29d0748,0xb7490748,0x329f0748,0x42a00748, + 0xa2a10748,0xb7490748,0x92a312c4,0x72a402b4,0x174812a5,0x12a60748,0x62a702ab,0x32a80748, + 0x42a90748,0xa2aa0748,0xb7490748,0x62ac12b0,0x32ad0748,0x42ae0748,0xa2af0748,0xb7490748, + 0x32b10748,0x42b20748,0xa2b30748,0xb7490748,0x174812b5,0x12b60748,0x62b702bb,0x32b80748, + 0x42b90748,0xa2ba0748,0xb7490748,0x62bc12c0,0x32bd0748,0x42be0748,0xa2bf0748,0xb7490748, + 0x32c10748,0x42c20748,0xa2c30748,0xb7490748,0x72c502f0,0x92c602e0,0x12c712cc,0x674812c8, + 0x62c90748,0x82ca0748,0xa2cb0748,0xb7490748,0x12cd02db,0x62ce02d2,0xa2cf0748,0xb2d00748, + 0x374902d1,0x87490748,0x62d312d7,0xa2d40748,0xb2d50748,0x374902d6,0x87490748,0xa2d80748, + 0xb2d90748,0x374902da,0x87490748,0x674812dc,0x62dd0748,0x82de0748,0xa2df0748,0xb7490748, + 0x174812e1,0x12e20748,0x62e302e7,0x32e40748,0x42e50748,0xa2e60748,0xb7490748,0x62e812ec, + 0x32e90748,0x42ea0748,0xa2eb0748,0xb7490748,0x32ed0748,0x42ee0748,0xa2ef0748,0xb7490748, + 0x92f10301,0x174812f2,0x12f30748,0x62f402f8,0xa2f50748,0xb2f60748,0x374902f7,0x87490748, + 0x62f912fd,0xa2fa0748,0xb2fb0748,0x374902fc,0x87490748,0xa2fe0748,0xb2ff0748,0x37490300, + 0x87490748,0x17481302,0x13030748,0x63040308,0x33050748,0x43060748,0xa3070748,0xb7490748, + 0x6309130d,0x330a0748,0x430b0748,0xa30c0748,0xb7490748,0x330e0748,0x430f0748,0xa3100748, + 0xb7490748,0x73120748,0x97481313,0x93140748,0x1315131a,0x67481316,0x63170748,0x83180748, + 0xa3190748,0xb7490748,0x131b0326,0x631c031f,0x831d0748,0xa31e0748,0xb7490748,0x63201323, + 0x83210748,0xa3220748,0xb7490748,0x83240748,0xa3250748,0xb7490748,0x67481327,0x63280748, + 0x83290748,0xa32a0748,0xb7490748,0x032c1655,0x532d1431,0x932e0360,0x2748032f,0x23301748, + 0x7331033d,0x17480332,0x13331748,0x63341336,0x33351748,0x47491748,0x6337033a,0x33381748, + 0x43391748,0xb7491748,0x333b1748,0x433c1748,0xb7491748,0x733e1354,0x133f0344,0x67480340, + 0x63411748,0x33421748,0x43431748,0x87491748,0x1345134f,0x63461348,0x33471748,0x47491748, + 0x6349034c,0x334a1748,0x434b1748,0xb7491748,0x334d1748,0x434e1748,0xb7491748,0x67480350, + 0x63511748,0x33521748,0x43531748,0x87491748,0x17480355,0x13561748,0x63571359,0x33581748, + 0x47491748,0x635a035d,0x335b1748,0x435c1748,0xb7491748,0x335e1748,0x435f1748,0xb7491748, + 0x936113ff,0x7362037b,0x27480363,0x23641748,0x17480365,0x13661748,0x6367036d,0xb3681748, + 0x3369136b,0x4749136a,0xa7491748,0x836c1748,0xa7491748,0x636e1375,0x336f1372,0x47491370, + 0xa3711748,0xb7491748,0x83731748,0xa3741748,0xb7491748,0xb3761748,0x33771379,0x47491378, + 0xa7491748,0x837a1748,0xa7491748,0x737c13e6,0x237d039d,0x137e0386,0x6748037f,0x63801748, + 0x83811748,0x43821384,0x37491383,0xa7491748,0xa3851748,0xb7491748,0x13871395,0x6388038b, + 0x83891748,0xa38a1748,0xb7491748,0x638c1392,0x838d1748,0x438e1390,0x3749138f,0xa7491748, + 0xa3911748,0xb7491748,0x83931748,0xa3941748,0xb7491748,0x67480396,0x63971748,0x83981748, + 0x4399139b,0x3749139a,0xa7491748,0xa39c1748,0xb7491748,0x239e13c6,0x139f03a7,0x674803a0, + 0x63a11748,0x83a21748,0x43a313a5,0x374913a4,0xa7491748,0xa3a61748,0xb7491748,0x13a813be, + 0x63a903af,0xb3aa1748,0x33ab13ad,0x474913ac,0xa7491748,0x83ae1748,0xa7491748,0x63b013b8, + 0x33b113b4,0x474913b2,0xa3b31748,0xb7491748,0x83b51748,0xa3b61748,0x474913b7,0xb7491748, + 0xb3b91748,0x33ba13bc,0x474913bb,0xa7491748,0x83bd1748,0xa7491748,0x674803bf,0x63c01748, + 0x83c11748,0x43c213c4,0x374913c3,0xa7491748,0xa3c51748,0xb7491748,0x13c703cf,0x674803c8, + 0x63c91748,0x83ca1748,0x43cb13cd,0x374913cc,0xa7491748,0xa3ce1748,0xb7491748,0x13d013de, + 0x63d103d4,0x83d21748,0xa3d31748,0xb7491748,0x63d513db,0x83d61748,0x43d713d9,0x374913d8, + 0xa7491748,0xa3da1748,0xb7491748,0x83dc1748,0xa3dd1748,0xb7491748,0x674803df,0x63e01748, + 0x83e11748,0x43e213e4,0x374913e3,0xa7491748,0xa3e51748,0xb7491748,0x274803e7,0x23e81748, + 0x174803e9,0x13ea1748,0x63eb03f1,0xb3ec1748,0x33ed13ef,0x474913ee,0xa7491748,0x83f01748, + 0xa7491748,0x63f213f9,0x33f313f6,0x474913f4,0xa3f51748,0xb7491748,0x83f71748,0xa3f81748, + 0xb7491748,0xb3fa1748,0x33fb13fd,0x474913fc,0xa7491748,0x83fe1748,0xa7491748,0x27480400, + 0x24011748,0x7402040e,0x17480403,0x14041748,0x64051407,0x34061748,0x47491748,0x6408040b, + 0x34091748,0x440a1748,0xb7491748,0x340c1748,0x440d1748,0xb7491748,0x740f1425,0x14100415, + 0x67480411,0x64121748,0x34131748,0x44141748,0x87491748,0x14161420,0x64171419,0x34181748, + 0x47491748,0x641a041d,0x341b1748,0x441c1748,0xb7491748,0x341e1748,0x441f1748,0xb7491748, + 0x67480421,0x64221748,0x34231748,0x44241748,0x87491748,0x17480426,0x14271748,0x6428142a, + 0x34291748,0x47491748,0x642b042e,0x342c1748,0x442d1748,0xb7491748,0x342f1748,0x44301748, + 0xb7491748,0x5432057d,0x2433048b,0x7434144d,0x97480435,0x94361748,0x1437043c,0x67480438, + 0x64391748,0x843a1748,0xa43b1748,0xb7491748,0x143d1448,0x643e0441,0x843f1748,0xa4401748, + 0xb7491748,0x64421445,0x84431748,0xa4441748,0xb7491748,0x84461748,0xa4471748,0xb7491748, + 0x67480449,0x644a1748,0x844b1748,0xa44c1748,0xb7491748,0x744e0748,0x944f145f,0x14500454, + 0x67481451,0x64520748,0x34530748,0x47490748,0x1455145a,0x67481456,0x64570748,0x34580748, + 0x44590748,0x87490748,0x6748145b,0x645c0748,0x345d0748,0x445e0748,0x87490748,0x9460047b, + 0x14611469,0x67481462,0x64630748,0x84640748,0x44650467,0x37490466,0xa7490748,0xa4680748, + 0xb7490748,0x146a0473,0x6748146b,0x646c0748,0x446d0470,0x3749046e,0x846f0748,0xa7490748, + 0x84710748,0xa4720748,0xb7490748,0x67481474,0x64750748,0x84760748,0x44770479,0x37490478, + 0xa7490748,0xa47a0748,0xb7490748,0x147c0480,0x6748147d,0x647e0748,0x347f0748,0x47490748, + 0x14811486,0x67481482,0x64830748,0x34840748,0x44850748,0x87490748,0x67481487,0x64880748, + 0x34890748,0x448a0748,0x87490748,0x248c1547,0x748d14c9,0x948e049e,0x1748048f,0x14901748, + 0x64910495,0x34921748,0x44931748,0xa4941748,0xb7491748,0x6496149a,0x34971748,0x44981748, + 0xa4991748,0xb7491748,0x349b1748,0x449c1748,0xa49d1748,0xb7491748,0x949f14b9,0x14a004a5, + 0x674804a1,0x64a21748,0x84a31748,0xa4a41748,0xb7491748,0x14a614b4,0x64a704ab,0xa4a81748, + 0xb4a91748,0x374914aa,0x87491748,0x64ac14b0,0xa4ad1748,0xb4ae1748,0x374914af,0x87491748, + 0xa4b11748,0xb4b21748,0x374914b3,0x87491748,0x674804b5,0x64b61748,0x84b71748,0xa4b81748, + 0xb7491748,0x174804ba,0x14bb1748,0x64bc04c0,0x34bd1748,0x44be1748,0xa4bf1748,0xb7491748, + 0x64c114c5,0x34c21748,0x44c31748,0xa4c41748,0xb7491748,0x34c61748,0x44c71748,0xa4c81748, + 0xb7491748,0x74ca0515,0x94cb14db,0x174804cc,0x14cd1748,0x64ce04d2,0xa4cf1748,0xb4d01748, + 0x374914d1,0x87491748,0x64d314d7,0xa4d41748,0xb4d51748,0x374914d6,0x87491748,0xa4d81748, + 0xb4d91748,0x374914da,0x87491748,0x94dc0505,0x14dd04e5,0x674814de,0x64df0748,0x84e00748, + 0x44e104e3,0x374904e2,0xa7490748,0xa4e40748,0xb7490748,0x14e614fd,0x64e714eb,0x34e81748, + 0x44e91748,0xa4ea1748,0xb7491748,0x64ec04f9,0x44ed14f3,0xa4ee04f0,0x84ef0748,0xb7490748, + 0x34f11748,0xb4f21748,0xa7491748,0x84f40748,0xa4f504f7,0x474904f6,0xb7490748,0x34f80748, + 0x47490748,0x34fa1748,0x44fb1748,0xa4fc1748,0xb7491748,0x674814fe,0x64ff0748,0x85000748, + 0x45010503,0x37490502,0xa7490748,0xa5040748,0xb7490748,0x17480506,0x15071748,0x6508050c, + 0x35091748,0x450a1748,0xa50b1748,0xb7491748,0x650d1511,0x350e1748,0x450f1748,0xa5101748, + 0xb7491748,0x35121748,0x45131748,0xa5141748,0xb7491748,0x95160526,0x17480517,0x15181748, + 0x6519051d,0x351a1748,0x451b1748,0xa51c1748,0xb7491748,0x651e1522,0x351f1748,0x45201748, + 0xa5211748,0xb7491748,0x35231748,0x45241748,0xa5251748,0xb7491748,0x95271537,0x17480528, + 0x15291748,0x652a052e,0xa52b1748,0xb52c1748,0x3749152d,0x87491748,0x652f1533,0xa5301748, + 0xb5311748,0x37491532,0x87491748,0xa5341748,0xb5351748,0x37491536,0x87491748,0x17480538, + 0x15391748,0x653a053e,0x353b1748,0x453c1748,0xa53d1748,0xb7491748,0x653f1543,0x35401748, + 0x45411748,0xa5421748,0xb7491748,0x35441748,0x45451748,0xa5461748,0xb7491748,0x75480564, + 0x97481549,0x954a0748,0x154b0553,0x6748154c,0x654d0748,0x854e0748,0x454f0551,0x37490550, + 0xa7490748,0xa5520748,0xb7490748,0x1554155c,0x67481555,0x65560748,0x85570748,0x4558055a, + 0x37490559,0xa7490748,0xa55b0748,0xb7490748,0x6748155d,0x655e0748,0x855f0748,0x45600562, + 0x37490561,0xa7490748,0xa5630748,0xb7490748,0x95651748,0x75661748,0x1567056c,0x67480568, + 0x65691748,0x856a1748,0xa56b1748,0xb7491748,0x156d1578,0x656e0571,0x856f1748,0xa5701748, + 0xb7491748,0x65721575,0x85731748,0xa5741748,0xb7491748,0x85761748,0xa5771748,0xb7491748, + 0x67480579,0x657a1748,0x857b1748,0xa57c1748,0xb7491748,0x257e0598,0x757f1748,0x97480580, + 0x95811748,0x15820587,0x67480583,0x65841748,0x85851748,0xa5861748,0xb7491748,0x15881593, + 0x6589058c,0x858a1748,0xa58b1748,0xb7491748,0x658d1590,0x858e1748,0xa58f1748,0xb7491748, + 0x85911748,0xa5921748,0xb7491748,0x67480594,0x65951748,0x85961748,0xa5971748,0xb7491748, + 0x2599163b,0x759a05cc,0x959b05ab,0x1748059c,0x159d1748,0x659e05a2,0x359f1748,0x45a01748, + 0xa5a11748,0xb7491748,0x65a315a7,0x35a41748,0x45a51748,0xa5a61748,0xb7491748,0x35a81748, + 0x45a91748,0xa5aa1748,0xb7491748,0x95ac15bc,0x174805ad,0x15ae1748,0x65af05b3,0xa5b01748, + 0xb5b11748,0x374915b2,0x87491748,0x65b415b8,0xa5b51748,0xb5b61748,0x374915b7,0x87491748, + 0xa5b91748,0xb5ba1748,0x374915bb,0x87491748,0x174805bd,0x15be1748,0x65bf05c3,0x35c01748, + 0x45c11748,0xa5c21748,0xb7491748,0x65c415c8,0x35c51748,0x45c61748,0xa5c71748,0xb7491748, + 0x35c91748,0x45ca1748,0xa5cb1748,0xb7491748,0x95cd05ee,0x75ce15de,0x174805cf,0x15d01748, + 0x65d105d5,0x35d21748,0x45d31748,0xa5d41748,0xb7491748,0x65d615da,0x35d71748,0x45d81748, + 0xa5d91748,0xb7491748,0x35db1748,0x45dc1748,0xa5dd1748,0xb7491748,0x174805df,0x15e01748, + 0x65e105e5,0x35e21748,0x45e31748,0xa5e41748,0xb7491748,0x65e615ea,0x35e71748,0x45e81748, + 0xa5e91748,0xb7491748,0x35eb1748,0x45ec1748,0xa5ed1748,0xb7491748,0x75ef161a,0x95f0160a, + 0x15f105f6,0x674805f2,0x65f31748,0x85f41748,0xa5f51748,0xb7491748,0x15f71605,0x65f805fc, + 0xa5f91748,0xb5fa1748,0x374915fb,0x87491748,0x65fd1601,0xa5fe1748,0xb5ff1748,0x37491600, + 0x87491748,0xa6021748,0xb6031748,0x37491604,0x87491748,0x67480606,0x66071748,0x86081748, + 0xa6091748,0xb7491748,0x1748060b,0x160c1748,0x660d0611,0x360e1748,0x460f1748,0xa6101748, + 0xb7491748,0x66121616,0x36131748,0x46141748,0xa6151748,0xb7491748,0x36171748,0x46181748, + 0xa6191748,0xb7491748,0x961b162b,0x1748061c,0x161d1748,0x661e0622,0xa61f1748,0xb6201748, + 0x37491621,0x87491748,0x66231627,0xa6241748,0xb6251748,0x37491626,0x87491748,0xa6281748, + 0xb6291748,0x3749162a,0x87491748,0x1748062c,0x162d1748,0x662e0632,0x362f1748,0x46301748, + 0xa6311748,0xb7491748,0x66331637,0x36341748,0x46351748,0xa6361748,0xb7491748,0x36381748, + 0x46391748,0xa63a1748,0xb7491748,0x763c1748,0x9748063d,0x963e1748,0x163f0644,0x67480640, + 0x66411748,0x86421748,0xa6431748,0xb7491748,0x16451650,0x66460649,0x86471748,0xa6481748, + 0xb7491748,0x664a164d,0x864b1748,0xa64c1748,0xb7491748,0x864e1748,0xa64f1748,0xb7491748, + 0x67480651,0x66521748,0x86531748,0xa6541748,0xb7491748,0x565616cf,0x77480657,0x76581748, + 0x26590675,0x9748065a,0x965b1748,0x165c0664,0x6748065d,0x665e1748,0x865f1748,0x46601662, + 0x37491661,0xa7491748,0xa6631748,0xb7491748,0x1665166d,0x67480666,0x66671748,0x86681748, + 0x4669166b,0x3749166a,0xa7491748,0xa66c1748,0xb7491748,0x6748066e,0x666f1748,0x86701748, + 0x46711673,0x37491672,0xa7491748,0xa6741748,0xb7491748,0x267616b3,0x96770687,0x1678167c, + 0x67480679,0x667a1748,0x367b1748,0x47491748,0x167d0682,0x6748067e,0x667f1748,0x36801748, + 0x46811748,0x87491748,0x67480683,0x66841748,0x36851748,0x46861748,0x87491748,0x968816a3, + 0x16890691,0x6748068a,0x668b1748,0x868c1748,0x468d168f,0x3749168e,0xa7491748,0xa6901748, + 0xb7491748,0x1692169b,0x67480693,0x66941748,0x46951698,0x37491696,0x86971748,0xa7491748, + 0x86991748,0xa69a1748,0xb7491748,0x6748069c,0x669d1748,0x869e1748,0x469f16a1,0x374916a0, + 0xa7491748,0xa6a21748,0xb7491748,0x16a416a8,0x674806a5,0x66a61748,0x36a71748,0x47491748, + 0x16a906ae,0x674806aa,0x66ab1748,0x36ac1748,0x46ad1748,0x87491748,0x674806af,0x66b01748, + 0x36b11748,0x46b21748,0x87491748,0x974806b4,0x96b51748,0x16b606be,0x674806b7,0x66b81748, + 0x86b91748,0x46ba16bc,0x374916bb,0xa7491748,0xa6bd1748,0xb7491748,0x16bf16c7,0x674806c0, + 0x66c11748,0x86c21748,0x46c316c5,0x374916c4,0xa7491748,0xa6c61748,0xb7491748,0x674806c8, + 0x66c91748,0x86ca1748,0x46cb16cd,0x374916cc,0xa7491748,0xa6ce1748,0xb7491748,0x56d00748, + 0x76d10748,0x26d216ee,0x974816d3,0x96d40748,0x16d506dd,0x674816d6,0x66d70748,0x86d80748, + 0x46d906db,0x374906da,0xa7490748,0xa6dc0748,0xb7490748,0x16de16e6,0x674816df,0x66e00748, + 0x86e10748,0x46e206e4,0x374906e3,0xa7490748,0xa6e50748,0xb7490748,0x674816e7,0x66e80748, + 0x86e90748,0x46ea06ec,0x374906eb,0xa7490748,0xa6ed0748,0xb7490748,0x26ef072c,0x96f01700, + 0x16f106f5,0x674816f2,0x66f30748,0x36f40748,0x47490748,0x16f616fb,0x674816f7,0x66f80748, + 0x36f90748,0x46fa0748,0x87490748,0x674816fc,0x66fd0748,0x36fe0748,0x46ff0748,0x87490748, + 0x9701071c,0x1702170a,0x67481703,0x67040748,0x87050748,0x47060708,0x37490707,0xa7490748, + 0xa7090748,0xb7490748,0x170b0714,0x6748170c,0x670d0748,0x470e0711,0x3749070f,0x87100748, + 0xa7490748,0x87120748,0xa7130748,0xb7490748,0x67481715,0x67160748,0x87170748,0x4718071a, + 0x37490719,0xa7490748,0xa71b0748,0xb7490748,0x171d0721,0x6748171e,0x671f0748,0x37200748, + 0x47490748,0x17221727,0x67481723,0x67240748,0x37250748,0x47260748,0x87490748,0x67481728, + 0x67290748,0x372a0748,0x472b0748,0x87490748,0x9748172d,0x972e0748,0x172f0737,0x67481730, + 0x67310748,0x87320748,0x47330735,0x37490734,0xa7490748,0xa7360748,0xb7490748,0x17381740, + 0x67481739,0x673a0748,0x873b0748,0x473c073e,0x3749073d,0xa7490748,0xa73f0748,0xb7490748, + 0x67481741,0x67420748,0x87430748,0x47440746,0x37490745,0xa7490748,0xa7470748,0xb7490748, + 0x000000fe,0x000000ff}; + + static const uint32_t table_9_16_corner_struct[] = + { 0x00010138,0x200200d3,0x4003008a,0x50040051,0x70050027,0x30060016,0x1007000d,0x6008000a, + 0x82ad0009,0xf2ad02ac,0xd00b02ac,0xe00c02ac,0xf2ad02ac,0x800e02ac,0x900f02ac,0xa01002ac, + 0x62ad0011,0xb01202ac,0xc01302ac,0xd01402ac,0xe01502ac,0xf2ad02ac,0xa01702ac,0xb01802ac, + 0xc01902ac,0x801a0023,0x901b001f,0x62ad001c,0xd01d02ac,0xe01e02ac,0xf2ad02ac,0x102002ac, + 0xd02102ac,0xe02202ac,0xf2ad02ac,0x102402ac,0xd02502ac,0xe02602ac,0xf2ad02ac,0x70281041, + 0xe0290038,0xf02a02ac,0x102b0032,0x302c002e,0x62ad002d,0xd2ad02ac,0xa02f02ac,0xb03002ac, + 0xc03102ac,0xd2ad02ac,0x803302ac,0x903402ac,0xa03502ac,0xb03602ac,0xc03702ac,0xd2ad02ac, + 0xe03912ac,0x803a12ac,0x903b12ac,0xa03c12ac,0xb03d12ac,0xc03e12ac,0xd03f12ac,0x62ad1040, + 0xf2ad12ac,0xe04202ac,0xf04302ac,0x1044004b,0x30450047,0x62ad0046,0xd2ad02ac,0xa04802ac, + 0xb04902ac,0xc04a02ac,0xd2ad02ac,0x804c02ac,0x904d02ac,0xa04e02ac,0xb04f02ac,0xc05002ac, + 0xd2ad02ac,0x5052106e,0xc0530064,0xd05402ac,0xe05502ac,0xf056005e,0x1057005a,0x32ad0058, + 0xa05902ac,0xb2ad02ac,0x805b02ac,0x905c02ac,0xa05d02ac,0xb2ad02ac,0x605f02ac,0x706002ac, + 0x806102ac,0x906202ac,0xa06302ac,0xb2ad02ac,0xc06512ac,0x706612ac,0x806712ac,0x906812ac, + 0xa06912ac,0xb06a12ac,0xd06b12ac,0x62ad106c,0xe06d12ac,0xf2ad12ac,0xc06f0080,0xd07002ac, + 0xe07102ac,0xf072007a,0x10730076,0x32ad0074,0xa07502ac,0xb2ad02ac,0x807702ac,0x907802ac, + 0xa07902ac,0xb2ad02ac,0x607b02ac,0x707c02ac,0x807d02ac,0x907e02ac,0xa07f02ac,0xb2ad02ac, + 0xc08112ac,0x708212ac,0x808312ac,0x908412ac,0xa08512ac,0xb08612ac,0xd08712ac,0xe08812ac, + 0x62ad1089,0xf2ad12ac,0x408b10b1,0xb08c00a1,0xc08d02ac,0xd08e02ac,0xa08f009d,0xe0900098, + 0xf0910094,0x12ad0092,0x809302ac,0x92ad02ac,0x609502ac,0x709602ac,0x809702ac,0x92ad02ac, + 0x509902ac,0x609a02ac,0x709b02ac,0x809c02ac,0x92ad02ac,0x109e02ac,0x309f02ac,0xe0a002ac, + 0xf2ad02ac,0xb0a212ac,0x70a312ac,0x80a412ac,0x90a512ac,0xa0a612ac,0x60a710ad,0x50a810aa, + 0x32ad10a9,0xc2ad12ac,0xc0ab12ac,0xd0ac12ac,0xe2ad12ac,0xc0ae12ac,0xd0af12ac,0xe0b012ac, + 0xf2ad12ac,0xb0b200c7,0xc0b302ac,0xd0b402ac,0xa0b500c3,0xe0b600be,0xf0b700ba,0x12ad00b8, + 0x80b902ac,0x92ad02ac,0x60bb02ac,0x70bc02ac,0x80bd02ac,0x92ad02ac,0x50bf02ac,0x60c002ac, + 0x70c102ac,0x80c202ac,0x92ad02ac,0x10c402ac,0x30c502ac,0xe0c602ac,0xf2ad02ac,0xb0c812ac, + 0x70c912ac,0x80ca12ac,0x90cb12ac,0xa0cc12ac,0xc0cd12ac,0xd0ce12ac,0x60cf10d1,0x52ad10d0, + 0xe2ad12ac,0xe0d212ac,0xf2ad12ac,0x20d4110a,0x90d500ef,0xa0d602ac,0xb0d702ac,0x80d800ea, + 0xc0d900e5,0xd0da00e1,0xe0db00de,0xf2ad00dc,0x60dd02ac,0x72ad02ac,0x50df02ac,0x60e002ac, + 0x72ad02ac,0x40e202ac,0x50e302ac,0x60e402ac,0x72ad02ac,0x30e602ac,0x40e702ac,0x50e802ac, + 0x60e902ac,0x72ad02ac,0x10eb02ac,0xc0ec02ac,0xd0ed02ac,0xe0ee02ac,0xf2ad02ac,0x90f012ac, + 0x70f112ac,0x80f212ac,0x60f31104,0x50f410ff,0x40f510fb,0x30f610f8,0x12ad10f7,0xa2ad12ac, + 0xa0f912ac,0xb0fa12ac,0xc2ad12ac,0xa0fc12ac,0xb0fd12ac,0xc0fe12ac,0xd2ad12ac,0xa10012ac, + 0xb10112ac,0xc10212ac,0xd10312ac,0xe2ad12ac,0xa10512ac,0xb10612ac,0xc10712ac,0xd10812ac, + 0xe10912ac,0xf2ad12ac,0x910b0125,0xa10c02ac,0xb10d02ac,0x810e0120,0xc10f011b,0xd1100117, + 0xe1110114,0xf2ad0112,0x611302ac,0x72ad02ac,0x511502ac,0x611602ac,0x72ad02ac,0x411802ac, + 0x511902ac,0x611a02ac,0x72ad02ac,0x311c02ac,0x411d02ac,0x511e02ac,0x611f02ac,0x72ad02ac, + 0x112102ac,0xc12202ac,0xd12302ac,0xe12402ac,0xf2ad02ac,0x912612ac,0x712712ac,0x812812ac, + 0xa12912ac,0xb12a12ac,0x612b1134,0x512c1131,0x412d112f,0x32ad112e,0xc2ad12ac,0xc13012ac, + 0xd2ad12ac,0xc13212ac,0xd13312ac,0xe2ad12ac,0xc13512ac,0xd13612ac,0xe13712ac,0xf2ad12ac, + 0x01391270,0x213a0170,0x913b0155,0x713c02ac,0x813d02ac,0x613e014f,0x513f014a,0x41400146, + 0x31410143,0x12ad0142,0xa2ad02ac,0xa14402ac,0xb14502ac,0xc2ad02ac,0xa14702ac,0xb14802ac, + 0xc14902ac,0xd2ad02ac,0xa14b02ac,0xb14c02ac,0xc14d02ac,0xd14e02ac,0xe2ad02ac,0xa15002ac, + 0xb15102ac,0xc15202ac,0xd15302ac,0xe15402ac,0xf2ad02ac,0x915612ac,0xa15712ac,0xb15812ac, + 0x8159116b,0xc15a1166,0xd15b1162,0xe15c115f,0xf2ad115d,0x615e12ac,0x72ad12ac,0x516012ac, + 0x616112ac,0x72ad12ac,0x416312ac,0x516412ac,0x616512ac,0x72ad12ac,0x316712ac,0x416812ac, + 0x516912ac,0x616a12ac,0x72ad12ac,0x116c12ac,0xc16d12ac,0xd16e12ac,0xe16f12ac,0xf2ad12ac, + 0x21711242,0x41720198,0xb1730182,0x717402ac,0x817502ac,0x917602ac,0xa17702ac,0x6178017e, + 0x5179017b,0x32ad017a,0xc2ad02ac,0xc17c02ac,0xd17d02ac,0xe2ad02ac,0xc17f02ac,0xd18002ac, + 0xe18102ac,0xf2ad02ac,0xb18312ac,0xc18412ac,0xd18512ac,0xa1861194,0xe187118f,0xf188118b, + 0x12ad1189,0x818a12ac,0x92ad12ac,0x618c12ac,0x718d12ac,0x818e12ac,0x92ad12ac,0x519012ac, + 0x619112ac,0x719212ac,0x819312ac,0x92ad12ac,0x119512ac,0x319612ac,0xe19712ac,0xf2ad12ac, + 0x41991220,0x519a01b6,0xc19b01a4,0x719c02ac,0x819d02ac,0x919e02ac,0xa19f02ac,0xb1a002ac, + 0xd1a102ac,0x62ad01a2,0xe1a302ac,0xf2ad02ac,0xc1a512ac,0xd1a612ac,0xe1a712ac,0xf1a811b0, + 0x11a911ac,0x32ad11aa,0xa1ab12ac,0xb2ad12ac,0x81ad12ac,0x91ae12ac,0xa1af12ac,0xb2ad12ac, + 0x61b112ac,0x71b212ac,0x81b312ac,0x91b412ac,0xa1b512ac,0xb2ad12ac,0x51b71204,0x71b801d1, + 0xe1b901c1,0x81ba02ac,0x91bb02ac,0xa1bc02ac,0xb1bd02ac,0xc1be02ac,0xd1bf02ac,0x62ad01c0, + 0xf2ad02ac,0xe1c212ac,0xf1c312ac,0x11c411cb,0x31c511c7,0x62ad11c6,0xd2ad12ac,0xa1c812ac, + 0xb1c912ac,0xc1ca12ac,0xd2ad12ac,0x81cc12ac,0x91cd12ac,0xa1ce12ac,0xb1cf12ac,0xc1d012ac, + 0xd2ad12ac,0x71d211f4,0x31d311e3,0x11d411da,0x61d511d7,0x82ad11d6,0xf2ad12ac,0xd1d812ac, + 0xe1d912ac,0xf2ad12ac,0x81db12ac,0x91dc12ac,0xa1dd12ac,0x62ad11de,0xb1df12ac,0xc1e012ac, + 0xd1e112ac,0xe1e212ac,0xf2ad12ac,0xa1e412ac,0xb1e512ac,0xc1e612ac,0x81e711f0,0x91e811ec, + 0x62ad11e9,0xd1ea12ac,0xe1eb12ac,0xf2ad12ac,0x11ed12ac,0xd1ee12ac,0xe1ef12ac,0xf2ad12ac, + 0x11f112ac,0xd1f212ac,0xe1f312ac,0xf2ad12ac,0xe1f512ac,0xf1f612ac,0x11f711fe,0x31f811fa, + 0x62ad11f9,0xd2ad12ac,0xa1fb12ac,0xb1fc12ac,0xc1fd12ac,0xd2ad12ac,0x81ff12ac,0x920012ac, + 0xa20112ac,0xb20212ac,0xc20312ac,0xd2ad12ac,0xc205020e,0x720602ac,0x820702ac,0x920802ac, + 0xa20902ac,0xb20a02ac,0xd20b02ac,0xe20c02ac,0x62ad020d,0xf2ad02ac,0xc20f12ac,0xd21012ac, + 0xe21112ac,0xf212121a,0x12131216,0x32ad1214,0xa21512ac,0xb2ad12ac,0x821712ac,0x921812ac, + 0xa21912ac,0xb2ad12ac,0x621b12ac,0x721c12ac,0x821d12ac,0x921e12ac,0xa21f12ac,0xb2ad12ac, + 0xb221022c,0x722202ac,0x822302ac,0x922402ac,0xa22502ac,0xc22602ac,0xd22702ac,0x6228022a, + 0x52ad0229,0xe2ad02ac,0xe22b02ac,0xf2ad02ac,0xb22d12ac,0xc22e12ac,0xd22f12ac,0xa230123e, + 0xe2311239,0xf2321235,0x12ad1233,0x823412ac,0x92ad12ac,0x623612ac,0x723712ac,0x823812ac, + 0x92ad12ac,0x523a12ac,0x623b12ac,0x723c12ac,0x823d12ac,0x92ad12ac,0x123f12ac,0x324012ac, + 0xe24112ac,0xf2ad12ac,0x92430255,0x724402ac,0x824502ac,0xa24602ac,0xb24702ac,0x62480251, + 0x5249024e,0x424a024c,0x32ad024b,0xc2ad02ac,0xc24d02ac,0xd2ad02ac,0xc24f02ac,0xd25002ac, + 0xe2ad02ac,0xc25202ac,0xd25302ac,0xe25402ac,0xf2ad02ac,0x925612ac,0xa25712ac,0xb25812ac, + 0x8259126b,0xc25a1266,0xd25b1262,0xe25c125f,0xf2ad125d,0x625e12ac,0x72ad12ac,0x526012ac, + 0x626112ac,0x72ad12ac,0x426312ac,0x526412ac,0x626512ac,0x72ad12ac,0x326712ac,0x426812ac, + 0x526912ac,0x626a12ac,0x72ad12ac,0x126c12ac,0xc26d12ac,0xd26e12ac,0xe26f12ac,0xf2ad12ac, + 0x7271028e,0x827202ac,0x927302ac,0x62740288,0x52750283,0x4276027f,0x3277027c,0x2278027a, + 0x12ad0279,0xa2ad02ac,0xa27b02ac,0xb2ad02ac,0xa27d02ac,0xb27e02ac,0xc2ad02ac,0xa28002ac, + 0xb28102ac,0xc28202ac,0xd2ad02ac,0xa28402ac,0xb28502ac,0xc28602ac,0xd28702ac,0xe2ad02ac, + 0xa28902ac,0xb28a02ac,0xc28b02ac,0xd28c02ac,0xe28d02ac,0xf2ad02ac,0x728f12ac,0x829012ac, + 0x929112ac,0x629212a6,0x529312a1,0x4294129d,0x3295129a,0x22961298,0x12ad1297,0xa2ad12ac, + 0xa29912ac,0xb2ad12ac,0xa29b12ac,0xb29c12ac,0xc2ad12ac,0xa29e12ac,0xb29f12ac,0xc2a012ac, + 0xd2ad12ac,0xa2a212ac,0xb2a312ac,0xc2a412ac,0xd2a512ac,0xe2ad12ac,0xa2a712ac,0xb2a812ac, + 0xc2a912ac,0xd2aa12ac,0xe2ab12ac,0xf2ad12ac,0x000000fe,0x000000ff}; + + + switch(agasttype) { + case AgastFeatureDetector::AGAST_5_8: + table_struct=(uint32_t *)(table_5_8_corner_struct); + break; + case AgastFeatureDetector::AGAST_7_12d: + table_struct=(uint32_t *)(table_7_12d_corner_struct); + break; + case AgastFeatureDetector::AGAST_7_12s: + table_struct=(uint32_t *)(table_7_12s_corner_struct); + break; + case AgastFeatureDetector::OAST_9_16: + default: + table_struct=(uint32_t *)(table_9_16_corner_struct); + break; + } + + while(true) + { + result = agast_tree_search(table_struct, (int *)pixel, ptr, b_test); + if (result == 254) + bmax = b_test; + else + bmin = b_test; + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b_test = (bmin + bmax) / 2; + } +} + +// 8 pixel mask +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + return AGAST_ALL_SCORE(ptr, pixel, threshold, AgastFeatureDetector::AGAST_5_8); +} + +// 12 pixel mask in square format +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + return AGAST_ALL_SCORE(ptr, pixel, threshold, AgastFeatureDetector::AGAST_7_12d); +} + +// 12 pixel mask in diamond format +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + return AGAST_ALL_SCORE(ptr, pixel, threshold, AgastFeatureDetector::AGAST_7_12s); +} + +// 16 pixel mask +template<> +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold) +{ + return AGAST_ALL_SCORE(ptr, pixel, threshold, AgastFeatureDetector::OAST_9_16); +} + +#endif // !(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) + +} +} // namespace cv diff --git a/modules/xfeatures2d/src/agast_score.hpp b/modules/xfeatures2d/src/agast_score.hpp new file mode 100644 index 00000000000..2e013fa12b1 --- /dev/null +++ b/modules/xfeatures2d/src/agast_score.hpp @@ -0,0 +1,71 @@ +/* This is AGAST and OAST, an optimal and accelerated corner detector + based on the accelerated segment tests + Below is the original copyright and the references */ + +/* +Copyright (C) 2010 Elmar Mair +All rights reserved. + +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. + + *Neither the name of the University of Cambridge nor the names of + its contributors may 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 COPYRIGHT OWNER 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. +*/ + +/* +The references are: + * Adaptive and Generic Corner Detection Based on the Accelerated Segment Test, + Elmar Mair and Gregory D. Hager and Darius Burschka + and Michael Suppa and Gerhard Hirzinger ECCV 2010 + URL: http://www6.in.tum.de/Main/ResearchAgast +*/ + + +#ifndef __OPENCV_FEATURES_2D_AGAST_HPP__ +#define __OPENCV_FEATURES_2D_AGAST_HPP__ + +#ifdef __cplusplus + +#include "precomp.hpp" +namespace cv +{ +namespace xfeatures2d +{ + +#if !(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) +int agast_tree_search(const uint32_t table_struct32[], int pixel_[], const unsigned char* const ptr, int threshold); +int AGAST_ALL_SCORE(const uchar* ptr, const int pixel[], int threshold, AgastFeatureDetector::DetectorType agasttype); +#endif //!(defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64)) + + +void makeAgastOffsets(int pixel[16], int row_stride, AgastFeatureDetector::DetectorType type); + +template +int agast_cornerScore(const uchar* ptr, const int pixel[], int threshold); + +} +} +#endif +#endif diff --git a/modules/xfeatures2d/src/akaze.cpp b/modules/xfeatures2d/src/akaze.cpp new file mode 100644 index 00000000000..e5b97758bcc --- /dev/null +++ b/modules/xfeatures2d/src/akaze.cpp @@ -0,0 +1,280 @@ +/*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) 2008, 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 Intel Corporation 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*/ + +/* +OpenCV wrapper of reference implementation of +[1] Fast Explicit Diffusion for Accelerated Features in Nonlinear Scale Spaces. +Pablo F. Alcantarilla, J. Nuevo and Adrien Bartoli. +In British Machine Vision Conference (BMVC), Bristol, UK, September 2013 +http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla13bmvc.pdf +@author Eugene Khvedchenya +*/ + +#include "precomp.hpp" +#include "kaze/AKAZEFeatures.h" + +#include + +namespace cv +{ +namespace xfeatures2d +{ + + using namespace std; + + class AKAZE_Impl : public AKAZE + { + public: + AKAZE_Impl(DescriptorType _descriptor_type, int _descriptor_size, int _descriptor_channels, + float _threshold, int _octaves, int _sublevels, KAZE::DiffusivityType _diffusivity, int _max_points) + : descriptor(_descriptor_type) + , descriptor_channels(_descriptor_channels) + , descriptor_size(_descriptor_size) + , threshold(_threshold) + , octaves(_octaves) + , sublevels(_sublevels) + , diffusivity(_diffusivity) + , max_points(_max_points) + { + } + + virtual ~AKAZE_Impl() CV_OVERRIDE + { + + } + + void setDescriptorType(int dtype) CV_OVERRIDE{ descriptor = dtype; } + int getDescriptorType() const CV_OVERRIDE{ return descriptor; } + + void setDescriptorSize(int dsize) CV_OVERRIDE { descriptor_size = dsize; } + int getDescriptorSize() const CV_OVERRIDE { return descriptor_size; } + + void setDescriptorChannels(int dch) CV_OVERRIDE { descriptor_channels = dch; } + int getDescriptorChannels() const CV_OVERRIDE { return descriptor_channels; } + + void setThreshold(double threshold_) CV_OVERRIDE { threshold = (float)threshold_; } + double getThreshold() const CV_OVERRIDE { return threshold; } + + void setNOctaves(int octaves_) CV_OVERRIDE { octaves = octaves_; } + int getNOctaves() const CV_OVERRIDE { return octaves; } + + void setNOctaveLayers(int octaveLayers_) CV_OVERRIDE { sublevels = octaveLayers_; } + int getNOctaveLayers() const CV_OVERRIDE { return sublevels; } + + void setDiffusivity(int diff_) CV_OVERRIDE{ diffusivity = diff_; } + int getDiffusivity() const CV_OVERRIDE{ return diffusivity; } + + void setMaxPoints(int max_points_) CV_OVERRIDE { max_points = max_points_; } + int getMaxPoints() const CV_OVERRIDE { return max_points; } + + // returns the descriptor size in bytes + int descriptorSize() const CV_OVERRIDE + { + switch (descriptor) + { + case DESCRIPTOR_KAZE: + case DESCRIPTOR_KAZE_UPRIGHT: + return 64; + + case DESCRIPTOR_MLDB: + case DESCRIPTOR_MLDB_UPRIGHT: + // We use the full length binary descriptor -> 486 bits + if (descriptor_size == 0) + { + int t = (6 + 36 + 120) * descriptor_channels; + return divUp(t, 8); + } + else + { + // We use the random bit selection length binary descriptor + return divUp(descriptor_size, 8); + } + + default: + return -1; + } + } + + // returns the descriptor type + int descriptorType() const CV_OVERRIDE + { + switch (descriptor) + { + case DESCRIPTOR_KAZE: + case DESCRIPTOR_KAZE_UPRIGHT: + return CV_32F; + + case DESCRIPTOR_MLDB: + case DESCRIPTOR_MLDB_UPRIGHT: + return CV_8U; + + default: + return -1; + } + } + + // returns the default norm type + int defaultNorm() const CV_OVERRIDE + { + switch (descriptor) + { + case DESCRIPTOR_KAZE: + case DESCRIPTOR_KAZE_UPRIGHT: + return NORM_L2; + + case DESCRIPTOR_MLDB: + case DESCRIPTOR_MLDB_UPRIGHT: + return NORM_HAMMING; + + default: + return -1; + } + } + + void detectAndCompute(InputArray image, InputArray mask, + std::vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints) CV_OVERRIDE + { + CV_INSTRUMENT_REGION(); + + CV_Assert( ! image.empty() ); + + AKAZEOptions options; + options.descriptor = descriptor; + options.descriptor_channels = descriptor_channels; + options.descriptor_size = descriptor_size; + options.img_width = image.cols(); + options.img_height = image.rows(); + options.dthreshold = threshold; + options.omax = octaves; + options.nsublevels = sublevels; + options.diffusivity = diffusivity; + + AKAZEFeatures impl(options); + impl.Create_Nonlinear_Scale_Space(image); + + if (!useProvidedKeypoints) + { + impl.Feature_Detection(keypoints); + } + + if (!mask.empty()) + { + KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat()); + } + + if (max_points > 0 && (int)keypoints.size() > max_points) { + std::partial_sort(keypoints.begin(), keypoints.begin() + max_points, keypoints.end(), + [](const cv::KeyPoint& k1, const cv::KeyPoint& k2) {return k1.response > k2.response;}); + keypoints.erase(keypoints.begin() + max_points, keypoints.end()); + } + + if(descriptors.needed()) + { + impl.Compute_Descriptors(keypoints, descriptors); + + CV_Assert((descriptors.empty() || descriptors.cols() == descriptorSize())); + CV_Assert((descriptors.empty() || (descriptors.type() == descriptorType()))); + } + } + + void write(FileStorage& fs) const CV_OVERRIDE + { + writeFormat(fs); + fs << "name" << getDefaultName(); + fs << "descriptor" << descriptor; + fs << "descriptor_channels" << descriptor_channels; + fs << "descriptor_size" << descriptor_size; + fs << "threshold" << threshold; + fs << "octaves" << octaves; + fs << "sublevels" << sublevels; + fs << "diffusivity" << diffusivity; + fs << "max_points" << max_points; + } + + void read(const FileNode& fn) CV_OVERRIDE + { + // if node is empty, keep previous value + if (!fn["descriptor"].empty()) + descriptor = static_cast((int)fn["descriptor"]); + if (!fn["descriptor_channels"].empty()) + descriptor_channels = (int)fn["descriptor_channels"]; + if (!fn["descriptor_size"].empty()) + descriptor_size = (int)fn["descriptor_size"]; + if (!fn["threshold"].empty()) + threshold = (float)fn["threshold"]; + if (!fn["octaves"].empty()) + octaves = (int)fn["octaves"]; + if (!fn["sublevels"].empty()) + sublevels = (int)fn["sublevels"]; + if (!fn["diffusivity"].empty()) + diffusivity = static_cast((int)fn["diffusivity"]); + if (!fn["max_points"].empty()) + max_points = (int)fn["max_points"]; + } + + int descriptor; + int descriptor_channels; + int descriptor_size; + float threshold; + int octaves; + int sublevels; + int diffusivity; + int max_points; + }; + + Ptr AKAZE::create(DescriptorType descriptor_type, + int descriptor_size, int descriptor_channels, + float threshold, int octaves, + int sublevels, KAZE::DiffusivityType diffusivity, int max_points) + { + return makePtr(descriptor_type, descriptor_size, descriptor_channels, + threshold, octaves, sublevels, diffusivity, max_points); + } + + String AKAZE::getDefaultName() const + { + return (Feature2D::getDefaultName() + ".AKAZE"); + } + +} +} // namespace cv diff --git a/modules/xfeatures2d/src/bagofwords.cpp b/modules/xfeatures2d/src/bagofwords.cpp new file mode 100644 index 00000000000..51640ba6ec1 --- /dev/null +++ b/modules/xfeatures2d/src/bagofwords.cpp @@ -0,0 +1,219 @@ +/*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. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, 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 Intel Corporation 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" + +namespace cv +{ +namespace xfeatures2d +{ + +BOWTrainer::BOWTrainer() : size(0) +{} + +BOWTrainer::~BOWTrainer() +{} + +void BOWTrainer::add( const Mat& _descriptors ) +{ + CV_Assert( !_descriptors.empty() ); + if( !descriptors.empty() ) + { + CV_Assert( descriptors[0].cols == _descriptors.cols ); + CV_Assert( descriptors[0].type() == _descriptors.type() ); + size += _descriptors.rows; + } + else + { + size = _descriptors.rows; + } + + descriptors.push_back(_descriptors); +} + +const std::vector& BOWTrainer::getDescriptors() const +{ + return descriptors; +} + +int BOWTrainer::descriptorsCount() const +{ + return descriptors.empty() ? 0 : size; +} + +void BOWTrainer::clear() +{ + descriptors.clear(); +} + +BOWKMeansTrainer::BOWKMeansTrainer( int _clusterCount, const TermCriteria& _termcrit, + int _attempts, int _flags ) : + clusterCount(_clusterCount), termcrit(_termcrit), attempts(_attempts), flags(_flags) +{} + +Mat BOWKMeansTrainer::cluster() const +{ + CV_INSTRUMENT_REGION(); + + CV_Assert( !descriptors.empty() ); + + Mat mergedDescriptors( descriptorsCount(), descriptors[0].cols, descriptors[0].type() ); + for( size_t i = 0, start = 0; i < descriptors.size(); i++ ) + { + Mat submut = mergedDescriptors.rowRange((int)start, (int)(start + descriptors[i].rows)); + descriptors[i].copyTo(submut); + start += descriptors[i].rows; + } + return cluster( mergedDescriptors ); +} + +BOWKMeansTrainer::~BOWKMeansTrainer() +{} + +Mat BOWKMeansTrainer::cluster( const Mat& _descriptors ) const +{ + CV_INSTRUMENT_REGION(); + + Mat labels, vocabulary; + kmeans( _descriptors, clusterCount, labels, termcrit, attempts, flags, vocabulary ); + return vocabulary; +} + + +BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( const Ptr& _dextractor, + const Ptr& _dmatcher ) : + dextractor(_dextractor), dmatcher(_dmatcher) +{} + +BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( const Ptr& _dmatcher ) : + dmatcher(_dmatcher) +{} + +BOWImgDescriptorExtractor::~BOWImgDescriptorExtractor() +{} + +void BOWImgDescriptorExtractor::setVocabulary( const Mat& _vocabulary ) +{ + dmatcher->clear(); + vocabulary = _vocabulary; + dmatcher->add( std::vector(1, vocabulary) ); +} + +const Mat& BOWImgDescriptorExtractor::getVocabulary() const +{ + return vocabulary; +} + +void BOWImgDescriptorExtractor::compute( InputArray image, std::vector& keypoints, OutputArray imgDescriptor, + std::vector >* pointIdxsOfClusters, Mat* descriptors ) +{ + CV_INSTRUMENT_REGION(); + + imgDescriptor.release(); + + if( keypoints.empty() ) + return; + + // Compute descriptors for the image. + Mat _descriptors; + dextractor->compute( image, keypoints, _descriptors ); + + compute( _descriptors, imgDescriptor, pointIdxsOfClusters ); + + // Add the descriptors of image keypoints + if (descriptors) { + *descriptors = _descriptors.clone(); + } +} + +int BOWImgDescriptorExtractor::descriptorSize() const +{ + return vocabulary.empty() ? 0 : vocabulary.rows; +} + +int BOWImgDescriptorExtractor::descriptorType() const +{ + return CV_32FC1; +} + +void BOWImgDescriptorExtractor::compute( InputArray keypointDescriptors, OutputArray _imgDescriptor, std::vector >* pointIdxsOfClusters ) +{ + CV_INSTRUMENT_REGION(); + + CV_Assert( !vocabulary.empty() ); + CV_Assert(!keypointDescriptors.empty()); + + int clusterCount = descriptorSize(); // = vocabulary.rows + + // Match keypoint descriptors to cluster center (to vocabulary) + std::vector matches; + dmatcher->match( keypointDescriptors, matches ); + + // Compute image descriptor + if( pointIdxsOfClusters ) + { + pointIdxsOfClusters->clear(); + pointIdxsOfClusters->resize(clusterCount); + } + + _imgDescriptor.create(1, clusterCount, descriptorType()); + _imgDescriptor.setTo(Scalar::all(0)); + + Mat imgDescriptor = _imgDescriptor.getMat(); + + float *dptr = imgDescriptor.ptr(); + for( size_t i = 0; i < matches.size(); i++ ) + { + int queryIdx = matches[i].queryIdx; + int trainIdx = matches[i].trainIdx; // cluster index + CV_Assert( queryIdx == (int)i ); + + dptr[trainIdx] = dptr[trainIdx] + 1.f; + if( pointIdxsOfClusters ) + (*pointIdxsOfClusters)[trainIdx].push_back( queryIdx ); + } + + // Normalize image descriptor. + imgDescriptor /= keypointDescriptors.size().height; +} + +} +} // namespace cv diff --git a/modules/xfeatures2d/src/brisk.cpp b/modules/xfeatures2d/src/brisk.cpp new file mode 100644 index 00000000000..2eb28420bdb --- /dev/null +++ b/modules/xfeatures2d/src/brisk.cpp @@ -0,0 +1,2435 @@ +/********************************************************************* + * Software License Agreement (BSD License) + * + * Copyright (C) 2011 The Autonomous Systems Lab (ASL), ETH Zurich, + * Stefan Leutenegger, Simon Lynen and Margarita Chli. + * Copyright (c) 2009, Willow Garage, Inc. + * All rights reserved. + * + * 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. + * * Neither the name of the Willow Garage nor the names of its + * contributors may 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 + * COPYRIGHT OWNER 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. + *********************************************************************/ + +/* + BRISK - Binary Robust Invariant Scalable Keypoints + Reference implementation of + [1] Stefan Leutenegger,Margarita Chli and Roland Siegwart, BRISK: + Binary Robust Invariant Scalable Keypoints, in Proceedings of + the IEEE International Conference on Computer Vision (ICCV2011). + */ + +#include "precomp.hpp" +#include +#include + +#include "agast_score.hpp" + +namespace cv +{ +namespace xfeatures2d +{ +class BRISK_Impl CV_FINAL : public BRISK +{ +public: + explicit BRISK_Impl(int _threshold=30, int _octaves=3, float _patternScale=1.0f); + // custom setup + explicit BRISK_Impl(const std::vector &radiusList, const std::vector &numberList, + float dMax=5.85f, float dMin=8.2f, const std::vector indexChange=std::vector()); + + explicit BRISK_Impl(int thresh, int octaves, const std::vector &radiusList, + const std::vector &numberList, float dMax=5.85f, float dMin=8.2f, + const std::vector indexChange=std::vector()); + + virtual ~BRISK_Impl(); + + void read( const FileNode& fn) CV_OVERRIDE; + void write( FileStorage& fs) const CV_OVERRIDE; + + int descriptorSize() const CV_OVERRIDE + { + return strings_; + } + + int descriptorType() const CV_OVERRIDE + { + return CV_8U; + } + + int defaultNorm() const CV_OVERRIDE + { + return NORM_HAMMING; + } + + virtual void setThreshold(int threshold_in) CV_OVERRIDE + { + threshold = threshold_in; + } + + virtual int getThreshold() const CV_OVERRIDE + { + return threshold; + } + + virtual void setOctaves(int octaves_in) CV_OVERRIDE + { + octaves = octaves_in; + } + + virtual int getOctaves() const CV_OVERRIDE + { + return octaves; + } + virtual void setPatternScale(float _patternScale) CV_OVERRIDE + { + patternScale = _patternScale; + std::vector rList; + std::vector nList; + + // this is the standard pattern found to be suitable also + rList.resize(5); + nList.resize(5); + const double f = 0.85 * patternScale; + + rList[0] = (float)(f * 0.); + rList[1] = (float)(f * 2.9); + rList[2] = (float)(f * 4.9); + rList[3] = (float)(f * 7.4); + rList[4] = (float)(f * 10.8); + + nList[0] = 1; + nList[1] = 10; + nList[2] = 14; + nList[3] = 15; + nList[4] = 20; + + generateKernel(rList, nList, (float)(5.85 * patternScale), (float)(8.2 * patternScale)); + } + virtual float getPatternScale() const CV_OVERRIDE + { + return patternScale; + } + + // call this to generate the kernel: + // circle of radius r (pixels), with n points; + // short pairings with dMax, long pairings with dMin + void generateKernel(const std::vector &radiusList, + const std::vector &numberList, float dMax=5.85f, float dMin=8.2f, + const std::vector &indexChange=std::vector()); + + void detectAndCompute( InputArray image, InputArray mask, + CV_OUT std::vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints ) CV_OVERRIDE; + +protected: + + void computeKeypointsNoOrientation(InputArray image, InputArray mask, std::vector& keypoints) const; + void computeDescriptorsAndOrOrientation(InputArray image, InputArray mask, std::vector& keypoints, + OutputArray descriptors, bool doDescriptors, bool doOrientation, + bool useProvidedKeypoints) const; + + // Feature parameters + CV_PROP_RW int threshold; + CV_PROP_RW int octaves; + CV_PROP_RW float patternScale; + + // some helper structures for the Brisk pattern representation + struct BriskPatternPoint{ + float x; // x coordinate relative to center + float y; // x coordinate relative to center + float sigma; // Gaussian smoothing sigma + }; + struct BriskShortPair{ + unsigned int i; // index of the first pattern point + unsigned int j; // index of other pattern point + }; + struct BriskLongPair{ + unsigned int i; // index of the first pattern point + unsigned int j; // index of other pattern point + int weighted_dx; // 1024.0/dx + int weighted_dy; // 1024.0/dy + }; + inline int smoothedIntensity(const cv::Mat& image, + const cv::Mat& integral,const float key_x, + const float key_y, const unsigned int scale, + const unsigned int rot, const unsigned int point) const; + // pattern properties + BriskPatternPoint* patternPoints_; //[i][rotation][scale] + unsigned int points_; // total number of collocation points + float* scaleList_; // lists the scaling per scale index [scale] + unsigned int* sizeList_; // lists the total pattern size per scale index [scale] + static const unsigned int scales_; // scales discretization + static const float scalerange_; // span of sizes 40->4 Octaves - else, this needs to be adjusted... + static const unsigned int n_rot_; // discretization of the rotation look-up + + // pairs + int strings_; // number of uchars the descriptor consists of + float dMax_; // short pair maximum distance + float dMin_; // long pair maximum distance + BriskShortPair* shortPairs_; // d<_dMax + BriskLongPair* longPairs_; // d>_dMin + unsigned int noShortPairs_; // number of shortParis + unsigned int noLongPairs_; // number of longParis + + // general + static const float basicSize_; + +private: + BRISK_Impl(const BRISK_Impl &); // copy disabled + BRISK_Impl& operator=(const BRISK_Impl &); // assign disabled +}; + + +// a layer in the Brisk detector pyramid +class BriskLayer +{ +public: + // constructor arguments + struct CommonParams + { + static const int HALFSAMPLE = 0; + static const int TWOTHIRDSAMPLE = 1; + }; + // construct a base layer + BriskLayer(const cv::Mat& img, float scale = 1.0f, float offset = 0.0f); + // derive a layer + BriskLayer(const BriskLayer& layer, int mode); + + // Agast without non-max suppression + void + getAgastPoints(int threshold, std::vector& keypoints); + + // get scores - attention, this is in layer coordinates, not scale=1 coordinates! + inline int + getAgastScore(int x, int y, int threshold) const; + inline int + getAgastScore_5_8(int x, int y, int threshold) const; + inline int + getAgastScore(float xf, float yf, int threshold, float scale = 1.0f) const; + + // accessors + inline const cv::Mat& + img() const + { + return img_; + } + inline const cv::Mat& + scores() const + { + return scores_; + } + inline float + scale() const + { + return scale_; + } + inline float + offset() const + { + return offset_; + } + + // half sampling + static inline void + halfsample(const cv::Mat& srcimg, cv::Mat& dstimg); + // two third sampling + static inline void + twothirdsample(const cv::Mat& srcimg, cv::Mat& dstimg); + +private: + // access gray values (smoothed/interpolated) + inline int + value(const cv::Mat& mat, float xf, float yf, float scale) const; + // the image + cv::Mat img_; + // its Agast scores + cv::Mat_ scores_; + // coordinate transformation + float scale_; + float offset_; + // agast + cv::Ptr oast_9_16_; + int pixel_5_8_[25]; + int pixel_9_16_[25]; +}; + +class BriskScaleSpace +{ +public: + // construct telling the octaves number: + BriskScaleSpace(int _octaves = 3); + ~BriskScaleSpace(); + + // construct the image pyramids + void + constructPyramid(const cv::Mat& image); + + // get Keypoints + void + getKeypoints(const int _threshold, std::vector& keypoints); + +protected: + // nonmax suppression: + inline bool + isMax2D(const int layer, const int x_layer, const int y_layer); + // 1D (scale axis) refinement: + inline float + refine1D(const float s_05, const float s0, const float s05, float& max) const; // around octave + inline float + refine1D_1(const float s_05, const float s0, const float s05, float& max) const; // around intra + inline float + refine1D_2(const float s_05, const float s0, const float s05, float& max) const; // around octave 0 only + // 2D maximum refinement: + inline float + subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, const int s_1_0, const int s_1_1, const int s_1_2, + const int s_2_0, const int s_2_1, const int s_2_2, float& delta_x, float& delta_y) const; + // 3D maximum refinement centered around (x_layer,y_layer) + inline float + refine3D(const int layer, const int x_layer, const int y_layer, float& x, float& y, float& scale, bool& ismax) const; + + // interpolated score access with recalculation when needed: + inline int + getScoreAbove(const int layer, const int x_layer, const int y_layer) const; + inline int + getScoreBelow(const int layer, const int x_layer, const int y_layer) const; + + // return the maximum of score patches above or below + inline float + getScoreMaxAbove(const int layer, const int x_layer, const int y_layer, const int threshold, bool& ismax, + float& dx, float& dy) const; + inline float + getScoreMaxBelow(const int layer, const int x_layer, const int y_layer, const int threshold, bool& ismax, + float& dx, float& dy) const; + + // the image pyramids: + int layers_; + std::vector pyramid_; + + // some constant parameters: + static const float safetyFactor_; + static const float basicSize_; +}; + +const float BRISK_Impl::basicSize_ = 12.0f; +const unsigned int BRISK_Impl::scales_ = 64; +const float BRISK_Impl::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted... +const unsigned int BRISK_Impl::n_rot_ = 1024; // discretization of the rotation look-up + +const float BriskScaleSpace::safetyFactor_ = 1.0f; +const float BriskScaleSpace::basicSize_ = 12.0f; + +// constructors +BRISK_Impl::BRISK_Impl(int _threshold, int _octaves, float _patternScale) +{ + threshold = _threshold; + octaves = _octaves; + + setPatternScale(_patternScale); +} + +BRISK_Impl::BRISK_Impl(const std::vector &radiusList, + const std::vector &numberList, + float dMax, float dMin, + const std::vector indexChange) +{ + generateKernel(radiusList, numberList, dMax, dMin, indexChange); + threshold = 20; + octaves = 3; +} + +BRISK_Impl::BRISK_Impl(int thresh, + int octaves_in, + const std::vector &radiusList, + const std::vector &numberList, + float dMax, float dMin, + const std::vector indexChange) +{ + generateKernel(radiusList, numberList, dMax, dMin, indexChange); + threshold = thresh; + octaves = octaves_in; +} + +void BRISK_Impl::read( const FileNode& fn) +{ + // if node is empty, keep previous value + if (!fn["threshold"].empty()) + fn["threshold"] >> threshold; + if (!fn["octaves"].empty()) + fn["octaves"] >> octaves; + if (!fn["patternScale"].empty()) + { + float _patternScale; + fn["patternScale"] >> _patternScale; + setPatternScale(_patternScale); + } +} +void BRISK_Impl::write( FileStorage& fs) const +{ + if(fs.isOpened()) + { + fs << "name" << getDefaultName(); + fs << "threshold" << threshold; + fs << "octaves" << octaves; + fs << "patternScale" << patternScale; + } +} + +void +BRISK_Impl::generateKernel(const std::vector &radiusList, + const std::vector &numberList, + float dMax, float dMin, + const std::vector& _indexChange) +{ + std::vector indexChange = _indexChange; + dMax_ = dMax; + dMin_ = dMin; + + // get the total number of points + const int rings = (int)radiusList.size(); + CV_Assert(radiusList.size() != 0 && radiusList.size() == numberList.size()); + points_ = 0; // remember the total number of points + double sineThetaLookupTable[n_rot_]; + double cosThetaLookupTable[n_rot_]; + for (int ring = 0; ring < rings; ring++) + { + points_ += numberList[ring]; + } + + // using a sine/cosine approximation for the lookup table + // utilizes the trig identities: + // sin(a + b) = sin(a)cos(b) + cos(a)sin(b) + // cos(a + b) = cos(a)cos(b) - sin(a)sin(b) + // and the fact that sin(0) = 0, cos(0) = 1 + double cosval = 1., sinval = 0.; + double dcos = cos(2*CV_PI/double(n_rot_)), dsin = sin(2*CV_PI/double(n_rot_)); + for( size_t rot = 0; rot < n_rot_; ++rot) + { + sineThetaLookupTable[rot] = sinval; + cosThetaLookupTable[rot] = cosval; + double t = sinval*dcos + cosval*dsin; + cosval = cosval*dcos - sinval*dsin; + sinval = t; + } + // set up the patterns + patternPoints_ = new BriskPatternPoint[points_ * scales_ * n_rot_]; + + // define the scale discretization: + static const float lb_scale = (float)(std::log(scalerange_) / std::log(2.0)); + static const float lb_scale_step = lb_scale / (scales_); + + scaleList_ = new float[scales_]; + sizeList_ = new unsigned int[scales_]; + + const float sigma_scale = 1.3f; + + for (unsigned int scale = 0; scale < scales_; ++scale) { + scaleList_[scale] = (float) std::pow((double) 2.0, (double) (scale * lb_scale_step)); + sizeList_[scale] = 0; + BriskPatternPoint *patternIteratorOuter = patternPoints_ + (scale * n_rot_ * points_); + // generate the pattern points look-up + for (int ring = 0; ring < rings; ++ring) { + double scaleRadiusProduct = scaleList_[scale] * radiusList[ring]; + float patternSigma = 0.0f; + if (ring == 0) { + patternSigma = sigma_scale * scaleList_[scale] * 0.5f; + } else { + patternSigma = (float) (sigma_scale * scaleList_[scale] * (double(radiusList[ring])) + * sin(CV_PI / numberList[ring])); + } + // adapt the sizeList if necessary + const unsigned int size = cvCeil(((scaleList_[scale] * radiusList[ring]) + patternSigma)) + 1; + if (sizeList_[scale] < size) { + sizeList_[scale] = size; + } + for (int num = 0; num < numberList[ring]; ++num) { + BriskPatternPoint *patternIterator = patternIteratorOuter; + double alpha = (double(num)) * 2 * CV_PI / double(numberList[ring]); + double sine_alpha = sin(alpha); + double cosine_alpha = cos(alpha); + + for (size_t rot = 0; rot < n_rot_; ++rot) { + double cosine_theta = cosThetaLookupTable[rot]; + double sine_theta = sineThetaLookupTable[rot]; + + // the actual coordinates on the circle + // sin(a + b) = sin(a) cos(b) + cos(a) sin(b) + // cos(a + b) = cos(a) cos(b) - sin(a) sin(b) + patternIterator->x = (float) (scaleRadiusProduct * + (cosine_theta * cosine_alpha - + sine_theta * sine_alpha)); // feature rotation plus angle of the point + patternIterator->y = (float) (scaleRadiusProduct * + (sine_theta * cosine_alpha + cosine_theta * sine_alpha)); + patternIterator->sigma = patternSigma; + // and the gaussian kernel sigma + // increment the iterator + patternIterator += points_; + } + ++patternIteratorOuter; + } + } + } + + // now also generate pairings + shortPairs_ = new BriskShortPair[points_ * (points_ - 1) / 2]; + longPairs_ = new BriskLongPair[points_ * (points_ - 1) / 2]; + noShortPairs_ = 0; + noLongPairs_ = 0; + + // fill indexChange with 0..n if empty + unsigned int indSize = (unsigned int)indexChange.size(); + if (indSize == 0) + { + indexChange.resize(points_ * (points_ - 1) / 2); + indSize = (unsigned int)indexChange.size(); + + for (unsigned int i = 0; i < indSize; i++) + indexChange[i] = i; + } + const float dMin_sq = dMin_ * dMin_; + const float dMax_sq = dMax_ * dMax_; + for (unsigned int i = 1; i < points_; i++) + { + for (unsigned int j = 0; j < i; j++) + { //(find all the pairs) + // point pair distance: + const float dx = patternPoints_[j].x - patternPoints_[i].x; + const float dy = patternPoints_[j].y - patternPoints_[i].y; + const float norm_sq = (dx * dx + dy * dy); + if (norm_sq > dMin_sq) + { + // save to long pairs + BriskLongPair& longPair = longPairs_[noLongPairs_]; + longPair.weighted_dx = int((dx / (norm_sq)) * 2048.0 + 0.5); + longPair.weighted_dy = int((dy / (norm_sq)) * 2048.0 + 0.5); + longPair.i = i; + longPair.j = j; + ++noLongPairs_; + } + else if (norm_sq < dMax_sq) + { + // save to short pairs + CV_Assert(noShortPairs_ < indSize); + // make sure the user passes something sensible + BriskShortPair& shortPair = shortPairs_[indexChange[noShortPairs_]]; + shortPair.j = j; + shortPair.i = i; + ++noShortPairs_; + } + } + } + + // no bits: + strings_ = (int) ceil((float(noShortPairs_)) / 128.0) * 4 * 4; +} + +// simple alternative: +inline int +BRISK_Impl::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const float key_x, + const float key_y, const unsigned int scale, const unsigned int rot, + const unsigned int point) const +{ + + // get the float position + const BriskPatternPoint& briskPoint = patternPoints_[scale * n_rot_ * points_ + rot * points_ + point]; + const float xf = briskPoint.x + key_x; + const float yf = briskPoint.y + key_y; + const int x = int(xf); + const int y = int(yf); + const int& imagecols = image.cols; + + // get the sigma: + const float sigma_half = briskPoint.sigma; + const float area = 4.0f * sigma_half * sigma_half; + + // calculate output: + int ret_val; + if (sigma_half < 0.5) + { + //interpolation multipliers: + const int r_x = (int)((xf - x) * 1024); + const int r_y = (int)((yf - y) * 1024); + const int r_x_1 = (1024 - r_x); + const int r_y_1 = (1024 - r_y); + const uchar* ptr = &image.at(y, x); + size_t step = image.step; + // just interpolate: + ret_val = r_x_1 * r_y_1 * ptr[0] + r_x * r_y_1 * ptr[1] + + r_x * r_y * ptr[step] + r_x_1 * r_y * ptr[step+1]; + return (ret_val + 512) / 1024; + } + + // this is the standard case (simple, not speed optimized yet): + + // scaling: + const int scaling = (int)(4194304.0 / area); + const int scaling2 = int(float(scaling) * area / 1024.0); + CV_Assert(scaling2 != 0); + + // the integral image is larger: + const int integralcols = imagecols + 1; + + // calculate borders + const float x_1 = xf - sigma_half; + const float x1 = xf + sigma_half; + const float y_1 = yf - sigma_half; + const float y1 = yf + sigma_half; + + const int x_left = int(x_1 + 0.5); + const int y_top = int(y_1 + 0.5); + const int x_right = int(x1 + 0.5); + const int y_bottom = int(y1 + 0.5); + + // overlap area - multiplication factors: + const float r_x_1 = float(x_left) - x_1 + 0.5f; + const float r_y_1 = float(y_top) - y_1 + 0.5f; + const float r_x1 = x1 - float(x_right) + 0.5f; + const float r_y1 = y1 - float(y_bottom) + 0.5f; + const int dx = x_right - x_left - 1; + const int dy = y_bottom - y_top - 1; + const int A = (int)((r_x_1 * r_y_1) * scaling); + const int B = (int)((r_x1 * r_y_1) * scaling); + const int C = (int)((r_x1 * r_y1) * scaling); + const int D = (int)((r_x_1 * r_y1) * scaling); + const int r_x_1_i = (int)(r_x_1 * scaling); + const int r_y_1_i = (int)(r_y_1 * scaling); + const int r_x1_i = (int)(r_x1 * scaling); + const int r_y1_i = (int)(r_y1 * scaling); + + if (dx + dy > 2) + { + // now the calculation: + const uchar* ptr = image.ptr() + x_left + imagecols * y_top; + // first the corners: + ret_val = A * int(*ptr); + ptr += dx + 1; + ret_val += B * int(*ptr); + ptr += dy * imagecols + 1; + ret_val += C * int(*ptr); + ptr -= dx + 1; + ret_val += D * int(*ptr); + + // next the edges: + const int* ptr_integral = integral.ptr() + x_left + integralcols * y_top + 1; + // find a simple path through the different surface corners + const int tmp1 = (*ptr_integral); + ptr_integral += dx; + const int tmp2 = (*ptr_integral); + ptr_integral += integralcols; + const int tmp3 = (*ptr_integral); + ptr_integral++; + const int tmp4 = (*ptr_integral); + ptr_integral += dy * integralcols; + const int tmp5 = (*ptr_integral); + ptr_integral--; + const int tmp6 = (*ptr_integral); + ptr_integral += integralcols; + const int tmp7 = (*ptr_integral); + ptr_integral -= dx; + const int tmp8 = (*ptr_integral); + ptr_integral -= integralcols; + const int tmp9 = (*ptr_integral); + ptr_integral--; + const int tmp10 = (*ptr_integral); + ptr_integral -= dy * integralcols; + const int tmp11 = (*ptr_integral); + ptr_integral++; + const int tmp12 = (*ptr_integral); + + // assign the weighted surface integrals: + const int upper = (tmp3 - tmp2 + tmp1 - tmp12) * r_y_1_i; + const int middle = (tmp6 - tmp3 + tmp12 - tmp9) * scaling; + const int left = (tmp9 - tmp12 + tmp11 - tmp10) * r_x_1_i; + const int right = (tmp5 - tmp4 + tmp3 - tmp6) * r_x1_i; + const int bottom = (tmp7 - tmp6 + tmp9 - tmp8) * r_y1_i; + + return (ret_val + upper + middle + left + right + bottom + scaling2 / 2) / scaling2; + } + + // now the calculation: + const uchar* ptr = image.ptr() + x_left + imagecols * y_top; + // first row: + ret_val = A * int(*ptr); + ptr++; + const uchar* end1 = ptr + dx; + for (; ptr < end1; ptr++) + { + ret_val += r_y_1_i * int(*ptr); + } + ret_val += B * int(*ptr); + // middle ones: + ptr += imagecols - dx - 1; + const uchar* end_j = ptr + dy * imagecols; + for (; ptr < end_j; ptr += imagecols - dx - 1) + { + ret_val += r_x_1_i * int(*ptr); + ptr++; + const uchar* end2 = ptr + dx; + for (; ptr < end2; ptr++) + { + ret_val += int(*ptr) * scaling; + } + ret_val += r_x1_i * int(*ptr); + } + // last row: + ret_val += D * int(*ptr); + ptr++; + const uchar* end3 = ptr + dx; + for (; ptr < end3; ptr++) + { + ret_val += r_y1_i * int(*ptr); + } + ret_val += C * int(*ptr); + + return (ret_val + scaling2 / 2) / scaling2; +} + +inline bool +RoiPredicate(const float minX, const float minY, const float maxX, const float maxY, const KeyPoint& keyPt) +{ + const Point2f& pt = keyPt.pt; + return (pt.x < minX) || (pt.x >= maxX) || (pt.y < minY) || (pt.y >= maxY); +} + +// computes the descriptor +void +BRISK_Impl::detectAndCompute( InputArray _image, InputArray _mask, std::vector& keypoints, + OutputArray _descriptors, bool useProvidedKeypoints) +{ + bool doOrientation=true; + + // If the user specified cv::noArray(), this will yield false. Otherwise it will return true. + bool doDescriptors = _descriptors.needed(); + + computeDescriptorsAndOrOrientation(_image, _mask, keypoints, _descriptors, doDescriptors, doOrientation, + useProvidedKeypoints); +} + +void +BRISK_Impl::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, std::vector& keypoints, + OutputArray _descriptors, bool doDescriptors, bool doOrientation, + bool useProvidedKeypoints) const +{ + Mat image = _image.getMat(), mask = _mask.getMat(); + if( image.type() != CV_8UC1 ) + cvtColor(image, image, COLOR_BGR2GRAY); + + if (!useProvidedKeypoints) + { + doOrientation = true; + computeKeypointsNoOrientation(_image, _mask, keypoints); + } + + //Remove keypoints very close to the border + size_t ksize = keypoints.size(); + std::vector kscales; // remember the scale per keypoint + kscales.resize(ksize); + static const float log2 = 0.693147180559945f; + static const float lb_scalerange = (float)(std::log(scalerange_) / (log2)); + std::vector::iterator beginning = keypoints.begin(); + std::vector::iterator beginningkscales = kscales.begin(); + static const float basicSize06 = basicSize_ * 0.6f; + for (size_t k = 0; k < ksize; k++) + { + unsigned int scale; + scale = std::max((int) (scales_ / lb_scalerange * (std::log(keypoints[k].size / (basicSize06)) / log2) + 0.5), 0); + // saturate + if (scale >= scales_) + scale = scales_ - 1; + kscales[k] = scale; + const int border = sizeList_[scale]; + const int border_x = image.cols - border; + const int border_y = image.rows - border; + if (RoiPredicate((float)border, (float)border, (float)border_x, (float)border_y, keypoints[k])) + { + keypoints.erase(beginning + k); + kscales.erase(beginningkscales + k); + if (k == 0) + { + beginning = keypoints.begin(); + beginningkscales = kscales.begin(); + } + ksize--; + k--; + } + } + + // first, calculate the integral image over the whole image: + // current integral image + cv::Mat _integral; // the integral image + cv::integral(image, _integral); + + int* _values = new int[points_]; // for temporary use + + // resize the descriptors: + cv::Mat descriptors; + if (doDescriptors) + { + _descriptors.create((int)ksize, strings_, CV_8U); + descriptors = _descriptors.getMat(); + descriptors.setTo(0); + } + + // now do the extraction for all keypoints: + + // temporary variables containing gray values at sample points: + int t1; + int t2; + + // the feature orientation + const uchar* ptr = descriptors.ptr(); + for (size_t k = 0; k < ksize; k++) + { + cv::KeyPoint& kp = keypoints[k]; + const int& scale = kscales[k]; + const float& x = kp.pt.x; + const float& y = kp.pt.y; + + if (doOrientation) + { + // get the gray values in the unrotated pattern + for (unsigned int i = 0; i < points_; i++) + { + _values[i] = smoothedIntensity(image, _integral, x, y, scale, 0, i); + } + + int direction0 = 0; + int direction1 = 0; + // now iterate through the long pairings + const BriskLongPair* max = longPairs_ + noLongPairs_; + for (BriskLongPair* iter = longPairs_; iter < max; ++iter) + { + CV_Assert(iter->i < points_ && iter->j < points_); + t1 = *(_values + iter->i); + t2 = *(_values + iter->j); + const int delta_t = (t1 - t2); + // update the direction: + const int tmp0 = delta_t * (iter->weighted_dx) / 1024; + const int tmp1 = delta_t * (iter->weighted_dy) / 1024; + direction0 += tmp0; + direction1 += tmp1; + } + kp.angle = (float)(atan2((float) direction1, (float) direction0) / CV_PI * 180.0); + + if (!doDescriptors) + { + if (kp.angle < 0) + kp.angle += 360.f; + } + } + + if (!doDescriptors) + continue; + + int theta; + if (kp.angle==-1) + { + // don't compute the gradient direction, just assign a rotation of 0 + theta = 0; + } + else + { + theta = (int) (n_rot_ * (kp.angle / (360.0)) + 0.5); + if (theta < 0) + theta += n_rot_; + if (theta >= int(n_rot_)) + theta -= n_rot_; + } + + if (kp.angle < 0) + kp.angle += 360.f; + + // now also extract the stuff for the actual direction: + // let us compute the smoothed values + int shifter = 0; + + //unsigned int mean=0; + // get the gray values in the rotated pattern + for (unsigned int i = 0; i < points_; i++) + { + _values[i] = smoothedIntensity(image, _integral, x, y, scale, theta, i); + } + + // now iterate through all the pairings + unsigned int* ptr2 = (unsigned int*) ptr; + const BriskShortPair* max = shortPairs_ + noShortPairs_; + for (BriskShortPair* iter = shortPairs_; iter < max; ++iter) + { + CV_Assert(iter->i < points_ && iter->j < points_); + t1 = *(_values + iter->i); + t2 = *(_values + iter->j); + if (t1 > t2) + { + *ptr2 |= ((1) << shifter); + + } // else already initialized with zero + // take care of the iterators: + ++shifter; + if (shifter == 32) + { + shifter = 0; + ++ptr2; + } + } + + ptr += strings_; + } + + // clean-up + delete[] _values; +} + + +BRISK_Impl::~BRISK_Impl() +{ + delete[] patternPoints_; + delete[] shortPairs_; + delete[] longPairs_; + delete[] scaleList_; + delete[] sizeList_; +} + +void +BRISK_Impl::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::vector& keypoints) const +{ + Mat image = _image.getMat(), mask = _mask.getMat(); + if( image.type() != CV_8UC1 ) + cvtColor(_image, image, COLOR_BGR2GRAY); + + BriskScaleSpace briskScaleSpace(octaves); + briskScaleSpace.constructPyramid(image); + briskScaleSpace.getKeypoints(threshold, keypoints); + + // remove invalid points + KeyPointsFilter::runByPixelsMask(keypoints, mask); +} + +// construct telling the octaves number: +BriskScaleSpace::BriskScaleSpace(int _octaves) +{ + if (_octaves == 0) + layers_ = 1; + else + layers_ = 2 * _octaves; +} +BriskScaleSpace::~BriskScaleSpace() +{ + +} +// construct the image pyramids +void +BriskScaleSpace::constructPyramid(const cv::Mat& image) +{ + + // set correct size: + pyramid_.clear(); + + // fill the pyramid: + pyramid_.push_back(BriskLayer(image.clone())); + if (layers_ > 1) + { + pyramid_.push_back(BriskLayer(pyramid_.back(), BriskLayer::CommonParams::TWOTHIRDSAMPLE)); + } + const int octaves2 = layers_; + + for (uchar i = 2; i < octaves2; i += 2) + { + pyramid_.push_back(BriskLayer(pyramid_[i - 2], BriskLayer::CommonParams::HALFSAMPLE)); + pyramid_.push_back(BriskLayer(pyramid_[i - 1], BriskLayer::CommonParams::HALFSAMPLE)); + } +} + +void +BriskScaleSpace::getKeypoints(const int threshold_, std::vector& keypoints) +{ + // make sure keypoints is empty + keypoints.resize(0); + keypoints.reserve(2000); + + // assign thresholds + int safeThreshold_ = (int)(threshold_ * safetyFactor_); + std::vector > agastPoints; + agastPoints.resize(layers_); + + // go through the octaves and intra layers and calculate agast corner scores: + for (int i = 0; i < layers_; i++) + { + // call OAST16_9 without nms + BriskLayer& l = pyramid_[i]; + l.getAgastPoints(safeThreshold_, agastPoints[i]); + } + + if (layers_ == 1) + { + // just do a simple 2d subpixel refinement... + const size_t num = agastPoints[0].size(); + for (size_t n = 0; n < num; n++) + { + const cv::Point2f& point = agastPoints.at(0)[n].pt; + // first check if it is a maximum: + if (!isMax2D(0, (int)point.x, (int)point.y)) + continue; + + // let's do the subpixel and float scale refinement: + BriskLayer& l = pyramid_[0]; + int s_0_0 = l.getAgastScore(point.x - 1, point.y - 1, 1); + int s_1_0 = l.getAgastScore(point.x, point.y - 1, 1); + int s_2_0 = l.getAgastScore(point.x + 1, point.y - 1, 1); + int s_2_1 = l.getAgastScore(point.x + 1, point.y, 1); + int s_1_1 = l.getAgastScore(point.x, point.y, 1); + int s_0_1 = l.getAgastScore(point.x - 1, point.y, 1); + int s_0_2 = l.getAgastScore(point.x - 1, point.y + 1, 1); + int s_1_2 = l.getAgastScore(point.x, point.y + 1, 1); + int s_2_2 = l.getAgastScore(point.x + 1, point.y + 1, 1); + float delta_x, delta_y; + float max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x, delta_y); + + // store: + keypoints.push_back(cv::KeyPoint(float(point.x) + delta_x, float(point.y) + delta_y, basicSize_, -1, max, 0)); + + } + + return; + } + + float x, y, scale, score; + for (int i = 0; i < layers_; i++) + { + BriskLayer& l = pyramid_[i]; + const size_t num = agastPoints[i].size(); + if (i == layers_ - 1) + { + for (size_t n = 0; n < num; n++) + { + const cv::Point2f& point = agastPoints.at(i)[n].pt; + // consider only 2D maxima... + if (!isMax2D(i, (int)point.x, (int)point.y)) + continue; + + bool ismax; + float dx, dy; + getScoreMaxBelow(i, (int)point.x, (int)point.y, l.getAgastScore(point.x, point.y, safeThreshold_), ismax, dx, dy); + if (!ismax) + continue; + + // get the patch on this layer: + int s_0_0 = l.getAgastScore(point.x - 1, point.y - 1, 1); + int s_1_0 = l.getAgastScore(point.x, point.y - 1, 1); + int s_2_0 = l.getAgastScore(point.x + 1, point.y - 1, 1); + int s_2_1 = l.getAgastScore(point.x + 1, point.y, 1); + int s_1_1 = l.getAgastScore(point.x, point.y, 1); + int s_0_1 = l.getAgastScore(point.x - 1, point.y, 1); + int s_0_2 = l.getAgastScore(point.x - 1, point.y + 1, 1); + int s_1_2 = l.getAgastScore(point.x, point.y + 1, 1); + int s_2_2 = l.getAgastScore(point.x + 1, point.y + 1, 1); + float delta_x, delta_y; + float max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x, delta_y); + + // store: + keypoints.push_back( + cv::KeyPoint((float(point.x) + delta_x) * l.scale() + l.offset(), + (float(point.y) + delta_y) * l.scale() + l.offset(), basicSize_ * l.scale(), -1, max, i)); + } + } + else + { + // not the last layer: + for (size_t n = 0; n < num; n++) + { + const cv::Point2f& point = agastPoints.at(i)[n].pt; + + // first check if it is a maximum: + if (!isMax2D(i, (int)point.x, (int)point.y)) + continue; + + // let's do the subpixel and float scale refinement: + bool ismax=false; + score = refine3D(i, (int)point.x, (int)point.y, x, y, scale, ismax); + if (!ismax) + { + continue; + } + + // finally store the detected keypoint: + if (score > float(threshold_)) + { + keypoints.push_back(cv::KeyPoint(x, y, basicSize_ * scale, -1, score, i)); + } + } + } + } +} + +// interpolated score access with recalculation when needed: +inline int +BriskScaleSpace::getScoreAbove(const int layer, const int x_layer, const int y_layer) const +{ + CV_Assert(layer < layers_-1); + const BriskLayer& l = pyramid_[layer + 1]; + if (layer % 2 == 0) + { // octave + const int sixths_x = 4 * x_layer - 1; + const int x_above = sixths_x / 6; + const int sixths_y = 4 * y_layer - 1; + const int y_above = sixths_y / 6; + const int r_x = (sixths_x % 6); + const int r_x_1 = 6 - r_x; + const int r_y = (sixths_y % 6); + const int r_y_1 = 6 - r_y; + uchar score = 0xFF + & ((r_x_1 * r_y_1 * l.getAgastScore(x_above, y_above, 1) + r_x * r_y_1 + * l.getAgastScore(x_above + 1, y_above, 1) + + r_x_1 * r_y * l.getAgastScore(x_above, y_above + 1, 1) + + r_x * r_y * l.getAgastScore(x_above + 1, y_above + 1, 1) + 18) + / 36); + + return score; + } + else + { // intra + const int eighths_x = 6 * x_layer - 1; + const int x_above = eighths_x / 8; + const int eighths_y = 6 * y_layer - 1; + const int y_above = eighths_y / 8; + const int r_x = (eighths_x % 8); + const int r_x_1 = 8 - r_x; + const int r_y = (eighths_y % 8); + const int r_y_1 = 8 - r_y; + uchar score = 0xFF + & ((r_x_1 * r_y_1 * l.getAgastScore(x_above, y_above, 1) + r_x * r_y_1 + * l.getAgastScore(x_above + 1, y_above, 1) + + r_x_1 * r_y * l.getAgastScore(x_above, y_above + 1, 1) + + r_x * r_y * l.getAgastScore(x_above + 1, y_above + 1, 1) + 32) + / 64); + return score; + } +} +inline int +BriskScaleSpace::getScoreBelow(const int layer, const int x_layer, const int y_layer) const +{ + CV_Assert(layer); + const BriskLayer& l = pyramid_[layer - 1]; + int sixth_x; + int quarter_x; + float xf; + int sixth_y; + int quarter_y; + float yf; + + // scaling: + float offs; + float area; + int scaling; + int scaling2; + + if (layer % 2 == 0) + { // octave + sixth_x = 8 * x_layer + 1; + xf = float(sixth_x) / 6.0f; + sixth_y = 8 * y_layer + 1; + yf = float(sixth_y) / 6.0f; + + // scaling: + offs = 2.0f / 3.0f; + area = 4.0f * offs * offs; + scaling = (int)(4194304.0 / area); + scaling2 = (int)(float(scaling) * area); + } + else + { + quarter_x = 6 * x_layer + 1; + xf = float(quarter_x) / 4.0f; + quarter_y = 6 * y_layer + 1; + yf = float(quarter_y) / 4.0f; + + // scaling: + offs = 3.0f / 4.0f; + area = 4.0f * offs * offs; + scaling = (int)(4194304.0 / area); + scaling2 = (int)(float(scaling) * area); + } + + // calculate borders + const float x_1 = xf - offs; + const float x1 = xf + offs; + const float y_1 = yf - offs; + const float y1 = yf + offs; + + const int x_left = int(x_1 + 0.5); + const int y_top = int(y_1 + 0.5); + const int x_right = int(x1 + 0.5); + const int y_bottom = int(y1 + 0.5); + + // overlap area - multiplication factors: + const float r_x_1 = float(x_left) - x_1 + 0.5f; + const float r_y_1 = float(y_top) - y_1 + 0.5f; + const float r_x1 = x1 - float(x_right) + 0.5f; + const float r_y1 = y1 - float(y_bottom) + 0.5f; + const int dx = x_right - x_left - 1; + const int dy = y_bottom - y_top - 1; + const int A = (int)((r_x_1 * r_y_1) * scaling); + const int B = (int)((r_x1 * r_y_1) * scaling); + const int C = (int)((r_x1 * r_y1) * scaling); + const int D = (int)((r_x_1 * r_y1) * scaling); + const int r_x_1_i = (int)(r_x_1 * scaling); + const int r_y_1_i = (int)(r_y_1 * scaling); + const int r_x1_i = (int)(r_x1 * scaling); + const int r_y1_i = (int)(r_y1 * scaling); + + // first row: + int ret_val = A * int(l.getAgastScore(x_left, y_top, 1)); + for (int X = 1; X <= dx; X++) + { + ret_val += r_y_1_i * int(l.getAgastScore(x_left + X, y_top, 1)); + } + ret_val += B * int(l.getAgastScore(x_left + dx + 1, y_top, 1)); + // middle ones: + for (int Y = 1; Y <= dy; Y++) + { + ret_val += r_x_1_i * int(l.getAgastScore(x_left, y_top + Y, 1)); + + for (int X = 1; X <= dx; X++) + { + ret_val += int(l.getAgastScore(x_left + X, y_top + Y, 1)) * scaling; + } + ret_val += r_x1_i * int(l.getAgastScore(x_left + dx + 1, y_top + Y, 1)); + } + // last row: + ret_val += D * int(l.getAgastScore(x_left, y_top + dy + 1, 1)); + for (int X = 1; X <= dx; X++) + { + ret_val += r_y1_i * int(l.getAgastScore(x_left + X, y_top + dy + 1, 1)); + } + ret_val += C * int(l.getAgastScore(x_left + dx + 1, y_top + dy + 1, 1)); + + return ((ret_val + scaling2 / 2) / scaling2); +} + +inline bool +BriskScaleSpace::isMax2D(const int layer, const int x_layer, const int y_layer) +{ + const cv::Mat& scores = pyramid_[layer].scores(); + const int scorescols = scores.cols; + const uchar* data = scores.ptr() + y_layer * scorescols + x_layer; + // decision tree: + const uchar center = (*data); + data--; + const uchar s_10 = *data; + if (center < s_10) + return false; + data += 2; + const uchar s10 = *data; + if (center < s10) + return false; + data -= (scorescols + 1); + const uchar s0_1 = *data; + if (center < s0_1) + return false; + data += 2 * scorescols; + const uchar s01 = *data; + if (center < s01) + return false; + data--; + const uchar s_11 = *data; + if (center < s_11) + return false; + data += 2; + const uchar s11 = *data; + if (center < s11) + return false; + data -= 2 * scorescols; + const uchar s1_1 = *data; + if (center < s1_1) + return false; + data -= 2; + const uchar s_1_1 = *data; + if (center < s_1_1) + return false; + + // reject neighbor maxima + std::vector delta; + // put together a list of 2d-offsets to where the maximum is also reached + if (center == s_1_1) + { + delta.push_back(-1); + delta.push_back(-1); + } + if (center == s0_1) + { + delta.push_back(0); + delta.push_back(-1); + } + if (center == s1_1) + { + delta.push_back(1); + delta.push_back(-1); + } + if (center == s_10) + { + delta.push_back(-1); + delta.push_back(0); + } + if (center == s10) + { + delta.push_back(1); + delta.push_back(0); + } + if (center == s_11) + { + delta.push_back(-1); + delta.push_back(1); + } + if (center == s01) + { + delta.push_back(0); + delta.push_back(1); + } + if (center == s11) + { + delta.push_back(1); + delta.push_back(1); + } + const unsigned int deltasize = (unsigned int)delta.size(); + if (deltasize != 0) + { + // in this case, we have to analyze the situation more carefully: + // the values are gaussian blurred and then we really decide + int smoothedcenter = 4 * center + 2 * (s_10 + s10 + s0_1 + s01) + s_1_1 + s1_1 + s_11 + s11; + for (unsigned int i = 0; i < deltasize; i += 2) + { + data = scores.ptr() + (y_layer - 1 + delta[i + 1]) * scorescols + x_layer + delta[i] - 1; + int othercenter = *data; + data++; + othercenter += 2 * (*data); + data++; + othercenter += *data; + data += scorescols; + othercenter += 2 * (*data); + data--; + othercenter += 4 * (*data); + data--; + othercenter += 2 * (*data); + data += scorescols; + othercenter += *data; + data++; + othercenter += 2 * (*data); + data++; + othercenter += *data; + if (othercenter > smoothedcenter) + return false; + } + } + return true; +} + +// 3D maximum refinement centered around (x_layer,y_layer) +inline float +BriskScaleSpace::refine3D(const int layer, const int x_layer, const int y_layer, float& x, float& y, float& scale, + bool& ismax) const +{ + ismax = true; + const BriskLayer& thisLayer = pyramid_[layer]; + const int center = thisLayer.getAgastScore(x_layer, y_layer, 1); + + // check and get above maximum: + float delta_x_above = 0, delta_y_above = 0; + float max_above = getScoreMaxAbove(layer, x_layer, y_layer, center, ismax, delta_x_above, delta_y_above); + + if (!ismax) + return 0.0f; + + float max; // to be returned + + if (layer % 2 == 0) + { // on octave + // treat the patch below: + float delta_x_below, delta_y_below; + float max_below_float; + int max_below = 0; + if (layer == 0) + { + // guess the lower intra octave... + const BriskLayer& l = pyramid_[0]; + int s_0_0 = l.getAgastScore_5_8(x_layer - 1, y_layer - 1, 1); + max_below = s_0_0; + int s_1_0 = l.getAgastScore_5_8(x_layer, y_layer - 1, 1); + max_below = std::max(s_1_0, max_below); + int s_2_0 = l.getAgastScore_5_8(x_layer + 1, y_layer - 1, 1); + max_below = std::max(s_2_0, max_below); + int s_2_1 = l.getAgastScore_5_8(x_layer + 1, y_layer, 1); + max_below = std::max(s_2_1, max_below); + int s_1_1 = l.getAgastScore_5_8(x_layer, y_layer, 1); + max_below = std::max(s_1_1, max_below); + int s_0_1 = l.getAgastScore_5_8(x_layer - 1, y_layer, 1); + max_below = std::max(s_0_1, max_below); + int s_0_2 = l.getAgastScore_5_8(x_layer - 1, y_layer + 1, 1); + max_below = std::max(s_0_2, max_below); + int s_1_2 = l.getAgastScore_5_8(x_layer, y_layer + 1, 1); + max_below = std::max(s_1_2, max_below); + int s_2_2 = l.getAgastScore_5_8(x_layer + 1, y_layer + 1, 1); + max_below = std::max(s_2_2, max_below); + + subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_below, delta_y_below); + max_below_float = (float)max_below; + } + else + { + max_below_float = getScoreMaxBelow(layer, x_layer, y_layer, center, ismax, delta_x_below, delta_y_below); + if (!ismax) + return 0; + } + + // get the patch on this layer: + int s_0_0 = thisLayer.getAgastScore(x_layer - 1, y_layer - 1, 1); + int s_1_0 = thisLayer.getAgastScore(x_layer, y_layer - 1, 1); + int s_2_0 = thisLayer.getAgastScore(x_layer + 1, y_layer - 1, 1); + int s_2_1 = thisLayer.getAgastScore(x_layer + 1, y_layer, 1); + int s_1_1 = thisLayer.getAgastScore(x_layer, y_layer, 1); + int s_0_1 = thisLayer.getAgastScore(x_layer - 1, y_layer, 1); + int s_0_2 = thisLayer.getAgastScore(x_layer - 1, y_layer + 1, 1); + int s_1_2 = thisLayer.getAgastScore(x_layer, y_layer + 1, 1); + int s_2_2 = thisLayer.getAgastScore(x_layer + 1, y_layer + 1, 1); + float delta_x_layer, delta_y_layer; + float max_layer = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_layer, + delta_y_layer); + + // calculate the relative scale (1D maximum): + if (layer == 0) + { + scale = refine1D_2(max_below_float, std::max(float(center), max_layer), max_above, max); + } + else + scale = refine1D(max_below_float, std::max(float(center), max_layer), max_above, max); + + if (scale > 1.0) + { + // interpolate the position: + const float r0 = (1.5f - scale) / .5f; + const float r1 = 1.0f - r0; + x = (r0 * delta_x_layer + r1 * delta_x_above + float(x_layer)) * thisLayer.scale() + thisLayer.offset(); + y = (r0 * delta_y_layer + r1 * delta_y_above + float(y_layer)) * thisLayer.scale() + thisLayer.offset(); + } + else + { + if (layer == 0) + { + // interpolate the position: + const float r0 = (scale - 0.5f) / 0.5f; + const float r_1 = 1.0f - r0; + x = r0 * delta_x_layer + r_1 * delta_x_below + float(x_layer); + y = r0 * delta_y_layer + r_1 * delta_y_below + float(y_layer); + } + else + { + // interpolate the position: + const float r0 = (scale - 0.75f) / 0.25f; + const float r_1 = 1.0f - r0; + x = (r0 * delta_x_layer + r_1 * delta_x_below + float(x_layer)) * thisLayer.scale() + thisLayer.offset(); + y = (r0 * delta_y_layer + r_1 * delta_y_below + float(y_layer)) * thisLayer.scale() + thisLayer.offset(); + } + } + } + else + { + // on intra + // check the patch below: + float delta_x_below, delta_y_below; + float max_below = getScoreMaxBelow(layer, x_layer, y_layer, center, ismax, delta_x_below, delta_y_below); + if (!ismax) + return 0.0f; + + // get the patch on this layer: + int s_0_0 = thisLayer.getAgastScore(x_layer - 1, y_layer - 1, 1); + int s_1_0 = thisLayer.getAgastScore(x_layer, y_layer - 1, 1); + int s_2_0 = thisLayer.getAgastScore(x_layer + 1, y_layer - 1, 1); + int s_2_1 = thisLayer.getAgastScore(x_layer + 1, y_layer, 1); + int s_1_1 = thisLayer.getAgastScore(x_layer, y_layer, 1); + int s_0_1 = thisLayer.getAgastScore(x_layer - 1, y_layer, 1); + int s_0_2 = thisLayer.getAgastScore(x_layer - 1, y_layer + 1, 1); + int s_1_2 = thisLayer.getAgastScore(x_layer, y_layer + 1, 1); + int s_2_2 = thisLayer.getAgastScore(x_layer + 1, y_layer + 1, 1); + float delta_x_layer, delta_y_layer; + float max_layer = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_layer, + delta_y_layer); + + // calculate the relative scale (1D maximum): + scale = refine1D_1(max_below, std::max(float(center), max_layer), max_above, max); + if (scale > 1.0) + { + // interpolate the position: + const float r0 = 4.0f - scale * 3.0f; + const float r1 = 1.0f - r0; + x = (r0 * delta_x_layer + r1 * delta_x_above + float(x_layer)) * thisLayer.scale() + thisLayer.offset(); + y = (r0 * delta_y_layer + r1 * delta_y_above + float(y_layer)) * thisLayer.scale() + thisLayer.offset(); + } + else + { + // interpolate the position: + const float r0 = scale * 3.0f - 2.0f; + const float r_1 = 1.0f - r0; + x = (r0 * delta_x_layer + r_1 * delta_x_below + float(x_layer)) * thisLayer.scale() + thisLayer.offset(); + y = (r0 * delta_y_layer + r_1 * delta_y_below + float(y_layer)) * thisLayer.scale() + thisLayer.offset(); + } + } + + // calculate the absolute scale: + scale *= thisLayer.scale(); + + // that's it, return the refined maximum: + return max; +} + +// return the maximum of score patches above or below +inline float +BriskScaleSpace::getScoreMaxAbove(const int layer, const int x_layer, const int y_layer, const int threshold, + bool& ismax, float& dx, float& dy) const +{ + + ismax = false; + // relevant floating point coordinates + float x_1; + float x1; + float y_1; + float y1; + + // the layer above + CV_Assert(layer + 1 < layers_); + const BriskLayer& layerAbove = pyramid_[layer + 1]; + + if (layer % 2 == 0) + { + // octave + x_1 = float(4 * (x_layer) - 1 - 2) / 6.0f; + x1 = float(4 * (x_layer) - 1 + 2) / 6.0f; + y_1 = float(4 * (y_layer) - 1 - 2) / 6.0f; + y1 = float(4 * (y_layer) - 1 + 2) / 6.0f; + } + else + { + // intra + x_1 = float(6 * (x_layer) - 1 - 3) / 8.0f; + x1 = float(6 * (x_layer) - 1 + 3) / 8.0f; + y_1 = float(6 * (y_layer) - 1 - 3) / 8.0f; + y1 = float(6 * (y_layer) - 1 + 3) / 8.0f; + } + + // check the first row + int max_x = (int)x_1 + 1; + int max_y = (int)y_1 + 1; + float tmp_max; + float maxval = (float)layerAbove.getAgastScore(x_1, y_1, 1); + if (maxval > threshold) + return 0; + for (int x = (int)x_1 + 1; x <= int(x1); x++) + { + tmp_max = (float)layerAbove.getAgastScore(float(x), y_1, 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = x; + } + } + tmp_max = (float)layerAbove.getAgastScore(x1, y_1, 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = int(x1); + } + + // middle rows + for (int y = (int)y_1 + 1; y <= int(y1); y++) + { + tmp_max = (float)layerAbove.getAgastScore(x_1, float(y), 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = int(x_1 + 1); + max_y = y; + } + for (int x = (int)x_1 + 1; x <= int(x1); x++) + { + tmp_max = (float)layerAbove.getAgastScore(x, y, 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = x; + max_y = y; + } + } + tmp_max = (float)layerAbove.getAgastScore(x1, float(y), 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = int(x1); + max_y = y; + } + } + + // bottom row + tmp_max = (float)layerAbove.getAgastScore(x_1, y1, 1); + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = int(x_1 + 1); + max_y = int(y1); + } + for (int x = (int)x_1 + 1; x <= int(x1); x++) + { + tmp_max = (float)layerAbove.getAgastScore(float(x), y1, 1); + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = x; + max_y = int(y1); + } + } + tmp_max = (float)layerAbove.getAgastScore(x1, y1, 1); + if (tmp_max > maxval) + { + maxval = tmp_max; + max_x = int(x1); + max_y = int(y1); + } + + //find dx/dy: + int s_0_0 = layerAbove.getAgastScore(max_x - 1, max_y - 1, 1); + int s_1_0 = layerAbove.getAgastScore(max_x, max_y - 1, 1); + int s_2_0 = layerAbove.getAgastScore(max_x + 1, max_y - 1, 1); + int s_2_1 = layerAbove.getAgastScore(max_x + 1, max_y, 1); + int s_1_1 = layerAbove.getAgastScore(max_x, max_y, 1); + int s_0_1 = layerAbove.getAgastScore(max_x - 1, max_y, 1); + int s_0_2 = layerAbove.getAgastScore(max_x - 1, max_y + 1, 1); + int s_1_2 = layerAbove.getAgastScore(max_x, max_y + 1, 1); + int s_2_2 = layerAbove.getAgastScore(max_x + 1, max_y + 1, 1); + float dx_1, dy_1; + float refined_max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, dx_1, dy_1); + + // calculate dx/dy in above coordinates + float real_x = float(max_x) + dx_1; + float real_y = float(max_y) + dy_1; + bool returnrefined = true; + if (layer % 2 == 0) + { + dx = (real_x * 6.0f + 1.0f) / 4.0f - float(x_layer); + dy = (real_y * 6.0f + 1.0f) / 4.0f - float(y_layer); + } + else + { + dx = (real_x * 8.0f + 1.0f) / 6.0f - float(x_layer); + dy = (real_y * 8.0f + 1.0f) / 6.0f - float(y_layer); + } + + // saturate + if (dx > 1.0f) + { + dx = 1.0f; + returnrefined = false; + } + if (dx < -1.0f) + { + dx = -1.0f; + returnrefined = false; + } + if (dy > 1.0f) + { + dy = 1.0f; + returnrefined = false; + } + if (dy < -1.0f) + { + dy = -1.0f; + returnrefined = false; + } + + // done and ok. + ismax = true; + if (returnrefined) + { + return std::max(refined_max, maxval); + } + return maxval; +} + +inline float +BriskScaleSpace::getScoreMaxBelow(const int layer, const int x_layer, const int y_layer, const int threshold, + bool& ismax, float& dx, float& dy) const +{ + ismax = false; + + // relevant floating point coordinates + float x_1; + float x1; + float y_1; + float y1; + + if (layer % 2 == 0) + { + // octave + x_1 = float(8 * (x_layer) + 1 - 4) / 6.0f; + x1 = float(8 * (x_layer) + 1 + 4) / 6.0f; + y_1 = float(8 * (y_layer) + 1 - 4) / 6.0f; + y1 = float(8 * (y_layer) + 1 + 4) / 6.0f; + } + else + { + x_1 = float(6 * (x_layer) + 1 - 3) / 4.0f; + x1 = float(6 * (x_layer) + 1 + 3) / 4.0f; + y_1 = float(6 * (y_layer) + 1 - 3) / 4.0f; + y1 = float(6 * (y_layer) + 1 + 3) / 4.0f; + } + + // the layer below + CV_Assert(layer > 0); + const BriskLayer& layerBelow = pyramid_[layer - 1]; + + // check the first row + int max_x = (int)x_1 + 1; + int max_y = (int)y_1 + 1; + float tmp_max; + float max = (float)layerBelow.getAgastScore(x_1, y_1, 1); + if (max > threshold) + return 0; + for (int x = (int)x_1 + 1; x <= int(x1); x++) + { + tmp_max = (float)layerBelow.getAgastScore(float(x), y_1, 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > max) + { + max = tmp_max; + max_x = x; + } + } + tmp_max = (float)layerBelow.getAgastScore(x1, y_1, 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > max) + { + max = tmp_max; + max_x = int(x1); + } + + // middle rows + for (int y = (int)y_1 + 1; y <= int(y1); y++) + { + tmp_max = (float)layerBelow.getAgastScore(x_1, float(y), 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > max) + { + max = tmp_max; + max_x = int(x_1 + 1); + max_y = y; + } + for (int x = (int)x_1 + 1; x <= int(x1); x++) + { + tmp_max = (float)layerBelow.getAgastScore(x, y, 1); + if (tmp_max > threshold) + return 0; + if (tmp_max == max) + { + const int t1 = 2 + * (layerBelow.getAgastScore(x - 1, y, 1) + layerBelow.getAgastScore(x + 1, y, 1) + + layerBelow.getAgastScore(x, y + 1, 1) + layerBelow.getAgastScore(x, y - 1, 1)) + + (layerBelow.getAgastScore(x + 1, y + 1, 1) + layerBelow.getAgastScore(x - 1, y + 1, 1) + + layerBelow.getAgastScore(x + 1, y - 1, 1) + layerBelow.getAgastScore(x - 1, y - 1, 1)); + const int t2 = 2 + * (layerBelow.getAgastScore(max_x - 1, max_y, 1) + layerBelow.getAgastScore(max_x + 1, max_y, 1) + + layerBelow.getAgastScore(max_x, max_y + 1, 1) + layerBelow.getAgastScore(max_x, max_y - 1, 1)) + + (layerBelow.getAgastScore(max_x + 1, max_y + 1, 1) + layerBelow.getAgastScore(max_x - 1, + max_y + 1, 1) + + layerBelow.getAgastScore(max_x + 1, max_y - 1, 1) + + layerBelow.getAgastScore(max_x - 1, max_y - 1, 1)); + if (t1 > t2) + { + max_x = x; + max_y = y; + } + } + if (tmp_max > max) + { + max = tmp_max; + max_x = x; + max_y = y; + } + } + tmp_max = (float)layerBelow.getAgastScore(x1, float(y), 1); + if (tmp_max > threshold) + return 0; + if (tmp_max > max) + { + max = tmp_max; + max_x = int(x1); + max_y = y; + } + } + + // bottom row + tmp_max = (float)layerBelow.getAgastScore(x_1, y1, 1); + if (tmp_max > max) + { + max = tmp_max; + max_x = int(x_1 + 1); + max_y = int(y1); + } + for (int x = (int)x_1 + 1; x <= int(x1); x++) + { + tmp_max = (float)layerBelow.getAgastScore(float(x), y1, 1); + if (tmp_max > max) + { + max = tmp_max; + max_x = x; + max_y = int(y1); + } + } + tmp_max = (float)layerBelow.getAgastScore(x1, y1, 1); + if (tmp_max > max) + { + max = tmp_max; + max_x = int(x1); + max_y = int(y1); + } + + //find dx/dy: + int s_0_0 = layerBelow.getAgastScore(max_x - 1, max_y - 1, 1); + int s_1_0 = layerBelow.getAgastScore(max_x, max_y - 1, 1); + int s_2_0 = layerBelow.getAgastScore(max_x + 1, max_y - 1, 1); + int s_2_1 = layerBelow.getAgastScore(max_x + 1, max_y, 1); + int s_1_1 = layerBelow.getAgastScore(max_x, max_y, 1); + int s_0_1 = layerBelow.getAgastScore(max_x - 1, max_y, 1); + int s_0_2 = layerBelow.getAgastScore(max_x - 1, max_y + 1, 1); + int s_1_2 = layerBelow.getAgastScore(max_x, max_y + 1, 1); + int s_2_2 = layerBelow.getAgastScore(max_x + 1, max_y + 1, 1); + float dx_1, dy_1; + float refined_max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, dx_1, dy_1); + + // calculate dx/dy in above coordinates + float real_x = float(max_x) + dx_1; + float real_y = float(max_y) + dy_1; + bool returnrefined = true; + if (layer % 2 == 0) + { + dx = (float)((real_x * 6.0 + 1.0) / 8.0) - float(x_layer); + dy = (float)((real_y * 6.0 + 1.0) / 8.0) - float(y_layer); + } + else + { + dx = (float)((real_x * 4.0 - 1.0) / 6.0) - float(x_layer); + dy = (float)((real_y * 4.0 - 1.0) / 6.0) - float(y_layer); + } + + // saturate + if (dx > 1.0) + { + dx = 1.0f; + returnrefined = false; + } + if (dx < -1.0f) + { + dx = -1.0f; + returnrefined = false; + } + if (dy > 1.0f) + { + dy = 1.0f; + returnrefined = false; + } + if (dy < -1.0f) + { + dy = -1.0f; + returnrefined = false; + } + + // done and ok. + ismax = true; + if (returnrefined) + { + return std::max(refined_max, max); + } + return max; +} + +inline float +BriskScaleSpace::refine1D(const float s_05, const float s0, const float s05, float& max) const +{ + int i_05 = int(1024.0 * s_05 + 0.5); + int i0 = int(1024.0 * s0 + 0.5); + int i05 = int(1024.0 * s05 + 0.5); + + // 16.0000 -24.0000 8.0000 + // -40.0000 54.0000 -14.0000 + // 24.0000 -27.0000 6.0000 + + int three_a = 16 * i_05 - 24 * i0 + 8 * i05; + // second derivative must be negative: + if (three_a >= 0) + { + if (s0 >= s_05 && s0 >= s05) + { + max = s0; + return 1.0f; + } + if (s_05 >= s0 && s_05 >= s05) + { + max = s_05; + return 0.75f; + } + if (s05 >= s0 && s05 >= s_05) + { + max = s05; + return 1.5f; + } + } + + int three_b = -40 * i_05 + 54 * i0 - 14 * i05; + // calculate max location: + float ret_val = -float(three_b) / float(2 * three_a); + // saturate and return + if (ret_val < 0.75) + ret_val = 0.75; + else if (ret_val > 1.5) + ret_val = 1.5; // allow to be slightly off bounds ...? + int three_c = +24 * i_05 - 27 * i0 + 6 * i05; + max = float(three_c) + float(three_a) * ret_val * ret_val + float(three_b) * ret_val; + max /= 3072.0f; + return ret_val; +} + +inline float +BriskScaleSpace::refine1D_1(const float s_05, const float s0, const float s05, float& max) const +{ + int i_05 = int(1024.0 * s_05 + 0.5); + int i0 = int(1024.0 * s0 + 0.5); + int i05 = int(1024.0 * s05 + 0.5); + + // 4.5000 -9.0000 4.5000 + //-10.5000 18.0000 -7.5000 + // 6.0000 -8.0000 3.0000 + + int two_a = 9 * i_05 - 18 * i0 + 9 * i05; + // second derivative must be negative: + if (two_a >= 0) + { + if (s0 >= s_05 && s0 >= s05) + { + max = s0; + return 1.0f; + } + if (s_05 >= s0 && s_05 >= s05) + { + max = s_05; + return 0.6666666666666666666666666667f; + } + if (s05 >= s0 && s05 >= s_05) + { + max = s05; + return 1.3333333333333333333333333333f; + } + } + + int two_b = -21 * i_05 + 36 * i0 - 15 * i05; + // calculate max location: + float ret_val = -float(two_b) / float(2 * two_a); + // saturate and return + if (ret_val < 0.6666666666666666666666666667f) + ret_val = 0.666666666666666666666666667f; + else if (ret_val > 1.33333333333333333333333333f) + ret_val = 1.333333333333333333333333333f; + int two_c = +12 * i_05 - 16 * i0 + 6 * i05; + max = float(two_c) + float(two_a) * ret_val * ret_val + float(two_b) * ret_val; + max /= 2048.0f; + return ret_val; +} + +inline float +BriskScaleSpace::refine1D_2(const float s_05, const float s0, const float s05, float& max) const +{ + int i_05 = int(1024.0 * s_05 + 0.5); + int i0 = int(1024.0 * s0 + 0.5); + int i05 = int(1024.0 * s05 + 0.5); + + // 18.0000 -30.0000 12.0000 + // -45.0000 65.0000 -20.0000 + // 27.0000 -30.0000 8.0000 + + int a = 2 * i_05 - 4 * i0 + 2 * i05; + // second derivative must be negative: + if (a >= 0) + { + if (s0 >= s_05 && s0 >= s05) + { + max = s0; + return 1.0f; + } + if (s_05 >= s0 && s_05 >= s05) + { + max = s_05; + return 0.7f; + } + if (s05 >= s0 && s05 >= s_05) + { + max = s05; + return 1.5f; + } + } + + int b = -5 * i_05 + 8 * i0 - 3 * i05; + // calculate max location: + float ret_val = -float(b) / float(2 * a); + // saturate and return + if (ret_val < 0.7f) + ret_val = 0.7f; + else if (ret_val > 1.5f) + ret_val = 1.5f; // allow to be slightly off bounds ...? + int c = +3 * i_05 - 3 * i0 + 1 * i05; + max = float(c) + float(a) * ret_val * ret_val + float(b) * ret_val; + max /= 1024; + return ret_val; +} + +inline float +BriskScaleSpace::subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, const int s_1_0, const int s_1_1, + const int s_1_2, const int s_2_0, const int s_2_1, const int s_2_2, float& delta_x, + float& delta_y) const +{ + + // the coefficients of the 2d quadratic function least-squares fit: + int tmp1 = s_0_0 + s_0_2 - 2 * s_1_1 + s_2_0 + s_2_2; + int coeff1 = 3 * (tmp1 + s_0_1 - ((s_1_0 + s_1_2) << 1) + s_2_1); + int coeff2 = 3 * (tmp1 - ((s_0_1 + s_2_1) << 1) + s_1_0 + s_1_2); + int tmp2 = s_0_2 - s_2_0; + int tmp3 = (s_0_0 + tmp2 - s_2_2); + int tmp4 = tmp3 - 2 * tmp2; + int coeff3 = -3 * (tmp3 + s_0_1 - s_2_1); + int coeff4 = -3 * (tmp4 + s_1_0 - s_1_2); + int coeff5 = (s_0_0 - s_0_2 - s_2_0 + s_2_2) << 2; + int coeff6 = -(s_0_0 + s_0_2 - ((s_1_0 + s_0_1 + s_1_2 + s_2_1) << 1) - 5 * s_1_1 + s_2_0 + s_2_2) << 1; + + // 2nd derivative test: + int H_det = 4 * coeff1 * coeff2 - coeff5 * coeff5; + + if (H_det == 0) + { + delta_x = 0.0f; + delta_y = 0.0f; + return float(coeff6) / 18.0f; + } + + if (!(H_det > 0 && coeff1 < 0)) + { + // The maximum must be at the one of the 4 patch corners. + int tmp_max = coeff3 + coeff4 + coeff5; + delta_x = 1.0f; + delta_y = 1.0f; + + int tmp = -coeff3 + coeff4 - coeff5; + if (tmp > tmp_max) + { + tmp_max = tmp; + delta_x = -1.0f; + delta_y = 1.0f; + } + tmp = coeff3 - coeff4 - coeff5; + if (tmp > tmp_max) + { + tmp_max = tmp; + delta_x = 1.0f; + delta_y = -1.0f; + } + tmp = -coeff3 - coeff4 + coeff5; + if (tmp > tmp_max) + { + tmp_max = tmp; + delta_x = -1.0f; + delta_y = -1.0f; + } + return float(tmp_max + coeff1 + coeff2 + coeff6) / 18.0f; + } + + // this is hopefully the normal outcome of the Hessian test + delta_x = float(2 * coeff2 * coeff3 - coeff4 * coeff5) / float(-H_det); + delta_y = float(2 * coeff1 * coeff4 - coeff3 * coeff5) / float(-H_det); + // TODO: this is not correct, but easy, so perform a real boundary maximum search: + bool tx = false; + bool tx_ = false; + bool ty = false; + bool ty_ = false; + if (delta_x > 1.0) + tx = true; + else if (delta_x < -1.0) + tx_ = true; + if (delta_y > 1.0) + ty = true; + if (delta_y < -1.0) + ty_ = true; + + if (tx || tx_ || ty || ty_) + { + // get two candidates: + float delta_x1 = 0.0f, delta_x2 = 0.0f, delta_y1 = 0.0f, delta_y2 = 0.0f; + if (tx) + { + delta_x1 = 1.0f; + delta_y1 = -float(coeff4 + coeff5) / float(2 * coeff2); + if (delta_y1 > 1.0f) + delta_y1 = 1.0f; + else if (delta_y1 < -1.0f) + delta_y1 = -1.0f; + } + else if (tx_) + { + delta_x1 = -1.0f; + delta_y1 = -float(coeff4 - coeff5) / float(2 * coeff2); + if (delta_y1 > 1.0f) + delta_y1 = 1.0f; + else if (delta_y1 < -1.0) + delta_y1 = -1.0f; + } + if (ty) + { + delta_y2 = 1.0f; + delta_x2 = -float(coeff3 + coeff5) / float(2 * coeff1); + if (delta_x2 > 1.0f) + delta_x2 = 1.0f; + else if (delta_x2 < -1.0f) + delta_x2 = -1.0f; + } + else if (ty_) + { + delta_y2 = -1.0f; + delta_x2 = -float(coeff3 - coeff5) / float(2 * coeff1); + if (delta_x2 > 1.0f) + delta_x2 = 1.0f; + else if (delta_x2 < -1.0f) + delta_x2 = -1.0f; + } + // insert both options for evaluation which to pick + float max1 = (coeff1 * delta_x1 * delta_x1 + coeff2 * delta_y1 * delta_y1 + coeff3 * delta_x1 + coeff4 * delta_y1 + + coeff5 * delta_x1 * delta_y1 + coeff6) + / 18.0f; + float max2 = (coeff1 * delta_x2 * delta_x2 + coeff2 * delta_y2 * delta_y2 + coeff3 * delta_x2 + coeff4 * delta_y2 + + coeff5 * delta_x2 * delta_y2 + coeff6) + / 18.0f; + if (max1 > max2) + { + delta_x = delta_x1; + delta_y = delta_y1; + return max1; + } + else + { + delta_x = delta_x2; + delta_y = delta_y2; + return max2; + } + } + + // this is the case of the maximum inside the boundaries: + return (coeff1 * delta_x * delta_x + coeff2 * delta_y * delta_y + coeff3 * delta_x + coeff4 * delta_y + + coeff5 * delta_x * delta_y + coeff6) + / 18.0f; +} + +// construct a layer +BriskLayer::BriskLayer(const cv::Mat& img_in, float scale_in, float offset_in) +{ + img_ = img_in; + scores_ = cv::Mat_::zeros(img_in.rows, img_in.cols); + // attention: this means that the passed image reference must point to persistent memory + scale_ = scale_in; + offset_ = offset_in; + // create an agast detector + oast_9_16_ = AgastFeatureDetector::create(1, false, AgastFeatureDetector::OAST_9_16); + makeAgastOffsets(pixel_5_8_, (int)img_.step, AgastFeatureDetector::AGAST_5_8); + makeAgastOffsets(pixel_9_16_, (int)img_.step, AgastFeatureDetector::OAST_9_16); +} +// derive a layer +BriskLayer::BriskLayer(const BriskLayer& layer, int mode) +{ + if (mode == CommonParams::HALFSAMPLE) + { + img_.create(layer.img().rows / 2, layer.img().cols / 2, CV_8U); + halfsample(layer.img(), img_); + scale_ = layer.scale() * 2; + offset_ = 0.5f * scale_ - 0.5f; + } + else + { + img_.create(2 * (layer.img().rows / 3), 2 * (layer.img().cols / 3), CV_8U); + twothirdsample(layer.img(), img_); + scale_ = layer.scale() * 1.5f; + offset_ = 0.5f * scale_ - 0.5f; + } + scores_ = cv::Mat::zeros(img_.rows, img_.cols, CV_8U); + oast_9_16_ = AgastFeatureDetector::create(1, false, AgastFeatureDetector::OAST_9_16); + makeAgastOffsets(pixel_5_8_, (int)img_.step, AgastFeatureDetector::AGAST_5_8); + makeAgastOffsets(pixel_9_16_, (int)img_.step, AgastFeatureDetector::OAST_9_16); +} + +// Agast +// wraps the agast class +void +BriskLayer::getAgastPoints(int threshold, std::vector& keypoints) +{ + oast_9_16_->setThreshold(threshold); + oast_9_16_->detect(img_, keypoints); + + // also write scores + const size_t num = keypoints.size(); + + for (size_t i = 0; i < num; i++) + scores_((int)keypoints[i].pt.y, (int)keypoints[i].pt.x) = saturate_cast(keypoints[i].response); +} + +inline int +BriskLayer::getAgastScore(int x, int y, int threshold) const +{ + if (x < 3 || y < 3) + return 0; + if (x >= img_.cols - 3 || y >= img_.rows - 3) + return 0; + uchar& score = (uchar&)scores_(y, x); + if (score > 2) + { + return score; + } + score = (uchar)agast_cornerScore(&img_.at(y, x), pixel_9_16_, threshold - 1); + if (score < threshold) + score = 0; + return score; +} + +inline int +BriskLayer::getAgastScore_5_8(int x, int y, int threshold) const +{ + if (x < 2 || y < 2) + return 0; + if (x >= img_.cols - 2 || y >= img_.rows - 2) + return 0; + int score = agast_cornerScore(&img_.at(y, x), pixel_5_8_, threshold - 1); + if (score < threshold) + score = 0; + return score; +} + +inline int +BriskLayer::getAgastScore(float xf, float yf, int threshold_in, float scale_in) const +{ + if (scale_in <= 1.0f) + { + // just do an interpolation inside the layer + const int x = int(xf); + const float rx1 = xf - float(x); + const float rx = 1.0f - rx1; + const int y = int(yf); + const float ry1 = yf - float(y); + const float ry = 1.0f - ry1; + + return (uchar)(rx * ry * getAgastScore(x, y, threshold_in) + rx1 * ry * getAgastScore(x + 1, y, threshold_in) + + rx * ry1 * getAgastScore(x, y + 1, threshold_in) + rx1 * ry1 * getAgastScore(x + 1, y + 1, threshold_in)); + } + else + { + // this means we overlap area smoothing + const float halfscale = scale_in / 2.0f; + // get the scores first: + for (int x = int(xf - halfscale); x <= int(xf + halfscale + 1.0f); x++) + { + for (int y = int(yf - halfscale); y <= int(yf + halfscale + 1.0f); y++) + { + getAgastScore(x, y, threshold_in); + } + } + // get the smoothed value + return value(scores_, xf, yf, scale_in); + } +} + +// access gray values (smoothed/interpolated) +inline int +BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const +{ + CV_Assert(!mat.empty()); + // get the position + const int x = cvFloor(xf); + const int y = cvFloor(yf); + const cv::Mat& image = mat; + const int& imagecols = image.cols; + + // get the sigma_half: + const float sigma_half = scale_in / 2; + const float area = 4.0f * sigma_half * sigma_half; + // calculate output: + int ret_val; + if (sigma_half < 0.5) + { + //interpolation multipliers: + const int r_x = (int)((xf - x) * 1024); + const int r_y = (int)((yf - y) * 1024); + const int r_x_1 = (1024 - r_x); + const int r_y_1 = (1024 - r_y); + const uchar* ptr = image.ptr() + x + y * imagecols; + // just interpolate: + ret_val = (r_x_1 * r_y_1 * int(*ptr)); + ptr++; + ret_val += (r_x * r_y_1 * int(*ptr)); + ptr += imagecols; + ret_val += (r_x * r_y * int(*ptr)); + ptr--; + ret_val += (r_x_1 * r_y * int(*ptr)); + return 0xFF & ((ret_val + 512) / 1024 / 1024); + } + + // this is the standard case (simple, not speed optimized yet): + + // scaling: + const int scaling = (int)(4194304.0f / area); + const int scaling2 = (int)(float(scaling) * area / 1024.0f); + CV_Assert(scaling2 != 0); + + // calculate borders + const float x_1 = xf - sigma_half; + const float x1 = xf + sigma_half; + const float y_1 = yf - sigma_half; + const float y1 = yf + sigma_half; + + const int x_left = int(x_1 + 0.5); + const int y_top = int(y_1 + 0.5); + const int x_right = int(x1 + 0.5); + const int y_bottom = int(y1 + 0.5); + + // overlap area - multiplication factors: + const float r_x_1 = float(x_left) - x_1 + 0.5f; + const float r_y_1 = float(y_top) - y_1 + 0.5f; + const float r_x1 = x1 - float(x_right) + 0.5f; + const float r_y1 = y1 - float(y_bottom) + 0.5f; + const int dx = x_right - x_left - 1; + const int dy = y_bottom - y_top - 1; + const int A = (int)((r_x_1 * r_y_1) * scaling); + const int B = (int)((r_x1 * r_y_1) * scaling); + const int C = (int)((r_x1 * r_y1) * scaling); + const int D = (int)((r_x_1 * r_y1) * scaling); + const int r_x_1_i = (int)(r_x_1 * scaling); + const int r_y_1_i = (int)(r_y_1 * scaling); + const int r_x1_i = (int)(r_x1 * scaling); + const int r_y1_i = (int)(r_y1 * scaling); + + // now the calculation: + const uchar* ptr = image.ptr() + x_left + imagecols * y_top; + // first row: + ret_val = A * int(*ptr); + ptr++; + const uchar* end1 = ptr + dx; + for (; ptr < end1; ptr++) + { + ret_val += r_y_1_i * int(*ptr); + } + ret_val += B * int(*ptr); + // middle ones: + ptr += imagecols - dx - 1; + const uchar* end_j = ptr + dy * imagecols; + for (; ptr < end_j; ptr += imagecols - dx - 1) + { + ret_val += r_x_1_i * int(*ptr); + ptr++; + const uchar* end2 = ptr + dx; + for (; ptr < end2; ptr++) + { + ret_val += int(*ptr) * scaling; + } + ret_val += r_x1_i * int(*ptr); + } + // last row: + ret_val += D * int(*ptr); + ptr++; + const uchar* end3 = ptr + dx; + for (; ptr < end3; ptr++) + { + ret_val += r_y1_i * int(*ptr); + } + ret_val += C * int(*ptr); + + return 0xFF & ((ret_val + scaling2 / 2) / scaling2 / 1024); +} + +// half sampling +inline void +BriskLayer::halfsample(const cv::Mat& srcimg, cv::Mat& dstimg) +{ + // make sure the destination image is of the right size: + CV_Assert(srcimg.cols / 2 == dstimg.cols); + CV_Assert(srcimg.rows / 2 == dstimg.rows); + + // handle non-SSE case + resize(srcimg, dstimg, dstimg.size(), 0, 0, INTER_AREA); +} + +inline void +BriskLayer::twothirdsample(const cv::Mat& srcimg, cv::Mat& dstimg) +{ + // make sure the destination image is of the right size: + CV_Assert((srcimg.cols / 3) * 2 == dstimg.cols); + CV_Assert((srcimg.rows / 3) * 2 == dstimg.rows); + + resize(srcimg, dstimg, dstimg.size(), 0, 0, INTER_AREA); +} + +Ptr BRISK::create(int thresh, int octaves, float patternScale) +{ + return makePtr(thresh, octaves, patternScale); +} + +// custom setup +Ptr BRISK::create(const std::vector &radiusList, const std::vector &numberList, + float dMax, float dMin, const std::vector& indexChange) +{ + return makePtr(radiusList, numberList, dMax, dMin, indexChange); +} + +Ptr BRISK::create(int thresh, int octaves, const std::vector &radiusList, + const std::vector &numberList, float dMax, float dMin, + const std::vector& indexChange) +{ + return makePtr(thresh, octaves, radiusList, numberList, dMax, dMin, indexChange); +} + +String BRISK::getDefaultName() const +{ + return (Feature2D::getDefaultName() + ".BRISK"); +} + +} +} // namespace cv \ No newline at end of file diff --git a/modules/xfeatures2d/src/kaze.cpp b/modules/xfeatures2d/src/kaze.cpp new file mode 100644 index 00000000000..578a881ea03 --- /dev/null +++ b/modules/xfeatures2d/src/kaze.cpp @@ -0,0 +1,216 @@ +/*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) 2008, 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 Intel Corporation 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*/ + +/* +OpenCV wrapper of reference implementation of +[1] KAZE Features. Pablo F. Alcantarilla, Adrien Bartoli and Andrew J. Davison. +In European Conference on Computer Vision (ECCV), Fiorenze, Italy, October 2012 +http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla12eccv.pdf +@author Eugene Khvedchenya +*/ + +#include "precomp.hpp" +#include "kaze/KAZEFeatures.h" + +namespace cv +{ +namespace xfeatures2d +{ + + class KAZE_Impl CV_FINAL : public KAZE + { + public: + KAZE_Impl(bool _extended, bool _upright, float _threshold, int _octaves, + int _sublevels, KAZE::DiffusivityType _diffusivity) + : extended(_extended) + , upright(_upright) + , threshold(_threshold) + , octaves(_octaves) + , sublevels(_sublevels) + , diffusivity(_diffusivity) + { + } + + virtual ~KAZE_Impl() CV_OVERRIDE {} + + void setExtended(bool extended_) CV_OVERRIDE { extended = extended_; } + bool getExtended() const CV_OVERRIDE { return extended; } + + void setUpright(bool upright_) CV_OVERRIDE { upright = upright_; } + bool getUpright() const CV_OVERRIDE { return upright; } + + void setThreshold(double threshold_) CV_OVERRIDE { threshold = (float)threshold_; } + double getThreshold() const CV_OVERRIDE { return threshold; } + + void setNOctaves(int octaves_) CV_OVERRIDE { octaves = octaves_; } + int getNOctaves() const CV_OVERRIDE { return octaves; } + + void setNOctaveLayers(int octaveLayers_) CV_OVERRIDE { sublevels = octaveLayers_; } + int getNOctaveLayers() const CV_OVERRIDE { return sublevels; } + + void setDiffusivity(int diff_) CV_OVERRIDE{ diffusivity = diff_; } + int getDiffusivity() const CV_OVERRIDE{ return diffusivity; } + + // returns the descriptor size in bytes + int descriptorSize() const CV_OVERRIDE + { + return extended ? 128 : 64; + } + + // returns the descriptor type + int descriptorType() const CV_OVERRIDE + { + return CV_32F; + } + + // returns the default norm type + int defaultNorm() const CV_OVERRIDE + { + return NORM_L2; + } + + void detectAndCompute(InputArray image, InputArray mask, + std::vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints) CV_OVERRIDE + { + CV_INSTRUMENT_REGION(); + + cv::Mat img = image.getMat(); + if (img.channels() > 1) + cvtColor(image, img, COLOR_BGR2GRAY); + + Mat img1_32; + if ( img.depth() == CV_32F ) + img1_32 = img; + else if ( img.depth() == CV_8U ) + img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); + else if ( img.depth() == CV_16U ) + img.convertTo(img1_32, CV_32F, 1.0 / 65535.0, 0); + + CV_Assert( ! img1_32.empty() ); + + KAZEOptions options; + options.img_width = img.cols; + options.img_height = img.rows; + options.extended = extended; + options.upright = upright; + options.dthreshold = threshold; + options.omax = octaves; + options.nsublevels = sublevels; + options.diffusivity = diffusivity; + + KAZEFeatures impl(options); + impl.Create_Nonlinear_Scale_Space(img1_32); + + if (!useProvidedKeypoints) + { + impl.Feature_Detection(keypoints); + } + + if (!mask.empty()) + { + cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat()); + } + + if( descriptors.needed() ) + { + Mat desc; + impl.Feature_Description(keypoints, desc); + desc.copyTo(descriptors); + + CV_Assert((!desc.rows || desc.cols == descriptorSize())); + CV_Assert((!desc.rows || (desc.type() == descriptorType()))); + } + } + + void write(FileStorage& fs) const CV_OVERRIDE + { + writeFormat(fs); + fs << "name" << getDefaultName(); + fs << "extended" << (int)extended; + fs << "upright" << (int)upright; + fs << "threshold" << threshold; + fs << "octaves" << octaves; + fs << "sublevels" << sublevels; + fs << "diffusivity" << diffusivity; + } + + void read(const FileNode& fn) CV_OVERRIDE + { + // if node is empty, keep previous value + if (!fn["extended"].empty()) + extended = (int)fn["extended"] != 0; + if (!fn["upright"].empty()) + upright = (int)fn["upright"] != 0; + if (!fn["threshold"].empty()) + threshold = (float)fn["threshold"]; + if (!fn["octaves"].empty()) + octaves = (int)fn["octaves"]; + if (!fn["sublevels"].empty()) + sublevels = (int)fn["sublevels"]; + if (!fn["diffusivity"].empty()) + diffusivity = static_cast((int)fn["diffusivity"]); + } + + bool extended; + bool upright; + float threshold; + int octaves; + int sublevels; + int diffusivity; + }; + + Ptr KAZE::create(bool extended, bool upright, + float threshold, + int octaves, int sublevels, + KAZE::DiffusivityType diffusivity) + { + return makePtr(extended, upright, threshold, octaves, sublevels, diffusivity); + } + + String KAZE::getDefaultName() const + { + return (Feature2D::getDefaultName() + ".KAZE"); + } + +} +} // namespace cv diff --git a/modules/xfeatures2d/src/kaze/AKAZEConfig.h b/modules/xfeatures2d/src/kaze/AKAZEConfig.h new file mode 100644 index 00000000000..52b4fea2d3c --- /dev/null +++ b/modules/xfeatures2d/src/kaze/AKAZEConfig.h @@ -0,0 +1,69 @@ +/** + * @file AKAZEConfig.h + * @brief AKAZE configuration file + * @date Feb 23, 2014 + * @author Pablo F. Alcantarilla, Jesus Nuevo + */ + +#ifndef __OPENCV_FEATURES_2D_AKAZE_CONFIG_H__ +#define __OPENCV_FEATURES_2D_AKAZE_CONFIG_H__ + +namespace cv +{ +namespace xfeatures2d +{ + +/* ************************************************************************* */ +/// AKAZE configuration options structure +struct AKAZEOptions { + + AKAZEOptions() + : omax(4) + , nsublevels(4) + , img_width(0) + , img_height(0) + , soffset(1.6f) + , derivative_factor(1.5f) + , sderivatives(1.0) + , diffusivity(KAZE::DIFF_PM_G2) + + , dthreshold(0.001f) + , min_dthreshold(0.00001f) + + , descriptor(AKAZE::DESCRIPTOR_MLDB) + , descriptor_size(0) + , descriptor_channels(3) + , descriptor_pattern_size(10) + + , kcontrast(0.001f) + , kcontrast_percentile(0.7f) + , kcontrast_nbins(300) + { + } + + int omax; ///< Maximum octave evolution of the image 2^sigma (coarsest scale sigma units) + int nsublevels; ///< Default number of sublevels per scale level + int img_width; ///< Width of the input image + int img_height; ///< Height of the input image + float soffset; ///< Base scale offset (sigma units) + float derivative_factor; ///< Factor for the multiscale derivatives + float sderivatives; ///< Smoothing factor for the derivatives + KAZE::DiffusivityType diffusivity; ///< Diffusivity type + + float dthreshold; ///< Detector response threshold to accept point + float min_dthreshold; ///< Minimum detector threshold to accept a point + + AKAZE::DescriptorType descriptor; ///< Type of descriptor + int descriptor_size; ///< Size of the descriptor in bits. 0->Full size + int descriptor_channels; ///< Number of channels in the descriptor (1, 2, 3) + int descriptor_pattern_size; ///< Actual patch size is 2*pattern_size*point.scale + + float kcontrast; ///< The contrast factor parameter + float kcontrast_percentile; ///< Percentile level for the contrast factor + int kcontrast_nbins; ///< Number of bins for the contrast factor histogram +}; + +} +} + +#endif diff --git a/modules/xfeatures2d/src/kaze/AKAZEFeatures.cpp b/modules/xfeatures2d/src/kaze/AKAZEFeatures.cpp new file mode 100644 index 00000000000..923b6077962 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/AKAZEFeatures.cpp @@ -0,0 +1,2321 @@ +/** + * @file AKAZEFeatures.cpp + * @brief Main class for detecting and describing binary features in an + * accelerated nonlinear scale space + * @date Sep 15, 2013 + * @author Pablo F. Alcantarilla, Jesus Nuevo + */ + +#include "../precomp.hpp" +#include "AKAZEFeatures.h" +#include "fed.h" +#include "nldiffusion_functions.h" +#include "utils.h" +#include "opencl_kernels_xfeatures2d.hpp" + +#include + +// Namespaces +namespace cv +{ +namespace xfeatures2d +{ +using namespace std; + +/* ************************************************************************* */ +/** + * @brief AKAZEFeatures constructor with input options + * @param options AKAZEFeatures configuration options + * @note This constructor allocates memory for the nonlinear scale space + */ +AKAZEFeatures::AKAZEFeatures(const AKAZEOptions& options) : options_(options) { + + ncycles_ = 0; + reordering_ = true; + + if (options_.descriptor_size > 0 && options_.descriptor >= AKAZE::DESCRIPTOR_MLDB_UPRIGHT) { + generateDescriptorSubsample(descriptorSamples_, descriptorBits_, options_.descriptor_size, + options_.descriptor_pattern_size, options_.descriptor_channels); + } + + Allocate_Memory_Evolution(); +} + +/* ************************************************************************* */ +/** + * @brief This method allocates the memory for the nonlinear diffusion evolution + */ +void AKAZEFeatures::Allocate_Memory_Evolution(void) { + CV_INSTRUMENT_REGION(); + + float rfactor = 0.0f; + int level_height = 0, level_width = 0; + + // maximum size of the area for the descriptor computation + float smax = 0.0; + if (options_.descriptor == AKAZE::DESCRIPTOR_MLDB_UPRIGHT || options_.descriptor == AKAZE::DESCRIPTOR_MLDB) { + smax = 10.0f*sqrtf(2.0f); + } + else if (options_.descriptor == AKAZE::DESCRIPTOR_KAZE_UPRIGHT || options_.descriptor == AKAZE::DESCRIPTOR_KAZE) { + smax = 12.0f*sqrtf(2.0f); + } + + // Allocate the dimension of the matrices for the evolution + for (int i = 0, power = 1; i <= options_.omax - 1; i++, power *= 2) { + rfactor = 1.0f / power; + level_height = (int)(options_.img_height*rfactor); + level_width = (int)(options_.img_width*rfactor); + + // Smallest possible octave and allow one scale if the image is small + if ((level_width < 80 || level_height < 40) && i != 0) { + options_.omax = i; + break; + } + + for (int j = 0; j < options_.nsublevels; j++) { + MEvolution step; + step.size = Size(level_width, level_height); + step.esigma = options_.soffset*pow(2.f, (float)(j) / (float)(options_.nsublevels) + i); + step.sigma_size = cvRound(step.esigma * options_.derivative_factor / power); // In fact sigma_size only depends on j + step.etime = 0.5f * (step.esigma * step.esigma); + step.octave = i; + step.sublevel = j; + step.octave_ratio = (float)power; + step.border = cvRound(smax * step.sigma_size) + 1; + + evolution_.push_back(step); + } + } + + // Allocate memory for the number of cycles and time steps + for (size_t i = 1; i < evolution_.size(); i++) { + int naux = 0; + vector tau; + float ttime = 0.0f; + ttime = evolution_[i].etime - evolution_[i - 1].etime; + naux = fed_tau_by_process_time(ttime, 1, 0.25f, reordering_, tau); + nsteps_.push_back(naux); + tsteps_.push_back(tau); + ncycles_++; + } +} + +/* ************************************************************************* */ +/** + * @brief Computes kernel size for Gaussian smoothing if the image + * @param sigma Kernel standard deviation + * @returns kernel size + */ +static inline int getGaussianKernelSize(float sigma) { + // Compute an appropriate kernel size according to the specified sigma + int ksize = (int)cvCeil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f))); + ksize |= 1; // kernel should be odd + return ksize; +} + +/* ************************************************************************* */ +/** +* @brief This function computes a scalar non-linear diffusion step +* @param Lt Base image in the evolution +* @param Lf Conductivity image +* @param Lstep Output image that gives the difference between the current +* Ld and the next Ld being evolved +* @param row_begin row where to start +* @param row_end last row to fill exclusive. the range is [row_begin, row_end). +* @note Forward Euler Scheme 3x3 stencil +* The function c is a scalar value that depends on the gradient norm +* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy +*/ +static inline void +nld_step_scalar_one_lane(const Mat& Lt, const Mat& Lf, Mat& Lstep, float step_size, int row_begin, int row_end) +{ + CV_INSTRUMENT_REGION(); + /* The labeling scheme for this five star stencil: + [ a ] + [ -1 c +1 ] + [ b ] + */ + + Lstep.create(Lt.size(), Lt.type()); + const int cols = Lt.cols - 2; + int row = row_begin; + + const float *lt_a, *lt_c, *lt_b; + const float *lf_a, *lf_c, *lf_b; + float *dst; + float step_r = 0.f; + + // Process the top row + if (row == 0) { + lt_c = Lt.ptr(0) + 1; /* Skip the left-most column by +1 */ + lf_c = Lf.ptr(0) + 1; + lt_b = Lt.ptr(1) + 1; + lf_b = Lf.ptr(1) + 1; + + // fill the corner to prevent uninitialized values + dst = Lstep.ptr(0); + dst[0] = 0.0f; + ++dst; + + for (int j = 0; j < cols; j++) { + step_r = (lf_c[j] + lf_c[j + 1])*(lt_c[j + 1] - lt_c[j]) + + (lf_c[j] + lf_c[j - 1])*(lt_c[j - 1] - lt_c[j]) + + (lf_c[j] + lf_b[j ])*(lt_b[j ] - lt_c[j]); + dst[j] = step_r * step_size; + } + + // fill the corner to prevent uninitialized values + dst[cols] = 0.0f; + ++row; + } + + // Process the middle rows + int middle_end = std::min(Lt.rows - 1, row_end); + for (; row < middle_end; ++row) + { + lt_a = Lt.ptr(row - 1); + lf_a = Lf.ptr(row - 1); + lt_c = Lt.ptr(row ); + lf_c = Lf.ptr(row ); + lt_b = Lt.ptr(row + 1); + lf_b = Lf.ptr(row + 1); + dst = Lstep.ptr(row); + + // The left-most column + step_r = (lf_c[0] + lf_c[1])*(lt_c[1] - lt_c[0]) + + (lf_c[0] + lf_b[0])*(lt_b[0] - lt_c[0]) + + (lf_c[0] + lf_a[0])*(lt_a[0] - lt_c[0]); + dst[0] = step_r * step_size; + + lt_a++; lt_c++; lt_b++; + lf_a++; lf_c++; lf_b++; + dst++; + + // The middle columns + for (int j = 0; j < cols; j++) + { + step_r = (lf_c[j] + lf_c[j + 1])*(lt_c[j + 1] - lt_c[j]) + + (lf_c[j] + lf_c[j - 1])*(lt_c[j - 1] - lt_c[j]) + + (lf_c[j] + lf_b[j ])*(lt_b[j ] - lt_c[j]) + + (lf_c[j] + lf_a[j ])*(lt_a[j ] - lt_c[j]); + dst[j] = step_r * step_size; + } + + // The right-most column + step_r = (lf_c[cols] + lf_c[cols - 1])*(lt_c[cols - 1] - lt_c[cols]) + + (lf_c[cols] + lf_b[cols ])*(lt_b[cols ] - lt_c[cols]) + + (lf_c[cols] + lf_a[cols ])*(lt_a[cols ] - lt_c[cols]); + dst[cols] = step_r * step_size; + } + + // Process the bottom row (row == Lt.rows - 1) + if (row_end == Lt.rows) { + lt_a = Lt.ptr(row - 1) + 1; /* Skip the left-most column by +1 */ + lf_a = Lf.ptr(row - 1) + 1; + lt_c = Lt.ptr(row ) + 1; + lf_c = Lf.ptr(row ) + 1; + + // fill the corner to prevent uninitialized values + dst = Lstep.ptr(row); + dst[0] = 0.0f; + ++dst; + + for (int j = 0; j < cols; j++) { + step_r = (lf_c[j] + lf_c[j + 1])*(lt_c[j + 1] - lt_c[j]) + + (lf_c[j] + lf_c[j - 1])*(lt_c[j - 1] - lt_c[j]) + + (lf_c[j] + lf_a[j ])*(lt_a[j ] - lt_c[j]); + dst[j] = step_r * step_size; + } + + // fill the corner to prevent uninitialized values + dst[cols] = 0.0f; + } +} + +class NonLinearScalarDiffusionStep : public ParallelLoopBody +{ +public: + NonLinearScalarDiffusionStep(const Mat& Lt, const Mat& Lf, Mat& Lstep, float step_size) + : Lt_(&Lt), Lf_(&Lf), Lstep_(&Lstep), step_size_(step_size) + {} + + void operator()(const Range& range) const CV_OVERRIDE + { + nld_step_scalar_one_lane(*Lt_, *Lf_, *Lstep_, step_size_, range.start, range.end); + } + +private: + const Mat* Lt_; + const Mat* Lf_; + Mat* Lstep_; + float step_size_; +}; + +#ifdef HAVE_OPENCL +static inline bool +ocl_non_linear_diffusion_step(InputArray Lt_, InputArray Lf_, OutputArray Lstep_, float step_size) +{ + if(!Lt_.isContinuous()) + return false; + + UMat Lt = Lt_.getUMat(); + UMat Lf = Lf_.getUMat(); + UMat Lstep = Lstep_.getUMat(); + + size_t globalSize[] = {(size_t)Lt.cols, (size_t)Lt.rows}; + + ocl::Kernel ker("AKAZE_nld_step_scalar", ocl::xfeatures2d::akaze_oclsrc); + if( ker.empty() ) + return false; + + return ker.args( + ocl::KernelArg::ReadOnly(Lt), + ocl::KernelArg::PtrReadOnly(Lf), + ocl::KernelArg::PtrWriteOnly(Lstep), + step_size).run(2, globalSize, 0, true); +} +#endif // HAVE_OPENCL + +static inline void +non_linear_diffusion_step(InputArray Lt_, InputArray Lf_, OutputArray Lstep_, float step_size) +{ + CV_INSTRUMENT_REGION(); + + Lstep_.create(Lt_.size(), Lt_.type()); + + CV_OCL_RUN(Lt_.isUMat() && Lf_.isUMat() && Lstep_.isUMat(), + ocl_non_linear_diffusion_step(Lt_, Lf_, Lstep_, step_size)); + + Mat Lt = Lt_.getMat(); + Mat Lf = Lf_.getMat(); + Mat Lstep = Lstep_.getMat(); + parallel_for_(Range(0, Lt.rows), NonLinearScalarDiffusionStep(Lt, Lf, Lstep, step_size)); +} + +/** + * @brief This function computes a good empirical value for the k contrast factor + * given two gradient images, the percentile (0-1), the temporal storage to hold + * gradient norms and the histogram bins + * @param Lx Horizontal gradient of the input image + * @param Ly Vertical gradient of the input image + * @param nbins Number of histogram bins + * @return k contrast factor + */ +static inline float +compute_kcontrast(InputArray Lx_, InputArray Ly_, float perc, int nbins) +{ + CV_INSTRUMENT_REGION(); + + CV_Assert(nbins > 2); + CV_Assert(!Lx_.empty()); + + Mat Lx = Lx_.getMat(); + Mat Ly = Ly_.getMat(); + + // temporary square roots of dot product + Mat modgs (Lx.rows - 2, Lx.cols - 2, CV_32F); + const int total = modgs.cols * modgs.rows; + float *modg = modgs.ptr(); + float hmax = 0.0f; + + for (int i = 1; i < Lx.rows - 1; i++) { + const float *lx = Lx.ptr(i) + 1; + const float *ly = Ly.ptr(i) + 1; + const int cols = Lx.cols - 2; + + for (int j = 0; j < cols; j++) { + float dist = sqrtf(lx[j] * lx[j] + ly[j] * ly[j]); + *modg++ = dist; + hmax = std::max(hmax, dist); + } + } + modg = modgs.ptr(); + + if (hmax == 0.0f) + return 0.03f; // e.g. a blank image + + // Compute the bin numbers: the value range [0, hmax] -> [0, nbins-1] + modgs *= (nbins - 1) / hmax; + + // Count up histogram + std::vector hist(nbins, 0); + for (int i = 0; i < total; i++) + hist[(int)modg[i]]++; + + // Now find the perc of the histogram percentile + const int nthreshold = (int)((total - hist[0]) * perc); // Exclude hist[0] as background + int nelements = 0; + for (int k = 1; k < nbins; k++) { + if (nelements >= nthreshold) + return (float)hmax * k / nbins; + + nelements += hist[k]; + } + + return 0.03f; +} + +#ifdef HAVE_OPENCL +static inline bool +ocl_pm_g2(InputArray Lx_, InputArray Ly_, OutputArray Lflow_, float kcontrast) +{ + UMat Lx = Lx_.getUMat(); + UMat Ly = Ly_.getUMat(); + UMat Lflow = Lflow_.getUMat(); + + int total = Lx.rows * Lx.cols; + size_t globalSize[] = {(size_t)total}; + + ocl::Kernel ker("AKAZE_pm_g2", ocl::xfeatures2d::akaze_oclsrc); + if( ker.empty() ) + return false; + + return ker.args( + ocl::KernelArg::PtrReadOnly(Lx), + ocl::KernelArg::PtrReadOnly(Ly), + ocl::KernelArg::PtrWriteOnly(Lflow), + kcontrast, total).run(1, globalSize, 0, true); +} +#endif // HAVE_OPENCL + +static inline void +compute_diffusivity(InputArray Lx, InputArray Ly, OutputArray Lflow, float kcontrast, KAZE::DiffusivityType diffusivity) +{ + CV_INSTRUMENT_REGION(); + + Lflow.create(Lx.size(), Lx.type()); + + switch (diffusivity) { + case KAZE::DIFF_PM_G1: + pm_g1(Lx, Ly, Lflow, kcontrast); + break; + case KAZE::DIFF_PM_G2: + CV_OCL_RUN(Lx.isUMat() && Ly.isUMat() && Lflow.isUMat(), ocl_pm_g2(Lx, Ly, Lflow, kcontrast)); + pm_g2(Lx, Ly, Lflow, kcontrast); + break; + case KAZE::DIFF_WEICKERT: + weickert_diffusivity(Lx, Ly, Lflow, kcontrast); + break; + case KAZE::DIFF_CHARBONNIER: + charbonnier_diffusivity(Lx, Ly, Lflow, kcontrast); + break; + default: + CV_Error_(Error::StsError, ("Diffusivity is not supported: %d", static_cast(diffusivity))); + break; + } +} + +/** + * @brief Converts input image to grayscale float image + * + * @param image any image + * @param dst grayscale float image + */ +static inline void prepareInputImage(InputArray image, OutputArray dst) +{ + Mat img = image.getMat(); + if (img.channels() > 1) + cvtColor(image, img, COLOR_BGR2GRAY); + + if ( img.depth() == CV_32F ) + dst.assign(img); + else if ( img.depth() == CV_8U ) + img.convertTo(dst, CV_32F, 1.0 / 255.0, 0); + else if ( img.depth() == CV_16U ) + img.convertTo(dst, CV_32F, 1.0 / 65535.0, 0); +} + +/** + * @brief This method creates the nonlinear scale space for a given image + * @param image Input image for which the nonlinear scale space needs to be created + */ +template +static inline void +create_nonlinear_scale_space(InputArray image, const AKAZEOptions &options, + const std::vector > &tsteps_evolution, std::vector > &evolution) +{ + CV_INSTRUMENT_REGION(); + CV_Assert(evolution.size() > 0); + + // convert input to grayscale float image if needed + MatType img; + prepareInputImage(image, img); + + // create first level of the evolution + int ksize = getGaussianKernelSize(options.soffset); + GaussianBlur(img, evolution[0].Lsmooth, Size(ksize, ksize), options.soffset, options.soffset, BORDER_REPLICATE); + evolution[0].Lsmooth.copyTo(evolution[0].Lt); + + if (evolution.size() == 1) { + // we don't need to compute kcontrast factor + Compute_Determinant_Hessian_Response(evolution); + return; + } + + // derivatives, flow and diffusion step + MatType Lx, Ly, Lsmooth, Lflow, Lstep; + + // compute derivatives for computing k contrast + GaussianBlur(img, Lsmooth, Size(5, 5), 1.0f, 1.0f, BORDER_REPLICATE); + Scharr(Lsmooth, Lx, CV_32F, 1, 0, 1, 0, BORDER_DEFAULT); + Scharr(Lsmooth, Ly, CV_32F, 0, 1, 1, 0, BORDER_DEFAULT); + Lsmooth.release(); + // compute the kcontrast factor + float kcontrast = compute_kcontrast(Lx, Ly, options.kcontrast_percentile, options.kcontrast_nbins); + + // Now generate the rest of evolution levels + for (size_t i = 1; i < evolution.size(); i++) { + Evolution &e = evolution[i]; + + if (e.octave > evolution[i - 1].octave) { + // new octave will be half the size + resize(evolution[i - 1].Lt, e.Lt, e.size, 0, 0, INTER_AREA); + kcontrast *= 0.75f; + } + else { + evolution[i - 1].Lt.copyTo(e.Lt); + } + + GaussianBlur(e.Lt, e.Lsmooth, Size(5, 5), 1.0f, 1.0f, BORDER_REPLICATE); + + // Compute the Gaussian derivatives Lx and Ly + Scharr(e.Lsmooth, Lx, CV_32F, 1, 0, 1.0, 0, BORDER_DEFAULT); + Scharr(e.Lsmooth, Ly, CV_32F, 0, 1, 1.0, 0, BORDER_DEFAULT); + + // Compute the conductivity equation + compute_diffusivity(Lx, Ly, Lflow, kcontrast, options.diffusivity); + + // Perform Fast Explicit Diffusion on Lt + const std::vector &tsteps = tsteps_evolution[i - 1]; + for (size_t j = 0; j < tsteps.size(); j++) { + const float step_size = tsteps[j] * 0.5f; + non_linear_diffusion_step(e.Lt, Lflow, Lstep, step_size); + add(e.Lt, Lstep, e.Lt); + } + } + + Compute_Determinant_Hessian_Response(evolution); + + return; +} + +/** + * @brief Converts between UMatPyramid and Pyramid and vice versa + * @details Matrices in evolution levels will be copied + * + * @param src source pyramid + * @param dst destination pyramid + */ +template +static inline void +convertScalePyramid(const std::vector >& src, std::vector > &dst) +{ + dst.resize(src.size()); + for (size_t i = 0; i < src.size(); ++i) { + dst[i] = Evolution(src[i]); + } +} + +/** + * @brief This method creates the nonlinear scale space for a given image + * @param image Input image for which the nonlinear scale space needs to be created + */ +void AKAZEFeatures::Create_Nonlinear_Scale_Space(InputArray image) +{ + if (ocl::isOpenCLActivated() && image.isUMat()) { + // will run OCL version of scale space pyramid + UMatPyramid uPyr; + // init UMat pyramid with sizes + convertScalePyramid(evolution_, uPyr); + create_nonlinear_scale_space(image, options_, tsteps_, uPyr); + // download pyramid from GPU + convertScalePyramid(uPyr, evolution_); + } else { + // CPU version + create_nonlinear_scale_space(image, options_, tsteps_, evolution_); + } +} + +/* ************************************************************************* */ + +#ifdef HAVE_OPENCL +static inline bool +ocl_compute_determinant(InputArray Lxx_, InputArray Lxy_, InputArray Lyy_, + OutputArray Ldet_, float sigma) +{ + UMat Lxx = Lxx_.getUMat(); + UMat Lxy = Lxy_.getUMat(); + UMat Lyy = Lyy_.getUMat(); + UMat Ldet = Ldet_.getUMat(); + + const int total = Lxx.rows * Lxx.cols; + size_t globalSize[] = {(size_t)total}; + + ocl::Kernel ker("AKAZE_compute_determinant", ocl::xfeatures2d::akaze_oclsrc); + if( ker.empty() ) + return false; + + return ker.args( + ocl::KernelArg::PtrReadOnly(Lxx), + ocl::KernelArg::PtrReadOnly(Lxy), + ocl::KernelArg::PtrReadOnly(Lyy), + ocl::KernelArg::PtrWriteOnly(Ldet), + sigma, total).run(1, globalSize, 0, true); +} +#endif // HAVE_OPENCL + +/** + * @brief Compute determinant from hessians + * @details Compute Ldet by (Lxx.mul(Lyy) - Lxy.mul(Lxy)) * sigma + * + * @param Lxx spatial derivates + * @param Lxy spatial derivates + * @param Lyy spatial derivates + * @param Ldet output determinant + * @param sigma determinant will be scaled by this sigma + */ +static inline void compute_determinant(InputArray Lxx_, InputArray Lxy_, InputArray Lyy_, + OutputArray Ldet_, float sigma) +{ + CV_INSTRUMENT_REGION(); + + Ldet_.create(Lxx_.size(), Lxx_.type()); + + CV_OCL_RUN(Lxx_.isUMat() && Ldet_.isUMat(), ocl_compute_determinant(Lxx_, Lxy_, Lyy_, Ldet_, sigma)); + + // output determinant + Mat Lxx = Lxx_.getMat(), Lxy = Lxy_.getMat(), Lyy = Lyy_.getMat(), Ldet = Ldet_.getMat(); + float *lxx = Lxx.ptr(); + float *lxy = Lxy.ptr(); + float *lyy = Lyy.ptr(); + float *ldet = Ldet.ptr(); + const int total = Lxx.cols * Lxx.rows; + for (int j = 0; j < total; j++) { + ldet[j] = (lxx[j] * lyy[j] - lxy[j] * lxy[j]) * sigma; + } + +} + +template +class DeterminantHessianResponse : public ParallelLoopBody +{ +public: + explicit DeterminantHessianResponse(std::vector >& ev) + : evolution_(&ev) + { + } + + void operator()(const Range& range) const CV_OVERRIDE + { + MatType Lxx, Lxy, Lyy; + + for (int i = range.start; i < range.end; i++) + { + Evolution &e = (*evolution_)[i]; + + // we cannot use cv:Scharr here, because we need to handle also + // kernel sizes other than 3, by default we are using 9x9, 5x5 and 7x7 + + // compute kernels + Mat DxKx, DxKy, DyKx, DyKy; + compute_derivative_kernels(DxKx, DxKy, 1, 0, e.sigma_size); + compute_derivative_kernels(DyKx, DyKy, 0, 1, e.sigma_size); + + // compute the multiscale derivatives + sepFilter2D(e.Lsmooth, e.Lx, CV_32F, DxKx, DxKy); + sepFilter2D(e.Lx, Lxx, CV_32F, DxKx, DxKy); + sepFilter2D(e.Lx, Lxy, CV_32F, DyKx, DyKy); + sepFilter2D(e.Lsmooth, e.Ly, CV_32F, DyKx, DyKy); + sepFilter2D(e.Ly, Lyy, CV_32F, DyKx, DyKy); + + // free Lsmooth to same some space in the pyramid, it is not needed anymore + e.Lsmooth.release(); + + // compute determinant scaled by sigma + float sigma_size_quat = (float)(e.sigma_size * e.sigma_size * e.sigma_size * e.sigma_size); + compute_determinant(Lxx, Lxy, Lyy, e.Ldet, sigma_size_quat); + } + } + +private: + std::vector >* evolution_; +}; + + +/** + * @brief This method computes the feature detector response for the nonlinear scale space + * @details OCL version + * @note We use the Hessian determinant as the feature detector response + */ +static inline void +Compute_Determinant_Hessian_Response(UMatPyramid &evolution) { + CV_INSTRUMENT_REGION(); + + DeterminantHessianResponse body (evolution); + body(Range(0, (int)evolution.size())); +} + +/** + * @brief This method computes the feature detector response for the nonlinear scale space + * @details CPU version + * @note We use the Hessian determinant as the feature detector response + */ +static inline void +Compute_Determinant_Hessian_Response(Pyramid &evolution) { + CV_INSTRUMENT_REGION(); + + parallel_for_(Range(0, (int)evolution.size()), DeterminantHessianResponse(evolution)); +} + +/* ************************************************************************* */ + +/** + * @brief This method selects interesting keypoints through the nonlinear scale space + * @param kpts Vector of detected keypoints + */ +void AKAZEFeatures::Feature_Detection(std::vector& kpts) +{ + CV_INSTRUMENT_REGION(); + + kpts.clear(); + std::vector keypoints_by_layers; + Find_Scale_Space_Extrema(keypoints_by_layers); + Do_Subpixel_Refinement(keypoints_by_layers, kpts); + Compute_Keypoints_Orientation(kpts); +} + +/** + * @brief This method searches v for a neighbor point of the point candidate p + * @param x Coordinates of the keypoint candidate to search a neighbor + * @param y Coordinates of the keypoint candidate to search a neighbor + * @param mask Matrix holding keypoints positions + * @param search_radius neighbour radius for searching keypoints + * @param idx The index to mask, pointing to keypoint found. + * @return true if a neighbor point is found; false otherwise + */ +static inline bool +find_neighbor_point(const int x, const int y, const Mat &mask, const int search_radius, int &idx) +{ + // search neighborhood for keypoints + for (int i = y - search_radius; i < y + search_radius; ++i) { + const uchar *curr = mask.ptr(i); + for (int j = x - search_radius; j < x + search_radius; ++j) { + if (curr[j] == 0) { + continue; // skip non-keypoint + } + // fine-compare with L2 metric (L2 is smaller than our search window) + int dx = j - x; + int dy = i - y; + if (dx * dx + dy * dy <= search_radius * search_radius) { + idx = i * mask.cols + j; + return true; + } + } + } + + return false; +} + +/** + * @brief Find keypoints in parallel for each pyramid layer + */ +class FindKeypointsSameScale : public ParallelLoopBody +{ +public: + explicit FindKeypointsSameScale(const Pyramid& ev, + std::vector& kpts, float dthreshold) + : evolution_(&ev), keypoints_by_layers_(&kpts), dthreshold_(dthreshold) + {} + + void operator()(const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + const MEvolution &e = (*evolution_)[i]; + Mat &kpts = (*keypoints_by_layers_)[i]; + // this mask will hold positions of keypoints in this level + kpts = Mat::zeros(e.Ldet.size(), CV_8UC1); + + // if border is too big we shouldn't search any keypoints + if (e.border + 1 >= e.Ldet.rows) + continue; + + const float * prev = e.Ldet.ptr(e.border - 1); + const float * curr = e.Ldet.ptr(e.border ); + const float * next = e.Ldet.ptr(e.border + 1); + const float * ldet = e.Ldet.ptr(); + uchar *mask = kpts.ptr(); + const int search_radius = e.sigma_size; // size of keypoint in this level + + for (int y = e.border; y < e.Ldet.rows - e.border; y++) { + for (int x = e.border; x < e.Ldet.cols - e.border; x++) { + const float value = curr[x]; + + // Filter the points with the detector threshold + if (value <= dthreshold_) + continue; + if (value <= curr[x-1] || value <= curr[x+1]) + continue; + if (value <= prev[x-1] || value <= prev[x ] || value <= prev[x+1]) + continue; + if (value <= next[x-1] || value <= next[x ] || value <= next[x+1]) + continue; + + int idx = 0; + // Compare response with the same scale + if (find_neighbor_point(x, y, kpts, search_radius, idx)) { + if (value > ldet[idx]) { + mask[idx] = 0; // clear old point - we have better candidate now + } else { + continue; // there already is a better keypoint + } + } + + kpts.at(y, x) = 1; // we have a new keypoint + } + + prev = curr; + curr = next; + next += e.Ldet.cols; + } + } + } + +private: + const Pyramid* evolution_; + std::vector* keypoints_by_layers_; + float dthreshold_; ///< Detector response threshold to accept point +}; + +/** + * @brief This method finds extrema in the nonlinear scale space + * @param keypoints_by_layers Output vectors of detected keypoints; one vector for each evolution level + */ +void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector& keypoints_by_layers) +{ + CV_INSTRUMENT_REGION(); + + keypoints_by_layers.resize(evolution_.size()); + + // find points in the same level + parallel_for_(Range(0, (int)evolution_.size()), + FindKeypointsSameScale(evolution_, keypoints_by_layers, options_.dthreshold)); + + // Filter points with the lower scale level + for (size_t i = 1; i < keypoints_by_layers.size(); i++) { + // constants for this level + const Mat &keypoints = keypoints_by_layers[i]; + const uchar *const kpts = keypoints_by_layers[i].ptr(); + uchar *const kpts_prev = keypoints_by_layers[i-1].ptr(); + const float *const ldet = evolution_[i].Ldet.ptr(); + const float *const ldet_prev = evolution_[i-1].Ldet.ptr(); + // ratios are just powers of 2 + const int diff_ratio = (int)evolution_[i].octave_ratio / (int)evolution_[i-1].octave_ratio; + const int search_radius = evolution_[i].sigma_size * diff_ratio; // size of keypoint in this level + + size_t j = 0; + for (int y = 0; y < keypoints.rows; y++) { + for (int x = 0; x < keypoints.cols; x++, j++) { + if (kpts[j] == 0) { + continue; // skip non-keypoints + } + int idx = 0; + // project point to lower scale layer + const int p_x = x * diff_ratio; + const int p_y = y * diff_ratio; + if (find_neighbor_point(p_x, p_y, keypoints_by_layers[i-1], search_radius, idx)) { + if (ldet[j] > ldet_prev[idx]) { + kpts_prev[idx] = 0; // clear keypoint in lower layer + } + // else this pt may be pruned by the upper scale + } + } + } + } + + // Now filter points with the upper scale level (the other direction) + for (int i = (int)keypoints_by_layers.size() - 2; i >= 0; i--) { + // constants for this level + const Mat &keypoints = keypoints_by_layers[i]; + const uchar *const kpts = keypoints_by_layers[i].ptr(); + uchar *const kpts_next = keypoints_by_layers[i+1].ptr(); + const float *const ldet = evolution_[i].Ldet.ptr(); + const float *const ldet_next = evolution_[i+1].Ldet.ptr(); + // ratios are just powers of 2, i+1 ratio is always greater or equal to i + const int diff_ratio = (int)evolution_[i+1].octave_ratio / (int)evolution_[i].octave_ratio; + const int search_radius = evolution_[i+1].sigma_size; // size of keypoints in upper level + + size_t j = 0; + for (int y = 0; y < keypoints.rows; y++) { + for (int x = 0; x < keypoints.cols; x++, j++) { + if (kpts[j] == 0) { + continue; // skip non-keypoints + } + int idx = 0; + // project point to upper scale layer + const int p_x = x / diff_ratio; + const int p_y = y / diff_ratio; + if (find_neighbor_point(p_x, p_y, keypoints_by_layers[i+1], search_radius, idx)) { + if (ldet[j] > ldet_next[idx]) { + kpts_next[idx] = 0; // clear keypoint in upper layer + } + } + } + } + } +} + +/* ************************************************************************* */ +/** + * @brief This method performs subpixel refinement of the detected keypoints + * @param keypoints_by_layers Input vectors of detected keypoints, sorted by evolution levels + * @param kpts Output vector of the final refined keypoints + */ +void AKAZEFeatures::Do_Subpixel_Refinement( + std::vector& keypoints_by_layers, std::vector& output_keypoints) +{ + CV_INSTRUMENT_REGION(); + + for (size_t i = 0; i < keypoints_by_layers.size(); i++) { + const MEvolution &e = evolution_[i]; + const float * const ldet = e.Ldet.ptr(); + const float ratio = e.octave_ratio; + const int cols = e.Ldet.cols; + const Mat& keypoints = keypoints_by_layers[i]; + const uchar *const kpts = keypoints.ptr(); + + size_t j = 0; + for (int y = 0; y < keypoints.rows; y++) { + for (int x = 0; x < keypoints.cols; x++, j++) { + if (kpts[j] == 0) { + continue; // skip non-keypoints + } + + // create a new keypoint + KeyPoint kp; + kp.pt.x = x * e.octave_ratio; + kp.pt.y = y * e.octave_ratio; + kp.size = e.esigma * options_.derivative_factor; + kp.angle = -1; + kp.response = ldet[j]; + kp.octave = e.octave; + kp.class_id = static_cast(i); + + // Compute the gradient + float Dx = 0.5f * (ldet[ y *cols + x + 1] - ldet[ y *cols + x - 1]); + float Dy = 0.5f * (ldet[(y + 1)*cols + x ] - ldet[(y - 1)*cols + x ]); + + // Compute the Hessian + float Dxx = ldet[ y *cols + x + 1] + ldet[ y *cols + x - 1] - 2.0f * ldet[y*cols + x]; + float Dyy = ldet[(y + 1)*cols + x ] + ldet[(y - 1)*cols + x ] - 2.0f * ldet[y*cols + x]; + float Dxy = 0.25f * (ldet[(y + 1)*cols + x + 1] + ldet[(y - 1)*cols + x - 1] - + ldet[(y - 1)*cols + x + 1] - ldet[(y + 1)*cols + x - 1]); + + // Solve the linear system + Matx22f A( Dxx, Dxy, + Dxy, Dyy ); + Vec2f b( -Dx, -Dy ); + Vec2f dst( 0.0f, 0.0f ); + solve(A, b, dst, DECOMP_LU); + + float dx = dst(0); + float dy = dst(1); + + if (fabs(dx) > 1.0f || fabs(dy) > 1.0f) + continue; // Ignore the point that is not stable + + // Refine the coordinates + kp.pt.x += dx * ratio + .5f*(ratio-1.f); + kp.pt.y += dy * ratio + .5f*(ratio-1.f); + + kp.angle = 0.0; + kp.size *= 2.0f; // In OpenCV the size of a keypoint is the diameter + + // Push the refined keypoint to the final storage + output_keypoints.push_back(kp); + } + } + } +} + +/* ************************************************************************* */ + +class SURF_Descriptor_Upright_64_Invoker : public ParallelLoopBody +{ +public: + SURF_Descriptor_Upright_64_Invoker(std::vector& kpts, Mat& desc, const Pyramid& evolution) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_SURF_Descriptor_Upright_64((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_SURF_Descriptor_Upright_64(const KeyPoint& kpt, float* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + const Pyramid* evolution_; +}; + +class SURF_Descriptor_64_Invoker : public ParallelLoopBody +{ +public: + SURF_Descriptor_64_Invoker(std::vector& kpts, Mat& desc, Pyramid& evolution) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + { + } + + void operator()(const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_SURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_SURF_Descriptor_64(const KeyPoint& kpt, float* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; +}; + +class MSURF_Upright_Descriptor_64_Invoker : public ParallelLoopBody +{ +public: + MSURF_Upright_Descriptor_64_Invoker(std::vector& kpts, Mat& desc, Pyramid& evolution) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + { + } + + void operator()(const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_MSURF_Upright_Descriptor_64((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; +}; + +class MSURF_Descriptor_64_Invoker : public ParallelLoopBody +{ +public: + MSURF_Descriptor_64_Invoker(std::vector& kpts, Mat& desc, Pyramid& evolution) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_MSURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_MSURF_Descriptor_64(const KeyPoint& kpt, float* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; +}; + +class Upright_MLDB_Full_Descriptor_Invoker : public ParallelLoopBody +{ +public: + Upright_MLDB_Full_Descriptor_Invoker(std::vector& kpts, Mat& desc, Pyramid& evolution, AKAZEOptions& options) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + , options_(&options) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_Upright_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; + AKAZEOptions* options_; +}; + +class Upright_MLDB_Descriptor_Subset_Invoker : public ParallelLoopBody +{ +public: + Upright_MLDB_Descriptor_Subset_Invoker(std::vector& kpts, + Mat& desc, + Pyramid& evolution, + AKAZEOptions& options, + Mat descriptorSamples, + Mat descriptorBits) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + , options_(&options) + , descriptorSamples_(descriptorSamples) + , descriptorBits_(descriptorBits) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_Upright_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; + AKAZEOptions* options_; + + Mat descriptorSamples_; // List of positions in the grids to sample LDB bits from. + Mat descriptorBits_; +}; + +class MLDB_Full_Descriptor_Invoker : public ParallelLoopBody +{ +public: + MLDB_Full_Descriptor_Invoker(std::vector& kpts, Mat& desc, Pyramid& evolution, AKAZEOptions& options) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + , options_(&options) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc, int desc_size) const; + void MLDB_Fill_Values(float* values, int sample_step, int level, + float xf, float yf, float co, float si, float scale) const; + void MLDB_Binary_Comparisons(float* values, unsigned char* desc, + int count, int& dpos) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; + AKAZEOptions* options_; +}; + +class MLDB_Descriptor_Subset_Invoker : public ParallelLoopBody +{ +public: + MLDB_Descriptor_Subset_Invoker(std::vector& kpts, + Mat& desc, + Pyramid& evolution, + AKAZEOptions& options, + Mat descriptorSamples, + Mat descriptorBits) + : keypoints_(&kpts) + , descriptors_(&desc) + , evolution_(&evolution) + , options_(&options) + , descriptorSamples_(descriptorSamples) + , descriptorBits_(descriptorBits) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Get_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr(i), descriptors_->cols); + } + } + + void Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc, int desc_size) const; + +private: + std::vector* keypoints_; + Mat* descriptors_; + Pyramid* evolution_; + AKAZEOptions* options_; + + Mat descriptorSamples_; // List of positions in the grids to sample LDB bits from. + Mat descriptorBits_; +}; + +/** + * @brief This method computes the set of descriptors through the nonlinear scale space + * @param kpts Vector of detected keypoints + * @param desc Matrix to store the descriptors + */ +void AKAZEFeatures::Compute_Descriptors(std::vector& kpts, OutputArray descriptors) +{ + CV_INSTRUMENT_REGION(); + + for(size_t i = 0; i < kpts.size(); i++) + { + CV_Assert(0 <= kpts[i].class_id && kpts[i].class_id < static_cast(evolution_.size())); + } + + // Allocate memory for the matrix with the descriptors + int descriptor_size = 64; + int descriptor_type = CV_32FC1; + if (options_.descriptor >= AKAZE::DESCRIPTOR_MLDB_UPRIGHT) + { + int descriptor_bits = (options_.descriptor_size == 0) + ? (6 + 36 + 120)*options_.descriptor_channels // the full length binary descriptor -> 486 bits + : options_.descriptor_size; // the random bit selection length binary descriptor + descriptor_size = divUp(descriptor_bits, 8); + descriptor_type = CV_8UC1; + } + descriptors.create((int)kpts.size(), descriptor_size, descriptor_type); + + Mat desc = descriptors.getMat(); + + switch (options_.descriptor) + { + case AKAZE::DESCRIPTOR_KAZE_UPRIGHT: // Upright descriptors, not invariant to rotation + { + parallel_for_(Range(0, (int)kpts.size()), MSURF_Upright_Descriptor_64_Invoker(kpts, desc, evolution_)); + } + break; + case AKAZE::DESCRIPTOR_KAZE: + { + parallel_for_(Range(0, (int)kpts.size()), MSURF_Descriptor_64_Invoker(kpts, desc, evolution_)); + } + break; + case AKAZE::DESCRIPTOR_MLDB_UPRIGHT: // Upright descriptors, not invariant to rotation + { + if (options_.descriptor_size == 0) + parallel_for_(Range(0, (int)kpts.size()), Upright_MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_)); + else + parallel_for_(Range(0, (int)kpts.size()), Upright_MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_)); + } + break; + case AKAZE::DESCRIPTOR_MLDB: + { + if (options_.descriptor_size == 0) + parallel_for_(Range(0, (int)kpts.size()), MLDB_Full_Descriptor_Invoker(kpts, desc, evolution_, options_)); + else + parallel_for_(Range(0, (int)kpts.size()), MLDB_Descriptor_Subset_Invoker(kpts, desc, evolution_, options_, descriptorSamples_, descriptorBits_)); + } + break; + } +} + +/* ************************************************************************* */ +/** + * @brief This function samples the derivative responses Lx and Ly for the points + * within the radius of 6*scale from (x0, y0), then multiply 2D Gaussian weight + * @param Lx Horizontal derivative + * @param Ly Vertical derivative + * @param x0 X-coordinate of the center point + * @param y0 Y-coordinate of the center point + * @param scale The sampling step + * @param resX Output array of the weighted horizontal derivative responses + * @param resY Output array of the weighted vertical derivative responses + */ +static inline +void Sample_Derivative_Response_Radius6(const Mat &Lx, const Mat &Ly, + const int x0, const int y0, const int scale, + float *resX, float *resY) +{ + /* ************************************************************************* */ + /// Lookup table for 2d gaussian (sigma = 2.5) where (0,0) is top left and (6,6) is bottom right + static const float gauss25[7][7] = + { + { 0.02546481f, 0.02350698f, 0.01849125f, 0.01239505f, 0.00708017f, 0.00344629f, 0.00142946f }, + { 0.02350698f, 0.02169968f, 0.01706957f, 0.01144208f, 0.00653582f, 0.00318132f, 0.00131956f }, + { 0.01849125f, 0.01706957f, 0.01342740f, 0.00900066f, 0.00514126f, 0.00250252f, 0.00103800f }, + { 0.01239505f, 0.01144208f, 0.00900066f, 0.00603332f, 0.00344629f, 0.00167749f, 0.00069579f }, + { 0.00708017f, 0.00653582f, 0.00514126f, 0.00344629f, 0.00196855f, 0.00095820f, 0.00039744f }, + { 0.00344629f, 0.00318132f, 0.00250252f, 0.00167749f, 0.00095820f, 0.00046640f, 0.00019346f }, + { 0.00142946f, 0.00131956f, 0.00103800f, 0.00069579f, 0.00039744f, 0.00019346f, 0.00008024f } + }; + static const struct gtable + { + float weight[109]; + int xidx[109]; + int yidx[109]; + + explicit gtable(void) + { + // Generate the weight and indices by one-time initialization + int k = 0; + for (int i = -6; i <= 6; ++i) { + for (int j = -6; j <= 6; ++j) { + if (i*i + j*j < 36) { + CV_Assert(k < 109); + weight[k] = gauss25[abs(i)][abs(j)]; + yidx[k] = i; + xidx[k] = j; + ++k; + } + } + } + } + } g; + + CV_Assert(x0 - 6 * scale >= 0 && x0 + 6 * scale < Lx.cols); + CV_Assert(y0 - 6 * scale >= 0 && y0 + 6 * scale < Lx.rows); + + for (int i = 0; i < 109; i++) + { + int y = y0 + g.yidx[i] * scale; + int x = x0 + g.xidx[i] * scale; + + float w = g.weight[i]; + resX[i] = w * Lx.at(y, x); + resY[i] = w * Ly.at(y, x); + } +} + +/** + * @brief This function sorts a[] by quantized float values + * @param a[] Input floating point array to sort + * @param n The length of a[] + * @param quantum The interval to convert a[i]'s float values to integers + * @param nkeys a[i] < nkeys * quantum + * @param idx[] Output array of the indices: a[idx[i]] forms a sorted array + * @param cum[] Output array of the starting indices of quantized floats + * @note The values of a[] in [k*quantum, (k + 1)*quantum) is labeled by + * the integer k, which is calculated by floor(a[i]/quantum). After sorting, + * the values from a[idx[cum[k]]] to a[idx[cum[k+1]-1]] are all labeled by k. + * This sorting is unstable to reduce the memory access. + */ +static inline +void quantized_counting_sort(const float a[], const int n, + const float quantum, const int nkeys, + int idx[/*n*/], int cum[/*nkeys + 1*/]) +{ + CV_Assert(nkeys > 0); + memset(cum, 0, sizeof(cum[0]) * (nkeys + 1)); + + // Count up the quantized values + for (int i = 0; i < n; i++) + { + int b = (int)(a[i] / quantum); + if (b < 0 || b >= nkeys) + b = 0; + cum[b]++; + } + + // Compute the inclusive prefix sum i.e. the end indices; cum[nkeys] is the total + for (int i = 1; i <= nkeys; i++) + { + cum[i] += cum[i - 1]; + } + CV_Assert(cum[nkeys] == n); + + // Generate the sorted indices; cum[] becomes the exclusive prefix sum i.e. the start indices of keys + for (int i = 0; i < n; i++) + { + int b = (int)(a[i] / quantum); + if (b < 0 || b >= nkeys) + b = 0; + idx[--cum[b]] = i; + } +} + +/** + * @brief This function computes the main orientation for a given keypoint + * @param kpt Input keypoint + * @note The orientation is computed using a similar approach as described in the + * original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006 + */ +static inline +void Compute_Main_Orientation(KeyPoint& kpt, const Pyramid& evolution) +{ + // get the right evolution level for this keypoint + const MEvolution& e = evolution[kpt.class_id]; + // Get the information from the keypoint + int scale = cvRound(0.5f * kpt.size / e.octave_ratio); + int x0 = cvRound(kpt.pt.x / e.octave_ratio); + int y0 = cvRound(kpt.pt.y / e.octave_ratio); + + // Sample derivatives responses for the points within radius of 6*scale + const int ang_size = 109; + float resX[ang_size], resY[ang_size]; + Sample_Derivative_Response_Radius6(e.Lx, e.Ly, x0, y0, scale, resX, resY); + + // Compute the angle of each gradient vector + float Ang[ang_size]; + hal::fastAtan2(resY, resX, Ang, ang_size, false); + + // Sort by the angles; angles are labeled by slices of 0.15 radian + const int slices = 42; + const float ang_step = (float)(2.0 * CV_PI / slices); + int slice[slices + 1]; + int sorted_idx[ang_size]; + quantized_counting_sort(Ang, ang_size, ang_step, slices, sorted_idx, slice); + + // Find the main angle by sliding a window of 7-slice size(=PI/3) around the keypoint + const int win = 7; + + float maxX = 0.0f, maxY = 0.0f; + for (int i = slice[0]; i < slice[win]; i++) { + const int idx = sorted_idx[i]; + maxX += resX[idx]; + maxY += resY[idx]; + } + float maxNorm = maxX * maxX + maxY * maxY; + + for (int sn = 1; sn <= slices - win; sn++) { + + if (slice[sn] == slice[sn - 1] && slice[sn + win] == slice[sn + win - 1]) + continue; // The contents of the window didn't change; don't repeat the computation + + float sumX = 0.0f, sumY = 0.0f; + for (int i = slice[sn]; i < slice[sn + win]; i++) { + const int idx = sorted_idx[i]; + sumX += resX[idx]; + sumY += resY[idx]; + } + + float norm = sumX * sumX + sumY * sumY; + if (norm > maxNorm) + maxNorm = norm, maxX = sumX, maxY = sumY; // Found bigger one; update + } + + for (int sn = slices - win + 1; sn < slices; sn++) { + int remain = sn + win - slices; + + if (slice[sn] == slice[sn - 1] && slice[remain] == slice[remain - 1]) + continue; + + float sumX = 0.0f, sumY = 0.0f; + for (int i = slice[sn]; i < slice[slices]; i++) { + const int idx = sorted_idx[i]; + sumX += resX[idx]; + sumY += resY[idx]; + } + for (int i = slice[0]; i < slice[remain]; i++) { + const int idx = sorted_idx[i]; + sumX += resX[idx]; + sumY += resY[idx]; + } + + float norm = sumX * sumX + sumY * sumY; + if (norm > maxNorm) + maxNorm = norm, maxX = sumX, maxY = sumY; + } + + // Store the final result + kpt.angle = fastAtan2(maxY, maxX); +} + +class ComputeKeypointOrientation : public ParallelLoopBody +{ +public: + ComputeKeypointOrientation(std::vector& kpts, + const Pyramid& evolution) + : keypoints_(&kpts) + , evolution_(&evolution) + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + for (int i = range.start; i < range.end; i++) + { + Compute_Main_Orientation((*keypoints_)[i], *evolution_); + } + } +private: + std::vector* keypoints_; + const Pyramid* evolution_; +}; + +/** + * @brief This method computes the main orientation for a given keypoints + * @param kpts Input keypoints + */ +void AKAZEFeatures::Compute_Keypoints_Orientation(std::vector& kpts) const +{ + CV_INSTRUMENT_REGION(); + + parallel_for_(Range(0, (int)kpts.size()), ComputeKeypointOrientation(kpts, evolution_)); +} + +/* ************************************************************************* */ +/** + * @brief This method computes the upright descriptor (not rotation invariant) of + * the provided keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + * @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired + * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, + * ECCV 2008 + */ +void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float *desc, int desc_size) const { + + const int dsize = 64; + CV_Assert(desc_size == dsize); + + float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; + float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; + float sample_x = 0.0, sample_y = 0.0; + int x1 = 0, y1 = 0, sample_step = 0, pattern_size = 0; + int x2 = 0, y2 = 0, kx = 0, ky = 0, i = 0, j = 0, dcount = 0; + float fx = 0.0, fy = 0.0, ratio = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; + int scale = 0; + + // Subregion centers for the 4x4 gaussian weighting + float cx = -0.5f, cy = 0.5f; + + const Pyramid& evolution = *evolution_; + + // Set the descriptor size and the sample and pattern sizes + sample_step = 5; + pattern_size = 12; + + // Get the information from the keypoint + ratio = (float)(1 << kpt.octave); + scale = cvRound(0.5f*kpt.size / ratio); + const int level = kpt.class_id; + const Mat Lx = evolution[level].Lx; + const Mat Ly = evolution[level].Ly; + yf = kpt.pt.y / ratio; + xf = kpt.pt.x / ratio; + + i = -8; + + // Calculate descriptor for this interest point + // Area of size 24 s x 24 s + while (i < pattern_size) { + j = -8; + i = i - 4; + + cx += 1.0f; + cy = -0.5f; + + while (j < pattern_size) { + dx = dy = mdx = mdy = 0.0; + cy += 1.0f; + j = j - 4; + + ky = i + sample_step; + kx = j + sample_step; + + ys = yf + (ky*scale); + xs = xf + (kx*scale); + + for (int k = i; k < i + 9; k++) { + for (int l = j; l < j + 9; l++) { + sample_y = k*scale + yf; + sample_x = l*scale + xf; + + //Get the gaussian weighted x and y responses + gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.50f*scale); + + y1 = cvFloor(sample_y); + x1 = cvFloor(sample_x); + + y2 = y1 + 1; + x2 = x1 + 1; + + if (x1 < 0 || y1 < 0 || x2 >= Lx.cols || y2 >= Lx.rows) + continue; // FIXIT Boundaries + + fx = sample_x - x1; + fy = sample_y - y1; + + res1 = Lx.at(y1, x1); + res2 = Lx.at(y1, x2); + res3 = Lx.at(y2, x1); + res4 = Lx.at(y2, x2); + rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + res1 = Ly.at(y1, x1); + res2 = Ly.at(y1, x2); + res3 = Ly.at(y2, x1); + res4 = Ly.at(y2, x2); + ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + rx = gauss_s1*rx; + ry = gauss_s1*ry; + + // Sum the derivatives to the cumulative descriptor + dx += rx; + dy += ry; + mdx += fabs(rx); + mdy += fabs(ry); + } + } + + // Add the values to the descriptor vector + gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f); + + desc[dcount++] = dx*gauss_s2; + desc[dcount++] = dy*gauss_s2; + desc[dcount++] = mdx*gauss_s2; + desc[dcount++] = mdy*gauss_s2; + + len += (dx*dx + dy*dy + mdx*mdx + mdy*mdy)*gauss_s2*gauss_s2; + + j += 9; + } + + i += 9; + } + + CV_Assert(dcount == desc_size); + + // convert to unit vector + len = sqrt(len); + + const float len_inv = 1.0f / len; + for (i = 0; i < dsize; i++) { + desc[i] *= len_inv; + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the descriptor of the provided keypoint given the + * main orientation of the keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + * @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired + * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, + * ECCV 2008 + */ +void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, float *desc, int desc_size) const { + + const int dsize = 64; + CV_Assert(desc_size == dsize); + + float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; + float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; + float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; + float fx = 0.0, fy = 0.0, ratio = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0; + int kx = 0, ky = 0, i = 0, j = 0, dcount = 0; + int scale = 0; + + // Subregion centers for the 4x4 gaussian weighting + float cx = -0.5f, cy = 0.5f; + + const Pyramid& evolution = *evolution_; + + // Set the descriptor size and the sample and pattern sizes + sample_step = 5; + pattern_size = 12; + + // Get the information from the keypoint + ratio = (float)(1 << kpt.octave); + scale = cvRound(0.5f*kpt.size / ratio); + angle = kpt.angle * static_cast(CV_PI / 180.f); + const int level = kpt.class_id; + const Mat Lx = evolution[level].Lx; + const Mat Ly = evolution[level].Ly; + yf = kpt.pt.y / ratio; + xf = kpt.pt.x / ratio; + co = cos(angle); + si = sin(angle); + + i = -8; + + // Calculate descriptor for this interest point + // Area of size 24 s x 24 s + while (i < pattern_size) { + j = -8; + i = i - 4; + + cx += 1.0f; + cy = -0.5f; + + while (j < pattern_size) { + dx = dy = mdx = mdy = 0.0; + cy += 1.0f; + j = j - 4; + + ky = i + sample_step; + kx = j + sample_step; + + xs = xf + (-kx*scale*si + ky*scale*co); + ys = yf + (kx*scale*co + ky*scale*si); + + for (int k = i; k < i + 9; ++k) { + for (int l = j; l < j + 9; ++l) { + // Get coords of sample point on the rotated axis + sample_y = yf + (l*scale*co + k*scale*si); + sample_x = xf + (-l*scale*si + k*scale*co); + + // Get the gaussian weighted x and y responses + gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); + + y1 = cvFloor(sample_y); + x1 = cvFloor(sample_x); + + y2 = y1 + 1; + x2 = x1 + 1; + + if (x1 < 0 || y1 < 0 || x2 >= Lx.cols || y2 >= Lx.rows) + continue; // FIXIT Boundaries + + fx = sample_x - x1; + fy = sample_y - y1; + + res1 = Lx.at(y1, x1); + res2 = Lx.at(y1, x2); + res3 = Lx.at(y2, x1); + res4 = Lx.at(y2, x2); + rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + res1 = Ly.at(y1, x1); + res2 = Ly.at(y1, x2); + res3 = Ly.at(y2, x1); + res4 = Ly.at(y2, x2); + ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + // Get the x and y derivatives on the rotated axis + rry = gauss_s1*(rx*co + ry*si); + rrx = gauss_s1*(-rx*si + ry*co); + + // Sum the derivatives to the cumulative descriptor + dx += rrx; + dy += rry; + mdx += fabs(rrx); + mdy += fabs(rry); + } + } + + // Add the values to the descriptor vector + gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f); + desc[dcount++] = dx*gauss_s2; + desc[dcount++] = dy*gauss_s2; + desc[dcount++] = mdx*gauss_s2; + desc[dcount++] = mdy*gauss_s2; + + len += (dx*dx + dy*dy + mdx*mdx + mdy*mdy)*gauss_s2*gauss_s2; + + j += 9; + } + + i += 9; + } + + CV_Assert(dcount == desc_size); + + // convert to unit vector + len = sqrt(len); + + const float len_inv = 1.0f / len; + for (i = 0; i < dsize; i++) { + desc[i] *= len_inv; + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the rupright descriptor (not rotation invariant) of + * the provided keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + */ +void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc, int desc_size) const { + + const AKAZEOptions & options = *options_; + const Pyramid& evolution = *evolution_; + + // Buffer for the M-LDB descriptor + const int max_channels = 3; + CV_Assert(options.descriptor_channels <= max_channels); + float values[16*max_channels]; + + // Get the information from the keypoint + const float ratio = (float)(1 << kpt.octave); + const int scale = cvRound(0.5f*kpt.size / ratio); + const int level = kpt.class_id; + const Mat Lx = evolution[level].Lx; + const Mat Ly = evolution[level].Ly; + const Mat Lt = evolution[level].Lt; + const float yf = kpt.pt.y / ratio; + const float xf = kpt.pt.x / ratio; + + // For 2x2 grid, 3x3 grid and 4x4 grid + const int pattern_size = options_->descriptor_pattern_size; + CV_Assert((pattern_size & 1) == 0); + const int sample_step[3] = { + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; + + memset(desc, 0, desc_size); + + // For the three grids + int dcount1 = 0; + for (int z = 0; z < 3; z++) { + int dcount2 = 0; + const int step = sample_step[z]; + for (int i = -pattern_size; i < pattern_size; i += step) { + for (int j = -pattern_size; j < pattern_size; j += step) { + float di = 0.0, dx = 0.0, dy = 0.0; + + int nsamples = 0; + for (int k = 0; k < step; k++) { + for (int l = 0; l < step; l++) { + + // Get the coordinates of the sample point + const float sample_y = yf + (l+j)*scale; + const float sample_x = xf + (k+i)*scale; + + const int y1 = cvRound(sample_y); + const int x1 = cvRound(sample_x); + + if (y1 < 0 || y1 >= Lt.rows || x1 < 0 || x1 >= Lt.cols) + continue; // Boundaries + + const float ri = Lt.at(y1, x1); + const float rx = Lx.at(y1, x1); + const float ry = Ly.at(y1, x1); + + di += ri; + dx += rx; + dy += ry; + nsamples++; + } + } + + if (nsamples > 0) + { + const float nsamples_inv = 1.0f / nsamples; + di *= nsamples_inv; + dx *= nsamples_inv; + dy *= nsamples_inv; + } + + float *val = &values[dcount2*max_channels]; + *(val) = di; + *(val+1) = dx; + *(val+2) = dy; + dcount2++; + } + } + + // Do binary comparison + const int num = (z + 2) * (z + 2); + for (int i = 0; i < num; i++) { + for (int j = i + 1; j < num; j++) { + const float * valI = &values[i*max_channels]; + const float * valJ = &values[j*max_channels]; + for (int k = 0; k < 3; ++k) { + if (*(valI + k) > *(valJ + k)) { + desc[dcount1 / 8] |= (1 << (dcount1 % 8)); + } + dcount1++; + } + } + } + + } // for (int z = 0; z < 3; z++) + + CV_Assert(dcount1 <= desc_size*8); + CV_Assert(divUp(dcount1, 8) == desc_size); +} + +void MLDB_Full_Descriptor_Invoker::MLDB_Fill_Values(float* values, int sample_step, const int level, + float xf, float yf, float co, float si, float scale) const +{ + const Pyramid& evolution = *evolution_; + int pattern_size = options_->descriptor_pattern_size; + int chan = options_->descriptor_channels; + const Mat Lx = evolution[level].Lx; + const Mat Ly = evolution[level].Ly; + const Mat Lt = evolution[level].Lt; + + const Size size = Lt.size(); + CV_Assert(size == Lx.size()); + CV_Assert(size == Ly.size()); + + int valpos = 0; + for (int i = -pattern_size; i < pattern_size; i += sample_step) { + for (int j = -pattern_size; j < pattern_size; j += sample_step) { + float di = 0.0f, dx = 0.0f, dy = 0.0f; + + int nsamples = 0; + for (int k = i; k < i + sample_step; k++) { + for (int l = j; l < j + sample_step; l++) { + float sample_y = yf + (l*co * scale + k*si*scale); + float sample_x = xf + (-l*si * scale + k*co*scale); + + int y1 = cvRound(sample_y); + int x1 = cvRound(sample_x); + + if (y1 < 0 || y1 >= Lt.rows || x1 < 0 || x1 >= Lt.cols) + continue; // Boundaries + + float ri = Lt.at(y1, x1); + di += ri; + + if(chan > 1) { + float rx = Lx.at(y1, x1); + float ry = Ly.at(y1, x1); + if (chan == 2) { + dx += sqrtf(rx*rx + ry*ry); + } + else { + float rry = rx*co + ry*si; + float rrx = -rx*si + ry*co; + dx += rrx; + dy += rry; + } + } + nsamples++; + } + } + + if (nsamples > 0) + { + const float nsamples_inv = 1.0f / nsamples; + di *= nsamples_inv; + dx *= nsamples_inv; + dy *= nsamples_inv; + } + + values[valpos] = di; + if (chan > 1) { + values[valpos + 1] = dx; + } + if (chan > 2) { + values[valpos + 2] = dy; + } + valpos += chan; + } + } +} + +void MLDB_Full_Descriptor_Invoker::MLDB_Binary_Comparisons(float* values, unsigned char* desc, + int count, int& dpos) const { + int chan = options_->descriptor_channels; + int* ivalues = (int*) values; + for(int i = 0; i < count * chan; i++) { + ivalues[i] = CV_TOGGLE_FLT(ivalues[i]); + } + + for(int pos = 0; pos < chan; pos++) { + for (int i = 0; i < count; i++) { + int ival = ivalues[chan * i + pos]; + for (int j = i + 1; j < count; j++) { + if (ival > ivalues[chan * j + pos]) { + desc[dpos >> 3] |= (1 << (dpos & 7)); + } + dpos++; + } + } + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the descriptor of the provided keypoint given the + * main orientation of the keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + */ +void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc, int desc_size) const { + + const int max_channels = 3; + CV_Assert(options_->descriptor_channels <= max_channels); + const int pattern_size = options_->descriptor_pattern_size; + + float values[16*max_channels]; + CV_Assert((pattern_size & 1) == 0); + //const double size_mult[3] = {1, 2.0/3.0, 1.0/2.0}; + const int sample_step[3] = { // static_cast(ceil(pattern_size * size_mult[lvl])) + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; + + float ratio = (float)(1 << kpt.octave); + float scale = (float)cvRound(0.5f*kpt.size / ratio); + float xf = kpt.pt.x / ratio; + float yf = kpt.pt.y / ratio; + float angle = kpt.angle * static_cast(CV_PI / 180.f); + float co = cos(angle); + float si = sin(angle); + + memset(desc, 0, desc_size); + + int dpos = 0; + for(int lvl = 0; lvl < 3; lvl++) + { + int val_count = (lvl + 2) * (lvl + 2); + MLDB_Fill_Values(values, sample_step[lvl], kpt.class_id, xf, yf, co, si, scale); + MLDB_Binary_Comparisons(values, desc, val_count, dpos); + } + + CV_Assert(dpos == 486); + CV_Assert(divUp(dpos, 8) == desc_size); +} + +/* ************************************************************************* */ +/** + * @brief This method computes the M-LDB descriptor of the provided keypoint given the + * main orientation of the keypoint. The descriptor is computed based on a subset of + * the bits of the whole descriptor + * @param kpt Input keypoint + * @param desc Descriptor vector + */ +void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc, int desc_size) const { + + float rx = 0.f, ry = 0.f; + float sample_x = 0.f, sample_y = 0.f; + + const AKAZEOptions & options = *options_; + const Pyramid& evolution = *evolution_; + + // Get the information from the keypoint + float ratio = (float)(1 << kpt.octave); + int scale = cvRound(0.5f*kpt.size / ratio); + float angle = kpt.angle * static_cast(CV_PI / 180.f); + const int level = kpt.class_id; + const Mat Lx = evolution[level].Lx; + const Mat Ly = evolution[level].Ly; + const Mat Lt = evolution[level].Lt; + float yf = kpt.pt.y / ratio; + float xf = kpt.pt.x / ratio; + float co = cos(angle); + float si = sin(angle); + + // Allocate memory for the matrix of values + // Buffer for the M-LDB descriptor + const int max_channels = 3; + const int channels = options.descriptor_channels; + CV_Assert(channels <= max_channels); + float values[(4 + 9 + 16)*max_channels] = { 0 }; + + // Sample everything, but only do the comparisons + const int pattern_size = options.descriptor_pattern_size; + CV_Assert((pattern_size & 1) == 0); + const int sample_steps[3] = { + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; + + for (int i = 0; i < descriptorSamples_.rows; i++) { + const int *coords = descriptorSamples_.ptr(i); + CV_Assert(coords[0] >= 0 && coords[0] < 3); + const int sample_step = sample_steps[coords[0]]; + float di = 0.f, dx = 0.f, dy = 0.f; + + for (int k = coords[1]; k < coords[1] + sample_step; k++) { + for (int l = coords[2]; l < coords[2] + sample_step; l++) { + + // Get the coordinates of the sample point + sample_y = yf + (l*scale*co + k*scale*si); + sample_x = xf + (-l*scale*si + k*scale*co); + + const int y1 = cvRound(sample_y); + const int x1 = cvRound(sample_x); + + if (x1 < 0 || y1 < 0 || x1 >= Lt.cols || y1 >= Lt.rows) + continue; // Boundaries + + di += Lt.at(y1, x1); + + if (options.descriptor_channels > 1) { + rx = Lx.at(y1, x1); + ry = Ly.at(y1, x1); + + if (options.descriptor_channels == 2) { + dx += sqrtf(rx*rx + ry*ry); + } + else if (options.descriptor_channels == 3) { + // Get the x and y derivatives on the rotated axis + dx += rx*co + ry*si; + dy += -rx*si + ry*co; + } + } + } + } + + float* pValues = &values[channels * i]; + pValues[0] = di; + + if (channels == 2) { + pValues[1] = dx; + } + else if (channels == 3) { + pValues[1] = dx; + pValues[2] = dy; + } + } + + // Do the comparisons + const int *comps = descriptorBits_.ptr(0); + + CV_Assert(divUp(descriptorBits_.rows, 8) == desc_size); + memset(desc, 0, desc_size); + + for (int i = 0; i values[comps[2 * i + 1]]) { + desc[i / 8] |= (1 << (i % 8)); + } + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the upright (not rotation invariant) M-LDB descriptor + * of the provided keypoint given the main orientation of the keypoint. + * The descriptor is computed based on a subset of the bits of the whole descriptor + * @param kpt Input keypoint + * @param desc Descriptor vector + */ +void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc, int desc_size) const { + + float di = 0.0f, dx = 0.0f, dy = 0.0f; + float rx = 0.0f, ry = 0.0f; + float sample_x = 0.0f, sample_y = 0.0f; + int x1 = 0, y1 = 0; + + const AKAZEOptions & options = *options_; + const Pyramid& evolution = *evolution_; + + // Get the information from the keypoint + float ratio = (float)(1 << kpt.octave); + int scale = cvRound(0.5f*kpt.size / ratio); + const int level = kpt.class_id; + const Mat Lx = evolution[level].Lx; + const Mat Ly = evolution[level].Ly; + const Mat Lt = evolution[level].Lt; + float yf = kpt.pt.y / ratio; + float xf = kpt.pt.x / ratio; + + // Allocate memory for the matrix of values + const int max_channels = 3; + const int channels = options.descriptor_channels; + CV_Assert(channels <= max_channels); + float values[(4 + 9 + 16)*max_channels] = { 0 }; + + const int pattern_size = options.descriptor_pattern_size; + CV_Assert((pattern_size & 1) == 0); + const int sample_steps[3] = { + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; + + for (int i = 0; i < descriptorSamples_.rows; i++) { + const int *coords = descriptorSamples_.ptr(i); + CV_Assert(coords[0] >= 0 && coords[0] < 3); + int sample_step = sample_steps[coords[0]]; + di = 0.0f, dx = 0.0f, dy = 0.0f; + + for (int k = coords[1]; k < coords[1] + sample_step; k++) { + for (int l = coords[2]; l < coords[2] + sample_step; l++) { + + // Get the coordinates of the sample point + sample_y = yf + l*scale; + sample_x = xf + k*scale; + + y1 = cvRound(sample_y); + x1 = cvRound(sample_x); + + if (x1 < 0 || y1 < 0 || x1 >= Lt.cols || y1 >= Lt.rows) + continue; // Boundaries + + di += Lt.at(y1, x1); + + if (options.descriptor_channels > 1) { + rx = Lx.at(y1, x1); + ry = Ly.at(y1, x1); + + if (options.descriptor_channels == 2) { + dx += sqrtf(rx*rx + ry*ry); + } + else if (options.descriptor_channels == 3) { + dx += rx; + dy += ry; + } + } + } + } + + float* pValues = &values[channels * i]; + pValues[0] = di; + + if (options.descriptor_channels == 2) { + pValues[1] = dx; + } + else if (options.descriptor_channels == 3) { + pValues[1] = dx; + pValues[2] = dy; + } + } + + // Do the comparisons + const int *comps = descriptorBits_.ptr(0); + + CV_Assert(divUp(descriptorBits_.rows, 8) == desc_size); + memset(desc, 0, desc_size); + + for (int i = 0; i values[comps[2 * i + 1]]) { + desc[i / 8] |= (1 << (i % 8)); + } + } +} + +/* ************************************************************************* */ +/** + * @brief This function computes a (quasi-random) list of bits to be taken + * from the full descriptor. To speed the extraction, the function creates + * a list of the samples that are involved in generating at least a bit (sampleList) + * and a list of the comparisons between those samples (comparisons) + * @param sampleList + * @param comparisons The matrix with the binary comparisons + * @param nbits The number of bits of the descriptor + * @param pattern_size The pattern size for the binary descriptor + * @param nchannels Number of channels to consider in the descriptor (1-3) + * @note The function keeps the 18 bits (3-channels by 6 comparisons) of the + * coarser grid, since it provides the most robust estimations + */ +void generateDescriptorSubsample(Mat& sampleList, Mat& comparisons, int nbits, + int pattern_size, int nchannels) { + + int ssz = 0; + for (int i = 0; i < 3; i++) { + int gz = (i + 2)*(i + 2); + ssz += gz*(gz - 1) / 2; + } + ssz *= nchannels; + + CV_Assert(ssz == 162*nchannels); + CV_Assert(nbits <= ssz && "Descriptor size can't be bigger than full descriptor (486 = 162*3 - 3 channels)"); + + // Since the full descriptor is usually under 10k elements, we pick + // the selection from the full matrix. We take as many samples per + // pick as the number of channels. For every pick, we + // take the two samples involved and put them in the sampling list + + Mat_ fullM(ssz / nchannels, 5); + for (int i = 0, c = 0; i < 3; i++) { + int gdiv = i + 2; //grid divisions, per row + int gsz = gdiv*gdiv; + int psz = divUp(2*pattern_size, gdiv); + + for (int j = 0; j < gsz; j++) { + for (int k = j + 1; k < gsz; k++, c++) { + fullM(c, 0) = i; + fullM(c, 1) = psz*(j % gdiv) - pattern_size; + fullM(c, 2) = psz*(j / gdiv) - pattern_size; + fullM(c, 3) = psz*(k % gdiv) - pattern_size; + fullM(c, 4) = psz*(k / gdiv) - pattern_size; + } + } + } + + RNG rng(1024); + const int npicks = divUp(nbits, nchannels); + Mat_ comps = Mat_(nchannels * npicks, 2); + comps = 1000; + + // Select some samples. A sample includes all channels + int count = 0; + Mat_ samples(29, 3); + Mat_ fullcopy = fullM.clone(); + samples = -1; + + for (int i = 0; i < npicks; i++) { + int k = rng(fullM.rows - i); + if (i < 6) { + // Force use of the coarser grid values and comparisons + k = i; + } + + bool n = true; + + for (int j = 0; j < count; j++) { + if (samples(j, 0) == fullcopy(k, 0) && samples(j, 1) == fullcopy(k, 1) && samples(j, 2) == fullcopy(k, 2)) { + n = false; + comps(i*nchannels, 0) = nchannels*j; + comps(i*nchannels + 1, 0) = nchannels*j + 1; + comps(i*nchannels + 2, 0) = nchannels*j + 2; + break; + } + } + + if (n) { + samples(count, 0) = fullcopy(k, 0); + samples(count, 1) = fullcopy(k, 1); + samples(count, 2) = fullcopy(k, 2); + comps(i*nchannels, 0) = nchannels*count; + comps(i*nchannels + 1, 0) = nchannels*count + 1; + comps(i*nchannels + 2, 0) = nchannels*count + 2; + count++; + } + + n = true; + for (int j = 0; j < count; j++) { + if (samples(j, 0) == fullcopy(k, 0) && samples(j, 1) == fullcopy(k, 3) && samples(j, 2) == fullcopy(k, 4)) { + n = false; + comps(i*nchannels, 1) = nchannels*j; + comps(i*nchannels + 1, 1) = nchannels*j + 1; + comps(i*nchannels + 2, 1) = nchannels*j + 2; + break; + } + } + + if (n) { + samples(count, 0) = fullcopy(k, 0); + samples(count, 1) = fullcopy(k, 3); + samples(count, 2) = fullcopy(k, 4); + comps(i*nchannels, 1) = nchannels*count; + comps(i*nchannels + 1, 1) = nchannels*count + 1; + comps(i*nchannels + 2, 1) = nchannels*count + 2; + count++; + } + + Mat tmp = fullcopy.row(k); + fullcopy.row(fullcopy.rows - i - 1).copyTo(tmp); + } + + sampleList = samples.rowRange(0, count).clone(); + comparisons = comps.rowRange(0, nbits).clone(); +} + +} +} diff --git a/modules/xfeatures2d/src/kaze/AKAZEFeatures.h b/modules/xfeatures2d/src/kaze/AKAZEFeatures.h new file mode 100644 index 00000000000..fe56dc5e120 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/AKAZEFeatures.h @@ -0,0 +1,118 @@ +/** + * @file AKAZE.h + * @brief Main class for detecting and computing binary descriptors in an + * accelerated nonlinear scale space + * @date Mar 27, 2013 + * @author Pablo F. Alcantarilla, Jesus Nuevo + */ + +#ifndef __OPENCV_FEATURES_2D_AKAZE_FEATURES_H__ +#define __OPENCV_FEATURES_2D_AKAZE_FEATURES_H__ + +/* ************************************************************************* */ +// Includes +#include "AKAZEConfig.h" + +namespace cv +{ +namespace xfeatures2d +{ + +/// A-KAZE nonlinear diffusion filtering evolution +template +struct Evolution +{ + Evolution() { + etime = 0.0f; + esigma = 0.0f; + octave = 0; + sublevel = 0; + sigma_size = 0; + octave_ratio = 0.0f; + border = 0; + } + + template + explicit Evolution(const Evolution &other) { + size = other.size; + etime = other.etime; + esigma = other.esigma; + octave = other.octave; + sublevel = other.sublevel; + sigma_size = other.sigma_size; + octave_ratio = other.octave_ratio; + border = other.border; + + other.Lx.copyTo(Lx); + other.Ly.copyTo(Ly); + other.Lt.copyTo(Lt); + other.Lsmooth.copyTo(Lsmooth); + other.Ldet.copyTo(Ldet); + } + + MatType Lx, Ly; ///< First order spatial derivatives + MatType Lt; ///< Evolution image + MatType Lsmooth; ///< Smoothed image, used only for computing determinant, released afterwards + MatType Ldet; ///< Detector response + + Size size; ///< Size of the layer + float etime; ///< Evolution time + float esigma; ///< Evolution sigma. For linear diffusion t = sigma^2 / 2 + int octave; ///< Image octave + int sublevel; ///< Image sublevel in each octave + int sigma_size; ///< Integer esigma. For computing the feature detector responses + float octave_ratio; ///< Scaling ratio of this octave. ratio = 2^octave + int border; ///< Width of border where descriptors cannot be computed +}; + +typedef Evolution MEvolution; +typedef Evolution UEvolution; +typedef std::vector Pyramid; +typedef std::vector UMatPyramid; + +/* ************************************************************************* */ +// AKAZE Class Declaration +class AKAZEFeatures { + +private: + + AKAZEOptions options_; ///< Configuration options for AKAZE + Pyramid evolution_; ///< Vector of nonlinear diffusion evolution + + /// FED parameters + int ncycles_; ///< Number of cycles + bool reordering_; ///< Flag for reordering time steps + std::vector > tsteps_; ///< Vector of FED dynamic time steps + std::vector nsteps_; ///< Vector of number of steps per cycle + + /// Matrices for the M-LDB descriptor computation + cv::Mat descriptorSamples_; // List of positions in the grids to sample LDB bits from. + cv::Mat descriptorBits_; + cv::Mat bitMask_; + + /// Scale Space methods + void Allocate_Memory_Evolution(); + void Find_Scale_Space_Extrema(std::vector& keypoints_by_layers); + void Do_Subpixel_Refinement(std::vector& keypoints_by_layers, + std::vector& kpts); + + /// Feature description methods + void Compute_Keypoints_Orientation(std::vector& kpts) const; + +public: + /// Constructor with input arguments + AKAZEFeatures(const AKAZEOptions& options); + void Create_Nonlinear_Scale_Space(InputArray img); + void Feature_Detection(std::vector& kpts); + void Compute_Descriptors(std::vector& kpts, OutputArray desc); +}; + +/* ************************************************************************* */ +/// Inline functions +void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons, + int nbits, int pattern_size, int nchannels); + +} +} + +#endif diff --git a/modules/xfeatures2d/src/kaze/KAZEConfig.h b/modules/xfeatures2d/src/kaze/KAZEConfig.h new file mode 100644 index 00000000000..ed437e76bc7 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/KAZEConfig.h @@ -0,0 +1,60 @@ +/** + * @file KAZEConfig.h + * @brief Configuration file + * @date Dec 27, 2011 + * @author Pablo F. Alcantarilla + */ + +#ifndef __OPENCV_FEATURES_2D_KAZE_CONFIG_H__ +#define __OPENCV_FEATURES_2D_KAZE_CONFIG_H__ + +// OpenCV Includes +#include "../precomp.hpp" +#include + +namespace cv +{ +namespace xfeatures2d +{ + +//************************************************************************************* + +struct KAZEOptions { + + KAZEOptions() + : diffusivity(KAZE::DIFF_PM_G2) + + , soffset(1.60f) + , omax(4) + , nsublevels(4) + , img_width(0) + , img_height(0) + , sderivatives(1.0f) + , dthreshold(0.001f) + , kcontrast(0.01f) + , kcontrast_percentille(0.7f) + , kcontrast_bins(300) + , upright(false) + , extended(false) + { + } + + KAZE::DiffusivityType diffusivity; + float soffset; + int omax; + int nsublevels; + int img_width; + int img_height; + float sderivatives; + float dthreshold; + float kcontrast; + float kcontrast_percentille; + int kcontrast_bins; + bool upright; + bool extended; +}; + +} +} + +#endif diff --git a/modules/xfeatures2d/src/kaze/KAZEFeatures.cpp b/modules/xfeatures2d/src/kaze/KAZEFeatures.cpp new file mode 100644 index 00000000000..23fd2eae935 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/KAZEFeatures.cpp @@ -0,0 +1,1219 @@ + +//============================================================================= +// +// KAZE.cpp +// Author: Pablo F. Alcantarilla +// Institution: University d'Auvergne +// Address: Clermont Ferrand, France +// Date: 21/01/2012 +// Email: pablofdezalc@gmail.com +// +// KAZE Features Copyright 2012, Pablo F. Alcantarilla +// All Rights Reserved +// See LICENSE for the license information +//============================================================================= + +/** + * @file KAZEFeatures.cpp + * @brief Main class for detecting and describing features in a nonlinear + * scale space + * @date Jan 21, 2012 + * @author Pablo F. Alcantarilla + */ +#include "../precomp.hpp" +#include "KAZEFeatures.h" +#include "utils.h" + +namespace cv +{ +namespace xfeatures2d +{ + +// Namespaces +using namespace std; + +/* ************************************************************************* */ +/** + * @brief KAZE constructor with input options + * @param options KAZE configuration options + * @note The constructor allocates memory for the nonlinear scale space + */ +KAZEFeatures::KAZEFeatures(KAZEOptions& options) + : options_(options) +{ + ncycles_ = 0; + reordering_ = true; + + // Now allocate memory for the evolution + Allocate_Memory_Evolution(); +} + +/* ************************************************************************* */ +/** + * @brief This method allocates the memory for the nonlinear diffusion evolution + */ +void KAZEFeatures::Allocate_Memory_Evolution(void) { + + // Allocate the dimension of the matrices for the evolution + for (int i = 0; i <= options_.omax - 1; i++) + { + for (int j = 0; j <= options_.nsublevels - 1; j++) + { + TEvolution aux; + aux.Lx = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Ly = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Lxx = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Lxy = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Lyy = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Lt = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Lsmooth = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.Ldet = Mat::zeros(options_.img_height, options_.img_width, CV_32F); + aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i); + aux.etime = 0.5f*(aux.esigma*aux.esigma); + aux.sigma_size = cvRound(aux.esigma); + aux.octave = i; + aux.sublevel = j; + evolution_.push_back(aux); + } + } + + // Allocate memory for the FED number of cycles and time steps + for (size_t i = 1; i < evolution_.size(); i++) + { + int naux = 0; + vector tau; + float ttime = 0.0; + ttime = evolution_[i].etime - evolution_[i - 1].etime; + naux = fed_tau_by_process_time(ttime, 1, 0.25f, reordering_, tau); + nsteps_.push_back(naux); + tsteps_.push_back(tau); + ncycles_++; + } +} + +/* ************************************************************************* */ +/** + * @brief This method creates the nonlinear scale space for a given image + * @param img Input image for which the nonlinear scale space needs to be created + * @return 0 if the nonlinear scale space was created successfully. -1 otherwise + */ +int KAZEFeatures::Create_Nonlinear_Scale_Space(const Mat &img) +{ + CV_Assert(evolution_.size() > 0); + + // Copy the original image to the first level of the evolution + img.copyTo(evolution_[0].Lt); + gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lt, 0, 0, options_.soffset); + gaussian_2D_convolution(evolution_[0].Lt, evolution_[0].Lsmooth, 0, 0, options_.sderivatives); + + // Firstly compute the kcontrast factor + Compute_KContrast(evolution_[0].Lt, options_.kcontrast_percentille); + + // Allocate memory for the flow and step images + Mat Lflow = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F); + Mat Lstep = Mat::zeros(evolution_[0].Lt.rows, evolution_[0].Lt.cols, CV_32F); + + // Now generate the rest of evolution levels + for (size_t i = 1; i < evolution_.size(); i++) + { + evolution_[i - 1].Lt.copyTo(evolution_[i].Lt); + gaussian_2D_convolution(evolution_[i - 1].Lt, evolution_[i].Lsmooth, 0, 0, options_.sderivatives); + + // Compute the Gaussian derivatives Lx and Ly + Scharr(evolution_[i].Lsmooth, evolution_[i].Lx, CV_32F, 1, 0, 1, 0, BORDER_DEFAULT); + Scharr(evolution_[i].Lsmooth, evolution_[i].Ly, CV_32F, 0, 1, 1, 0, BORDER_DEFAULT); + + // Compute the conductivity equation + if (options_.diffusivity == KAZE::DIFF_PM_G1) + pm_g1(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast); + else if (options_.diffusivity == KAZE::DIFF_PM_G2) + pm_g2(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast); + else if (options_.diffusivity == KAZE::DIFF_WEICKERT) + weickert_diffusivity(evolution_[i].Lx, evolution_[i].Ly, Lflow, options_.kcontrast); + + // Perform FED n inner steps + for (int j = 0; j < nsteps_[i - 1]; j++) + nld_step_scalar(evolution_[i].Lt, Lflow, Lstep, tsteps_[i - 1][j]); + } + + return 0; +} + +/* ************************************************************************* */ +/** + * @brief This method computes the k contrast factor + * @param img Input image + * @param kpercentile Percentile of the gradient histogram + */ +void KAZEFeatures::Compute_KContrast(const Mat &img, const float &kpercentile) +{ + options_.kcontrast = compute_k_percentile(img, kpercentile, options_.sderivatives, options_.kcontrast_bins, 0, 0); +} + +/* ************************************************************************* */ +/** + * @brief This method computes the feature detector response for the nonlinear scale space + * @note We use the Hessian determinant as feature detector + */ +void KAZEFeatures::Compute_Detector_Response(void) +{ + float lxx = 0.0, lxy = 0.0, lyy = 0.0; + + // Firstly compute the multiscale derivatives + Compute_Multiscale_Derivatives(); + + for (size_t i = 0; i < evolution_.size(); i++) + { + for (int ix = 0; ix < options_.img_height; ix++) + { + for (int jx = 0; jx < options_.img_width; jx++) + { + lxx = *(evolution_[i].Lxx.ptr(ix)+jx); + lxy = *(evolution_[i].Lxy.ptr(ix)+jx); + lyy = *(evolution_[i].Lyy.ptr(ix)+jx); + *(evolution_[i].Ldet.ptr(ix)+jx) = (lxx*lyy - lxy*lxy); + } + } + } +} + +/* ************************************************************************* */ +/** + * @brief This method selects interesting keypoints through the nonlinear scale space + * @param kpts Vector of keypoints + */ +void KAZEFeatures::Feature_Detection(std::vector& kpts) +{ + kpts.clear(); + Compute_Detector_Response(); + Determinant_Hessian(kpts); + Do_Subpixel_Refinement(kpts); +} + +/* ************************************************************************* */ +class MultiscaleDerivativesKAZEInvoker : public ParallelLoopBody +{ +public: + explicit MultiscaleDerivativesKAZEInvoker(std::vector& ev) : evolution_(&ev) + { + } + + void operator()(const Range& range) const CV_OVERRIDE + { + std::vector& evolution = *evolution_; + for (int i = range.start; i < range.end; i++) + { + compute_scharr_derivatives(evolution[i].Lsmooth, evolution[i].Lx, 1, 0, evolution[i].sigma_size); + compute_scharr_derivatives(evolution[i].Lsmooth, evolution[i].Ly, 0, 1, evolution[i].sigma_size); + compute_scharr_derivatives(evolution[i].Lx, evolution[i].Lxx, 1, 0, evolution[i].sigma_size); + compute_scharr_derivatives(evolution[i].Ly, evolution[i].Lyy, 0, 1, evolution[i].sigma_size); + compute_scharr_derivatives(evolution[i].Lx, evolution[i].Lxy, 0, 1, evolution[i].sigma_size); + + evolution[i].Lx = evolution[i].Lx*((evolution[i].sigma_size)); + evolution[i].Ly = evolution[i].Ly*((evolution[i].sigma_size)); + evolution[i].Lxx = evolution[i].Lxx*((evolution[i].sigma_size)*(evolution[i].sigma_size)); + evolution[i].Lxy = evolution[i].Lxy*((evolution[i].sigma_size)*(evolution[i].sigma_size)); + evolution[i].Lyy = evolution[i].Lyy*((evolution[i].sigma_size)*(evolution[i].sigma_size)); + } + } + +private: + std::vector* evolution_; +}; + +/* ************************************************************************* */ +/** + * @brief This method computes the multiscale derivatives for the nonlinear scale space + */ +void KAZEFeatures::Compute_Multiscale_Derivatives(void) +{ + parallel_for_(Range(0, (int)evolution_.size()), + MultiscaleDerivativesKAZEInvoker(evolution_)); +} + + +/* ************************************************************************* */ +class FindExtremumKAZEInvoker : public ParallelLoopBody +{ +public: + explicit FindExtremumKAZEInvoker(std::vector& ev, std::vector >& kpts_par, + const KAZEOptions& options) : evolution_(&ev), kpts_par_(&kpts_par), options_(options) + { + } + + void operator()(const Range& range) const CV_OVERRIDE + { + std::vector& evolution = *evolution_; + std::vector >& kpts_par = *kpts_par_; + for (int i = range.start; i < range.end; i++) + { + float value = 0.0; + bool is_extremum = false; + + for (int ix = 1; ix < options_.img_height - 1; ix++) + { + for (int jx = 1; jx < options_.img_width - 1; jx++) + { + is_extremum = false; + value = *(evolution[i].Ldet.ptr(ix)+jx); + + // Filter the points with the detector threshold + if (value > options_.dthreshold) + { + if (value >= *(evolution[i].Ldet.ptr(ix)+jx - 1)) + { + // First check on the same scale + if (check_maximum_neighbourhood(evolution[i].Ldet, 1, value, ix, jx, 1)) + { + // Now check on the lower scale + if (check_maximum_neighbourhood(evolution[i - 1].Ldet, 1, value, ix, jx, 0)) + { + // Now check on the upper scale + if (check_maximum_neighbourhood(evolution[i + 1].Ldet, 1, value, ix, jx, 0)) + is_extremum = true; + } + } + } + } + + // Add the point of interest!! + if (is_extremum) + { + KeyPoint point; + point.pt.x = (float)jx; + point.pt.y = (float)ix; + point.response = fabs(value); + point.size = evolution[i].esigma; + point.octave = (int)evolution[i].octave; + point.class_id = i; + + // We use the angle field for the sublevel value + // Then, we will replace this angle field with the main orientation + point.angle = static_cast(evolution[i].sublevel); + kpts_par[i - 1].push_back(point); + } + } + } + } + } + +private: + std::vector* evolution_; + std::vector >* kpts_par_; + KAZEOptions options_; +}; + +/* ************************************************************************* */ +/** + * @brief This method performs the detection of keypoints by using the normalized + * score of the Hessian determinant through the nonlinear scale space + * @param kpts Vector of keypoints + * @note We compute features for each of the nonlinear scale space level in a different processing thread + */ +void KAZEFeatures::Determinant_Hessian(std::vector& kpts) +{ + int level = 0; + float smax = 3.0; + int id_repeated = 0; + int left_x = 0, right_x = 0, up_y = 0, down_y = 0; + bool is_extremum = false, is_repeated = false, is_out = false; + + // Delete the memory of the vector of keypoints vectors + // In case we use the same kaze object for multiple images + for (size_t i = 0; i < kpts_par_.size(); i++) { + vector().swap(kpts_par_[i]); + } + kpts_par_.clear(); + vector aux; + + // Allocate memory for the vector of vectors + for (size_t i = 1; i < evolution_.size() - 1; i++) { + kpts_par_.push_back(aux); + } + + parallel_for_(Range(1, (int)evolution_.size()-1), + FindExtremumKAZEInvoker(evolution_, kpts_par_, options_)); + + // Now fill the vector of keypoints!!! + for (int i = 0; i < (int)kpts_par_.size(); i++) + { + for (int j = 0; j < (int)kpts_par_[i].size(); j++) + { + level = i + 1; + const TEvolution& evolution_level = evolution_[level]; + + is_extremum = true; + is_repeated = false; + is_out = false; + + const KeyPoint& kpts_par_ij = kpts_par_[i][j]; + + // Check in case we have the same point as maxima in previous evolution levels + for (int ik = 0; ik < (int)kpts.size(); ik++) + { + const KeyPoint& kpts_ik = kpts[ik]; + if (kpts_ik.class_id == level || kpts_ik.class_id == level + 1 || kpts_ik.class_id == level - 1) { + Point2f diff = kpts_par_ij.pt - kpts_ik.pt; + float dist = diff.dot(diff); + + if (dist < evolution_level.sigma_size*evolution_level.sigma_size) { + if (kpts_par_ij.response > kpts_ik.response) { + id_repeated = ik; + is_repeated = true; + } + else { + is_extremum = false; + } + + break; + } + } + } + + if (is_extremum == true) { + // Check that the point is under the image limits for the descriptor computation + left_x = cvRound(kpts_par_ij.pt.x - smax*kpts_par_ij.size); + right_x = cvRound(kpts_par_ij.pt.x + smax*kpts_par_ij.size); + up_y = cvRound(kpts_par_ij.pt.y - smax*kpts_par_ij.size); + down_y = cvRound(kpts_par_ij.pt.y + smax*kpts_par_ij.size); + + if (left_x < 0 || right_x >= evolution_level.Ldet.cols || + up_y < 0 || down_y >= evolution_level.Ldet.rows) { + is_out = true; + } + + if (is_out == false) { + if (is_repeated == false) { + kpts.push_back(kpts_par_ij); + } + else { + kpts[id_repeated] = kpts_par_ij; + } + } + } + } + } +} + +/* ************************************************************************* */ +/** + * @brief This method performs subpixel refinement of the detected keypoints + * @param kpts Vector of detected keypoints + */ +void KAZEFeatures::Do_Subpixel_Refinement(std::vector &kpts) { + + int step = 1; + int x = 0, y = 0; + float Dx = 0.0, Dy = 0.0, Ds = 0.0, dsc = 0.0; + float Dxx = 0.0, Dyy = 0.0, Dss = 0.0, Dxy = 0.0, Dxs = 0.0, Dys = 0.0; + Mat A = Mat::zeros(3, 3, CV_32F); + Mat b = Mat::zeros(3, 1, CV_32F); + Mat dst = Mat::zeros(3, 1, CV_32F); + + vector kpts_(kpts); + + for (size_t i = 0; i < kpts_.size(); i++) { + + x = static_cast(kpts_[i].pt.x); + y = static_cast(kpts_[i].pt.y); + + // Compute the gradient + Dx = (1.0f / (2.0f*step))*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x + step) + - *(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x - step)); + Dy = (1.0f / (2.0f*step))*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y + step) + x) + - *(evolution_[kpts_[i].class_id].Ldet.ptr(y - step) + x)); + Ds = 0.5f*(*(evolution_[kpts_[i].class_id + 1].Ldet.ptr(y)+x) + - *(evolution_[kpts_[i].class_id - 1].Ldet.ptr(y)+x)); + + // Compute the Hessian + Dxx = (1.0f / (step*step))*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x + step) + + *(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x - step) + - 2.0f*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x))); + + Dyy = (1.0f / (step*step))*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y + step) + x) + + *(evolution_[kpts_[i].class_id].Ldet.ptr(y - step) + x) + - 2.0f*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x))); + + Dss = *(evolution_[kpts_[i].class_id + 1].Ldet.ptr(y)+x) + + *(evolution_[kpts_[i].class_id - 1].Ldet.ptr(y)+x) + - 2.0f*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y)+x)); + + Dxy = (1.0f / (4.0f*step))*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y + step) + x + step) + + (*(evolution_[kpts_[i].class_id].Ldet.ptr(y - step) + x - step))) + - (1.0f / (4.0f*step))*(*(evolution_[kpts_[i].class_id].Ldet.ptr(y - step) + x + step) + + (*(evolution_[kpts_[i].class_id].Ldet.ptr(y + step) + x - step))); + + Dxs = (1.0f / (4.0f*step))*(*(evolution_[kpts_[i].class_id + 1].Ldet.ptr(y)+x + step) + + (*(evolution_[kpts_[i].class_id - 1].Ldet.ptr(y)+x - step))) + - (1.0f / (4.0f*step))*(*(evolution_[kpts_[i].class_id + 1].Ldet.ptr(y)+x - step) + + (*(evolution_[kpts_[i].class_id - 1].Ldet.ptr(y)+x + step))); + + Dys = (1.0f / (4.0f*step))*(*(evolution_[kpts_[i].class_id + 1].Ldet.ptr(y + step) + x) + + (*(evolution_[kpts_[i].class_id - 1].Ldet.ptr(y - step) + x))) + - (1.0f / (4.0f*step))*(*(evolution_[kpts_[i].class_id + 1].Ldet.ptr(y - step) + x) + + (*(evolution_[kpts_[i].class_id - 1].Ldet.ptr(y + step) + x))); + + // Solve the linear system + *(A.ptr(0)) = Dxx; + *(A.ptr(1) + 1) = Dyy; + *(A.ptr(2) + 2) = Dss; + + *(A.ptr(0) + 1) = *(A.ptr(1)) = Dxy; + *(A.ptr(0) + 2) = *(A.ptr(2)) = Dxs; + *(A.ptr(1) + 2) = *(A.ptr(2) + 1) = Dys; + + *(b.ptr(0)) = -Dx; + *(b.ptr(1)) = -Dy; + *(b.ptr(2)) = -Ds; + + solve(A, b, dst, DECOMP_LU); + + if (fabs(*(dst.ptr(0))) <= 1.0f && fabs(*(dst.ptr(1))) <= 1.0f && fabs(*(dst.ptr(2))) <= 1.0f) { + kpts_[i].pt.x += *(dst.ptr(0)); + kpts_[i].pt.y += *(dst.ptr(1)); + dsc = kpts_[i].octave + (kpts_[i].angle + *(dst.ptr(2))) / ((float)(options_.nsublevels)); + + // In OpenCV the size of a keypoint is the diameter!! + kpts_[i].size = 2.0f*options_.soffset*pow((float)2.0f, dsc); + kpts_[i].angle = 0.0; + } + // Set the points to be deleted after the for loop + else { + kpts_[i].response = -1; + } + } + + // Clear the vector of keypoints + kpts.clear(); + + for (size_t i = 0; i < kpts_.size(); i++) { + if (kpts_[i].response != -1) { + kpts.push_back(kpts_[i]); + } + } +} + +/* ************************************************************************* */ +class KAZE_Descriptor_Invoker : public ParallelLoopBody +{ +public: + KAZE_Descriptor_Invoker(std::vector &kpts, Mat &desc, std::vector& evolution, const KAZEOptions& options) + : kpts_(&kpts) + , desc_(&desc) + , evolution_(&evolution) + , options_(options) + { + } + + virtual ~KAZE_Descriptor_Invoker() + { + } + + void operator() (const Range& range) const CV_OVERRIDE + { + std::vector &kpts = *kpts_; + Mat &desc = *desc_; + std::vector &evolution = *evolution_; + + for (int i = range.start; i < range.end; i++) + { + kpts[i].angle = 0.0; + if (options_.upright) + { + kpts[i].angle = 0.0; + if (options_.extended) + Get_KAZE_Upright_Descriptor_128(kpts[i], desc.ptr((int)i)); + else + Get_KAZE_Upright_Descriptor_64(kpts[i], desc.ptr((int)i)); + } + else + { + KAZEFeatures::Compute_Main_Orientation(kpts[i], evolution, options_); + + if (options_.extended) + Get_KAZE_Descriptor_128(kpts[i], desc.ptr((int)i)); + else + Get_KAZE_Descriptor_64(kpts[i], desc.ptr((int)i)); + } + } + } +private: + void Get_KAZE_Upright_Descriptor_64(const KeyPoint& kpt, float* desc) const; + void Get_KAZE_Descriptor_64(const KeyPoint& kpt, float* desc) const; + void Get_KAZE_Upright_Descriptor_128(const KeyPoint& kpt, float* desc) const; + void Get_KAZE_Descriptor_128(const KeyPoint& kpt, float *desc) const; + + std::vector * kpts_; + Mat * desc_; + std::vector * evolution_; + KAZEOptions options_; +}; + +/* ************************************************************************* */ +/** + * @brief This method computes the set of descriptors through the nonlinear scale space + * @param kpts Vector of keypoints + * @param desc Matrix with the feature descriptors + */ +void KAZEFeatures::Feature_Description(std::vector &kpts, Mat &desc) +{ + for(size_t i = 0; i < kpts.size(); i++) + { + CV_Assert(0 <= kpts[i].class_id && kpts[i].class_id < static_cast(evolution_.size())); + } + + // Allocate memory for the matrix of descriptors + if (options_.extended == true) { + desc = Mat::zeros((int)kpts.size(), 128, CV_32FC1); + } + else { + desc = Mat::zeros((int)kpts.size(), 64, CV_32FC1); + } + + parallel_for_(Range(0, (int)kpts.size()), KAZE_Descriptor_Invoker(kpts, desc, evolution_, options_)); +} + +/* ************************************************************************* */ +/** + * @brief This method computes the main orientation for a given keypoint + * @param kpt Input keypoint + * @note The orientation is computed using a similar approach as described in the + * original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006 + */ +void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector& evolution_, const KAZEOptions& options) +{ + int ix = 0, iy = 0, idx = 0, s = 0, level = 0; + float xf = 0.0, yf = 0.0, gweight = 0.0; + vector resX(109), resY(109), Ang(109); + + // Variables for computing the dominant direction + float sumX = 0.0, sumY = 0.0, max = 0.0, ang1 = 0.0, ang2 = 0.0; + + // Get the information from the keypoint + xf = kpt.pt.x; + yf = kpt.pt.y; + level = kpt.class_id; + s = cvRound(kpt.size / 2.0f); + + // Calculate derivatives responses for points within radius of 6*scale + for (int i = -6; i <= 6; ++i) { + for (int j = -6; j <= 6; ++j) { + if (i*i + j*j < 36) { + iy = cvRound(yf + j*s); + ix = cvRound(xf + i*s); + + if (iy >= 0 && iy < options.img_height && ix >= 0 && ix < options.img_width) { + gweight = gaussian(iy - yf, ix - xf, 2.5f*s); + resX[idx] = gweight*(*(evolution_[level].Lx.ptr(iy)+ix)); + resY[idx] = gweight*(*(evolution_[level].Ly.ptr(iy)+ix)); + } + else { + resX[idx] = 0.0; + resY[idx] = 0.0; + } + + Ang[idx] = fastAtan2(resY[idx], resX[idx]) * (float)(CV_PI / 180.0f); + ++idx; + } + } + } + + // Loop slides pi/3 window around feature point + for (ang1 = 0; ang1 < 2.0f*CV_PI; ang1 += 0.15f) { + ang2 = (ang1 + (float)(CV_PI / 3.0) > (float)(2.0*CV_PI) ? ang1 - (float)(5.0*CV_PI / 3.0) : ang1 + (float)(CV_PI / 3.0)); + sumX = sumY = 0.f; + + for (size_t k = 0; k < Ang.size(); ++k) { + // Get angle from the x-axis of the sample point + const float & ang = Ang[k]; + + // Determine whether the point is within the window + if (ang1 < ang2 && ang1 < ang && ang < ang2) { + sumX += resX[k]; + sumY += resY[k]; + } + else if (ang2 < ang1 && + ((ang > 0 && ang < ang2) || (ang > ang1 && ang < (float)(2.0*CV_PI)))) { + sumX += resX[k]; + sumY += resY[k]; + } + } + + // if the vector produced from this window is longer than all + // previous vectors then this forms the new dominant direction + if (sumX*sumX + sumY*sumY > max) { + // store largest orientation + max = sumX*sumX + sumY*sumY; + kpt.angle = fastAtan2(sumY, sumX); + } + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the upright descriptor (not rotation invariant) of + * the provided keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + * @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired + * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, + * ECCV 2008 + */ +void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const KeyPoint &kpt, float *desc) const +{ + float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; + float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; + float sample_x = 0.0, sample_y = 0.0; + int x1 = 0, y1 = 0, sample_step = 0, pattern_size = 0; + int x2 = 0, y2 = 0, kx = 0, ky = 0, i = 0, j = 0, dcount = 0; + float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; + int dsize = 0, scale = 0, level = 0; + + std::vector& evolution = *evolution_; + + // Subregion centers for the 4x4 gaussian weighting + float cx = -0.5f, cy = 0.5f; + + // Set the descriptor size and the sample and pattern sizes + dsize = 64; + sample_step = 5; + pattern_size = 12; + + // Get the information from the keypoint + yf = kpt.pt.y; + xf = kpt.pt.x; + scale = cvRound(kpt.size / 2.0f); + level = kpt.class_id; + + i = -8; + + // Calculate descriptor for this interest point + // Area of size 24 s x 24 s + while (i < pattern_size) { + j = -8; + i = i - 4; + + cx += 1.0f; + cy = -0.5f; + + while (j < pattern_size) { + + dx = dy = mdx = mdy = 0.0; + cy += 1.0f; + j = j - 4; + + ky = i + sample_step; + kx = j + sample_step; + + ys = yf + (ky*scale); + xs = xf + (kx*scale); + + for (int k = i; k < i + 9; k++) { + for (int l = j; l < j + 9; l++) { + + sample_y = k*scale + yf; + sample_x = l*scale + xf; + + //Get the gaussian weighted x and y responses + gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); + + y1 = (int)(sample_y - 0.5f); + x1 = (int)(sample_x - 0.5f); + + checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); + + y2 = (int)(sample_y + 0.5f); + x2 = (int)(sample_x + 0.5f); + + checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); + + fx = sample_x - x1; + fy = sample_y - y1; + + res1 = *(evolution[level].Lx.ptr(y1)+x1); + res2 = *(evolution[level].Lx.ptr(y1)+x2); + res3 = *(evolution[level].Lx.ptr(y2)+x1); + res4 = *(evolution[level].Lx.ptr(y2)+x2); + rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + res1 = *(evolution[level].Ly.ptr(y1)+x1); + res2 = *(evolution[level].Ly.ptr(y1)+x2); + res3 = *(evolution[level].Ly.ptr(y2)+x1); + res4 = *(evolution[level].Ly.ptr(y2)+x2); + ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + rx = gauss_s1*rx; + ry = gauss_s1*ry; + + // Sum the derivatives to the cumulative descriptor + dx += rx; + dy += ry; + mdx += fabs(rx); + mdy += fabs(ry); + } + } + + // Add the values to the descriptor vector + gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f); + + desc[dcount++] = dx*gauss_s2; + desc[dcount++] = dy*gauss_s2; + desc[dcount++] = mdx*gauss_s2; + desc[dcount++] = mdy*gauss_s2; + + len += (dx*dx + dy*dy + mdx*mdx + mdy*mdy)*gauss_s2*gauss_s2; + + j += 9; + } + + i += 9; + } + + // convert to unit vector + len = sqrt(len); + + for (i = 0; i < dsize; i++) { + desc[i] /= len; + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the descriptor of the provided keypoint given the + * main orientation of the keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + * @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired + * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, + * ECCV 2008 + */ +void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const KeyPoint &kpt, float *desc) const +{ + float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; + float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; + float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; + float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0; + int kx = 0, ky = 0, i = 0, j = 0, dcount = 0; + int dsize = 0, scale = 0, level = 0; + + std::vector& evolution = *evolution_; + + // Subregion centers for the 4x4 gaussian weighting + float cx = -0.5f, cy = 0.5f; + + // Set the descriptor size and the sample and pattern sizes + dsize = 64; + sample_step = 5; + pattern_size = 12; + + // Get the information from the keypoint + yf = kpt.pt.y; + xf = kpt.pt.x; + scale = cvRound(kpt.size / 2.0f); + angle = kpt.angle * static_cast(CV_PI / 180.f); + level = kpt.class_id; + co = cos(angle); + si = sin(angle); + + i = -8; + + // Calculate descriptor for this interest point + // Area of size 24 s x 24 s + while (i < pattern_size) { + + j = -8; + i = i - 4; + + cx += 1.0f; + cy = -0.5f; + + while (j < pattern_size) { + + dx = dy = mdx = mdy = 0.0; + cy += 1.0f; + j = j - 4; + + ky = i + sample_step; + kx = j + sample_step; + + xs = xf + (-kx*scale*si + ky*scale*co); + ys = yf + (kx*scale*co + ky*scale*si); + + for (int k = i; k < i + 9; ++k) { + for (int l = j; l < j + 9; ++l) { + + // Get coords of sample point on the rotated axis + sample_y = yf + (l*scale*co + k*scale*si); + sample_x = xf + (-l*scale*si + k*scale*co); + + // Get the gaussian weighted x and y responses + gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); + y1 = cvFloor(sample_y); + x1 = cvFloor(sample_x); + + checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); + + y2 = y1 + 1; + x2 = x1 + 1; + + checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); + + fx = sample_x - x1; + fy = sample_y - y1; + + res1 = *(evolution[level].Lx.ptr(y1)+x1); + res2 = *(evolution[level].Lx.ptr(y1)+x2); + res3 = *(evolution[level].Lx.ptr(y2)+x1); + res4 = *(evolution[level].Lx.ptr(y2)+x2); + rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + res1 = *(evolution[level].Ly.ptr(y1)+x1); + res2 = *(evolution[level].Ly.ptr(y1)+x2); + res3 = *(evolution[level].Ly.ptr(y2)+x1); + res4 = *(evolution[level].Ly.ptr(y2)+x2); + ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + // Get the x and y derivatives on the rotated axis + rry = gauss_s1*(rx*co + ry*si); + rrx = gauss_s1*(-rx*si + ry*co); + + // Sum the derivatives to the cumulative descriptor + dx += rrx; + dy += rry; + mdx += fabs(rrx); + mdy += fabs(rry); + } + } + + // Add the values to the descriptor vector + gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f); + desc[dcount++] = dx*gauss_s2; + desc[dcount++] = dy*gauss_s2; + desc[dcount++] = mdx*gauss_s2; + desc[dcount++] = mdy*gauss_s2; + len += (dx*dx + dy*dy + mdx*mdx + mdy*mdy)*gauss_s2*gauss_s2; + j += 9; + } + i += 9; + } + + // convert to unit vector + len = sqrt(len); + + for (i = 0; i < dsize; i++) { + desc[i] /= len; + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the extended upright descriptor (not rotation invariant) of + * the provided keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + * @note Rectangular grid of 24 s x 24 s. Descriptor Length 128. The descriptor is inspired + * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, + * ECCV 2008 + */ +void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const KeyPoint &kpt, float *desc) const +{ + float gauss_s1 = 0.0, gauss_s2 = 0.0; + float rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; + float sample_x = 0.0, sample_y = 0.0; + int x1 = 0, y1 = 0, sample_step = 0, pattern_size = 0; + int x2 = 0, y2 = 0, kx = 0, ky = 0, i = 0, j = 0, dcount = 0; + float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; + float dxp = 0.0, dyp = 0.0, mdxp = 0.0, mdyp = 0.0; + float dxn = 0.0, dyn = 0.0, mdxn = 0.0, mdyn = 0.0; + int dsize = 0, scale = 0, level = 0; + + // Subregion centers for the 4x4 gaussian weighting + float cx = -0.5f, cy = 0.5f; + + std::vector& evolution = *evolution_; + + // Set the descriptor size and the sample and pattern sizes + dsize = 128; + sample_step = 5; + pattern_size = 12; + + // Get the information from the keypoint + yf = kpt.pt.y; + xf = kpt.pt.x; + scale = cvRound(kpt.size / 2.0f); + level = kpt.class_id; + + i = -8; + + // Calculate descriptor for this interest point + // Area of size 24 s x 24 s + while (i < pattern_size) { + + j = -8; + i = i - 4; + + cx += 1.0f; + cy = -0.5f; + + while (j < pattern_size) { + + dxp = dxn = mdxp = mdxn = 0.0; + dyp = dyn = mdyp = mdyn = 0.0; + + cy += 1.0f; + j = j - 4; + + ky = i + sample_step; + kx = j + sample_step; + + ys = yf + (ky*scale); + xs = xf + (kx*scale); + + for (int k = i; k < i + 9; k++) { + for (int l = j; l < j + 9; l++) { + + sample_y = k*scale + yf; + sample_x = l*scale + xf; + + //Get the gaussian weighted x and y responses + gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); + + y1 = (int)(sample_y - 0.5f); + x1 = (int)(sample_x - 0.5f); + + checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); + + y2 = (int)(sample_y + 0.5f); + x2 = (int)(sample_x + 0.5f); + + checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); + + fx = sample_x - x1; + fy = sample_y - y1; + + res1 = *(evolution[level].Lx.ptr(y1)+x1); + res2 = *(evolution[level].Lx.ptr(y1)+x2); + res3 = *(evolution[level].Lx.ptr(y2)+x1); + res4 = *(evolution[level].Lx.ptr(y2)+x2); + rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + res1 = *(evolution[level].Ly.ptr(y1)+x1); + res2 = *(evolution[level].Ly.ptr(y1)+x2); + res3 = *(evolution[level].Ly.ptr(y2)+x1); + res4 = *(evolution[level].Ly.ptr(y2)+x2); + ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + rx = gauss_s1*rx; + ry = gauss_s1*ry; + + // Sum the derivatives to the cumulative descriptor + if (ry >= 0.0) { + dxp += rx; + mdxp += fabs(rx); + } + else { + dxn += rx; + mdxn += fabs(rx); + } + + if (rx >= 0.0) { + dyp += ry; + mdyp += fabs(ry); + } + else { + dyn += ry; + mdyn += fabs(ry); + } + } + } + + // Add the values to the descriptor vector + gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f); + + desc[dcount++] = dxp*gauss_s2; + desc[dcount++] = dxn*gauss_s2; + desc[dcount++] = mdxp*gauss_s2; + desc[dcount++] = mdxn*gauss_s2; + desc[dcount++] = dyp*gauss_s2; + desc[dcount++] = dyn*gauss_s2; + desc[dcount++] = mdyp*gauss_s2; + desc[dcount++] = mdyn*gauss_s2; + + // Store the current length^2 of the vector + len += (dxp*dxp + dxn*dxn + mdxp*mdxp + mdxn*mdxn + + dyp*dyp + dyn*dyn + mdyp*mdyp + mdyn*mdyn)*gauss_s2*gauss_s2; + + j += 9; + } + + i += 9; + } + + // convert to unit vector + len = sqrt(len); + + for (i = 0; i < dsize; i++) { + desc[i] /= len; + } +} + +/* ************************************************************************* */ +/** + * @brief This method computes the extended G-SURF descriptor of the provided keypoint + * given the main orientation of the keypoint + * @param kpt Input keypoint + * @param desc Descriptor vector + * @note Rectangular grid of 24 s x 24 s. Descriptor Length 128. The descriptor is inspired + * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, + * ECCV 2008 + */ +void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const KeyPoint &kpt, float *desc) const +{ + float gauss_s1 = 0.0, gauss_s2 = 0.0; + float rx = 0.0, ry = 0.0, rrx = 0.0, rry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0; + float sample_x = 0.0, sample_y = 0.0, co = 0.0, si = 0.0, angle = 0.0; + float fx = 0.0, fy = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 0.0; + float dxp = 0.0, dyp = 0.0, mdxp = 0.0, mdyp = 0.0; + float dxn = 0.0, dyn = 0.0, mdxn = 0.0, mdyn = 0.0; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0, sample_step = 0, pattern_size = 0; + int kx = 0, ky = 0, i = 0, j = 0, dcount = 0; + int dsize = 0, scale = 0, level = 0; + + std::vector& evolution = *evolution_; + + // Subregion centers for the 4x4 gaussian weighting + float cx = -0.5f, cy = 0.5f; + + // Set the descriptor size and the sample and pattern sizes + dsize = 128; + sample_step = 5; + pattern_size = 12; + + // Get the information from the keypoint + yf = kpt.pt.y; + xf = kpt.pt.x; + scale = cvRound(kpt.size / 2.0f); + angle = kpt.angle * static_cast(CV_PI / 180.f); + level = kpt.class_id; + co = cos(angle); + si = sin(angle); + + i = -8; + + // Calculate descriptor for this interest point + // Area of size 24 s x 24 s + while (i < pattern_size) { + + j = -8; + i = i - 4; + + cx += 1.0f; + cy = -0.5f; + + while (j < pattern_size) { + + dxp = dxn = mdxp = mdxn = 0.0; + dyp = dyn = mdyp = mdyn = 0.0; + + cy += 1.0f; + j = j - 4; + + ky = i + sample_step; + kx = j + sample_step; + + xs = xf + (-kx*scale*si + ky*scale*co); + ys = yf + (kx*scale*co + ky*scale*si); + + for (int k = i; k < i + 9; ++k) { + for (int l = j; l < j + 9; ++l) { + + // Get coords of sample point on the rotated axis + sample_y = yf + (l*scale*co + k*scale*si); + sample_x = xf + (-l*scale*si + k*scale*co); + + // Get the gaussian weighted x and y responses + gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); + + y1 = cvFloor(sample_y); + x1 = cvFloor(sample_x); + + checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); + + y2 = y1 + 1; + x2 = x1 + 1; + + checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); + + fx = sample_x - x1; + fy = sample_y - y1; + + res1 = *(evolution[level].Lx.ptr(y1)+x1); + res2 = *(evolution[level].Lx.ptr(y1)+x2); + res3 = *(evolution[level].Lx.ptr(y2)+x1); + res4 = *(evolution[level].Lx.ptr(y2)+x2); + rx = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + res1 = *(evolution[level].Ly.ptr(y1)+x1); + res2 = *(evolution[level].Ly.ptr(y1)+x2); + res3 = *(evolution[level].Ly.ptr(y2)+x1); + res4 = *(evolution[level].Ly.ptr(y2)+x2); + ry = (1.0f - fx)*(1.0f - fy)*res1 + fx*(1.0f - fy)*res2 + (1.0f - fx)*fy*res3 + fx*fy*res4; + + // Get the x and y derivatives on the rotated axis + rry = gauss_s1*(rx*co + ry*si); + rrx = gauss_s1*(-rx*si + ry*co); + + // Sum the derivatives to the cumulative descriptor + if (rry >= 0.0) { + dxp += rrx; + mdxp += fabs(rrx); + } + else { + dxn += rrx; + mdxn += fabs(rrx); + } + + if (rrx >= 0.0) { + dyp += rry; + mdyp += fabs(rry); + } + else { + dyn += rry; + mdyn += fabs(rry); + } + } + } + + // Add the values to the descriptor vector + gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f); + + desc[dcount++] = dxp*gauss_s2; + desc[dcount++] = dxn*gauss_s2; + desc[dcount++] = mdxp*gauss_s2; + desc[dcount++] = mdxn*gauss_s2; + desc[dcount++] = dyp*gauss_s2; + desc[dcount++] = dyn*gauss_s2; + desc[dcount++] = mdyp*gauss_s2; + desc[dcount++] = mdyn*gauss_s2; + + // Store the current length^2 of the vector + len += (dxp*dxp + dxn*dxn + mdxp*mdxp + mdxn*mdxn + + dyp*dyp + dyn*dyn + mdyp*mdyp + mdyn*mdyn)*gauss_s2*gauss_s2; + + j += 9; + } + + i += 9; + } + + // convert to unit vector + len = sqrt(len); + + for (i = 0; i < dsize; i++) { + desc[i] /= len; + } +} + +} +} diff --git a/modules/xfeatures2d/src/kaze/KAZEFeatures.h b/modules/xfeatures2d/src/kaze/KAZEFeatures.h new file mode 100644 index 00000000000..e31f50a1c53 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/KAZEFeatures.h @@ -0,0 +1,67 @@ + +/** + * @file KAZE.h + * @brief Main program for detecting and computing descriptors in a nonlinear + * scale space + * @date Jan 21, 2012 + * @author Pablo F. Alcantarilla + */ + +#ifndef __OPENCV_FEATURES_2D_KAZE_FEATURES_H__ +#define __OPENCV_FEATURES_2D_KAZE_FEATURES_H__ + +/* ************************************************************************* */ +// Includes +#include "KAZEConfig.h" +#include "nldiffusion_functions.h" +#include "fed.h" +#include "TEvolution.h" + +namespace cv +{ +namespace xfeatures2d +{ + +/* ************************************************************************* */ +// KAZE Class Declaration +class KAZEFeatures +{ +private: + + /// Parameters of the Nonlinear diffusion class + KAZEOptions options_; ///< Configuration options for KAZE + std::vector evolution_; ///< Vector of nonlinear diffusion evolution + + /// Vector of keypoint vectors for finding extrema in multiple threads + std::vector > kpts_par_; + + /// FED parameters + int ncycles_; ///< Number of cycles + bool reordering_; ///< Flag for reordering time steps + std::vector > tsteps_; ///< Vector of FED dynamic time steps + std::vector nsteps_; ///< Vector of number of steps per cycle + +public: + + /// Constructor + KAZEFeatures(KAZEOptions& options); + + /// Public methods for KAZE interface + void Allocate_Memory_Evolution(void); + int Create_Nonlinear_Scale_Space(const cv::Mat& img); + void Feature_Detection(std::vector& kpts); + void Feature_Description(std::vector& kpts, cv::Mat& desc); + static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector& evolution_, const KAZEOptions& options); + + /// Feature Detection Methods + void Compute_KContrast(const cv::Mat& img, const float& kper); + void Compute_Multiscale_Derivatives(void); + void Compute_Detector_Response(void); + void Determinant_Hessian(std::vector& kpts); + void Do_Subpixel_Refinement(std::vector& kpts); +}; + +} +} + +#endif diff --git a/modules/xfeatures2d/src/kaze/TEvolution.h b/modules/xfeatures2d/src/kaze/TEvolution.h new file mode 100644 index 00000000000..36052b3e642 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/TEvolution.h @@ -0,0 +1,41 @@ +/** + * @file TEvolution.h + * @brief Header file with the declaration of the TEvolution struct + * @date Jun 02, 2014 + * @author Pablo F. Alcantarilla + */ + +#ifndef __OPENCV_FEATURES_2D_TEVOLUTION_H__ +#define __OPENCV_FEATURES_2D_TEVOLUTION_H__ + +namespace cv +{ + +/* ************************************************************************* */ +/// KAZE/A-KAZE nonlinear diffusion filtering evolution +struct TEvolution +{ + TEvolution() { + etime = 0.0f; + esigma = 0.0f; + octave = 0; + sublevel = 0; + sigma_size = 0; + } + + Mat Lx, Ly; ///< First order spatial derivatives + Mat Lxx, Lxy, Lyy; ///< Second order spatial derivatives + Mat Lt; ///< Evolution image + Mat Lsmooth; ///< Smoothed image + Mat Ldet; ///< Detector response + + float etime; ///< Evolution time + float esigma; ///< Evolution sigma. For linear diffusion t = sigma^2 / 2 + int octave; ///< Image octave + int sublevel; ///< Image sublevel in each octave + int sigma_size; ///< Integer esigma. For computing the feature detector responses +}; + +} + +#endif diff --git a/modules/xfeatures2d/src/kaze/fed.cpp b/modules/xfeatures2d/src/kaze/fed.cpp new file mode 100644 index 00000000000..2026b838752 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/fed.cpp @@ -0,0 +1,192 @@ +//============================================================================= +// +// fed.cpp +// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2) +// Institutions: Georgia Institute of Technology (1) +// TrueVision Solutions (2) +// Date: 15/09/2013 +// Email: pablofdezalc@gmail.com +// +// AKAZE Features Copyright 2013, Pablo F. Alcantarilla, Jesus Nuevo +// All Rights Reserved +// See LICENSE for the license information +//============================================================================= + +/** + * @file fed.cpp + * @brief Functions for performing Fast Explicit Diffusion and building the + * nonlinear scale space + * @date Sep 15, 2013 + * @author Pablo F. Alcantarilla, Jesus Nuevo + * @note This code is derived from FED/FJ library from Grewenig et al., + * The FED/FJ library allows solving more advanced problems + * Please look at the following papers for more information about FED: + * [1] S. Grewenig, J. Weickert, C. Schroers, A. Bruhn. Cyclic Schemes for + * PDE-Based Image Analysis. Technical Report No. 327, Department of Mathematics, + * Saarland University, Saarbrücken, Germany, March 2013 + * [2] S. Grewenig, J. Weickert, A. Bruhn. From box filtering to fast explicit diffusion. + * DAGM, 2010 + * +*/ +#include "../precomp.hpp" +#include "fed.h" + +using namespace std; + +//************************************************************************************* +//************************************************************************************* + +/** + * @brief This function allocates an array of the least number of time steps such + * that a certain stopping time for the whole process can be obtained and fills + * it with the respective FED time step sizes for one cycle + * The function returns the number of time steps per cycle or 0 on failure + * @param T Desired process stopping time + * @param M Desired number of cycles + * @param tau_max Stability limit for the explicit scheme + * @param reordering Reordering flag + * @param tau The vector with the dynamic step sizes + */ +int fed_tau_by_process_time(const float& T, const int& M, const float& tau_max, + const bool& reordering, std::vector& tau) { + // All cycles have the same fraction of the stopping time + return fed_tau_by_cycle_time(T/(float)M,tau_max,reordering,tau); +} + +//************************************************************************************* +//************************************************************************************* + +/** + * @brief This function allocates an array of the least number of time steps such + * that a certain stopping time for the whole process can be obtained and fills it + * it with the respective FED time step sizes for one cycle + * The function returns the number of time steps per cycle or 0 on failure + * @param t Desired cycle stopping time + * @param tau_max Stability limit for the explicit scheme + * @param reordering Reordering flag + * @param tau The vector with the dynamic step sizes + */ +int fed_tau_by_cycle_time(const float& t, const float& tau_max, + const bool& reordering, std::vector &tau) { + int n = 0; // Number of time steps + float scale = 0.0; // Ratio of t we search to maximal t + + // Compute necessary number of time steps + n = cvCeil(sqrtf(3.0f*t/tau_max+0.25f)-0.5f-1.0e-8f); + scale = 3.0f*t/(tau_max*(float)(n*(n+1))); + + // Call internal FED time step creation routine + return fed_tau_internal(n,scale,tau_max,reordering,tau); +} + +//************************************************************************************* +//************************************************************************************* + +/** + * @brief This function allocates an array of time steps and fills it with FED + * time step sizes + * The function returns the number of time steps per cycle or 0 on failure + * @param n Number of internal steps + * @param scale Ratio of t we search to maximal t + * @param tau_max Stability limit for the explicit scheme + * @param reordering Reordering flag + * @param tau The vector with the dynamic step sizes + */ +int fed_tau_internal(const int& n, const float& scale, const float& tau_max, + const bool& reordering, std::vector &tau) { + float c = 0.0, d = 0.0; // Time savers + vector tauh; // Helper vector for unsorted taus + + if (n <= 0) { + return 0; + } + + // Allocate memory for the time step size + tau = vector(n); + + if (reordering) { + tauh = vector(n); + } + + // Compute time saver + c = 1.0f / (4.0f * (float)n + 2.0f); + d = scale * tau_max / 2.0f; + + // Set up originally ordered tau vector + for (int k = 0; k < n; ++k) { + float h = cosf((float)CV_PI * (2.0f * (float)k + 1.0f) * c); + + if (reordering) { + tauh[k] = d / (h * h); + } + else { + tau[k] = d / (h * h); + } + } + + // Permute list of time steps according to chosen reordering function + int kappa = 0, prime = 0; + + if (reordering == true) { + // Choose kappa cycle with k = n/2 + // This is a heuristic. We can use Leja ordering instead!! + kappa = n / 2; + + // Get modulus for permutation + prime = n + 1; + + while (!fed_is_prime_internal(prime)) { + prime++; + } + + // Perform permutation + for (int k = 0, l = 0; l < n; ++k, ++l) { + int index = 0; + while ((index = ((k+1)*kappa) % prime - 1) >= n) { + k++; + } + + tau[l] = tauh[index]; + } + } + + return n; +} + +//************************************************************************************* +//************************************************************************************* + +/** + * @brief This function checks if a number is prime or not + * @param number Number to check if it is prime or not + * @return true if the number is prime + */ +bool fed_is_prime_internal(const int& number) { + bool is_prime = false; + + if (number <= 1) { + return false; + } + else if (number == 1 || number == 2 || number == 3 || number == 5 || number == 7) { + return true; + } + else if ((number % 2) == 0 || (number % 3) == 0 || (number % 5) == 0 || (number % 7) == 0) { + return false; + } + else { + is_prime = true; + int upperLimit = (int)sqrt(1.0f + number); + int divisor = 11; + + while (divisor <= upperLimit ) { + if (number % divisor == 0) + { + is_prime = false; + } + + divisor +=2; + } + + return is_prime; + } +} diff --git a/modules/xfeatures2d/src/kaze/fed.h b/modules/xfeatures2d/src/kaze/fed.h new file mode 100644 index 00000000000..0cfa4005c8b --- /dev/null +++ b/modules/xfeatures2d/src/kaze/fed.h @@ -0,0 +1,25 @@ +#ifndef __OPENCV_FEATURES_2D_FED_H__ +#define __OPENCV_FEATURES_2D_FED_H__ + +//****************************************************************************** +//****************************************************************************** + +// Includes +#include + +//************************************************************************************* +//************************************************************************************* + +// Declaration of functions +int fed_tau_by_process_time(const float& T, const int& M, const float& tau_max, + const bool& reordering, std::vector& tau); +int fed_tau_by_cycle_time(const float& t, const float& tau_max, + const bool& reordering, std::vector &tau) ; +int fed_tau_internal(const int& n, const float& scale, const float& tau_max, + const bool& reordering, std::vector &tau); +bool fed_is_prime_internal(const int& number); + +//************************************************************************************* +//************************************************************************************* + +#endif // __OPENCV_FEATURES_2D_FED_H__ diff --git a/modules/xfeatures2d/src/kaze/nldiffusion_functions.cpp b/modules/xfeatures2d/src/kaze/nldiffusion_functions.cpp new file mode 100644 index 00000000000..942b8d78751 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/nldiffusion_functions.cpp @@ -0,0 +1,542 @@ +//============================================================================= +// +// nldiffusion_functions.cpp +// Author: Pablo F. Alcantarilla +// Institution: University d'Auvergne +// Address: Clermont Ferrand, France +// Date: 27/12/2011 +// Email: pablofdezalc@gmail.com +// +// KAZE Features Copyright 2012, Pablo F. Alcantarilla +// All Rights Reserved +// See LICENSE for the license information +//============================================================================= + +/** + * @file nldiffusion_functions.cpp + * @brief Functions for non-linear diffusion applications: + * 2D Gaussian Derivatives + * Perona and Malik conductivity equations + * Perona and Malik evolution + * @date Dec 27, 2011 + * @author Pablo F. Alcantarilla + */ + +#include "../precomp.hpp" +#include "nldiffusion_functions.h" +#include + +// Namespaces + +/* ************************************************************************* */ + +namespace cv +{ +using namespace std; + +/* ************************************************************************* */ +/** + * @brief This function smoothes an image with a Gaussian kernel + * @param src Input image + * @param dst Output image + * @param ksize_x Kernel size in X-direction (horizontal) + * @param ksize_y Kernel size in Y-direction (vertical) + * @param sigma Kernel standard deviation + */ +void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma) { + + int ksize_x_ = 0, ksize_y_ = 0; + + // Compute an appropriate kernel size according to the specified sigma + if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) { + ksize_x_ = cvCeil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f))); + ksize_y_ = ksize_x_; + } + + // The kernel size must be and odd number + if ((ksize_x_ % 2) == 0) { + ksize_x_ += 1; + } + + if ((ksize_y_ % 2) == 0) { + ksize_y_ += 1; + } + + // Perform the Gaussian Smoothing with border replication + GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE); +} + +/* ************************************************************************* */ +/** + * @brief This function computes image derivatives with Scharr kernel + * @param src Input image + * @param dst Output image + * @param xorder Derivative order in X-direction (horizontal) + * @param yorder Derivative order in Y-direction (vertical) + * @note Scharr operator approximates better rotation invariance than + * other stencils such as Sobel. See Weickert and Scharr, + * A Scheme for Coherence-Enhancing Diffusion Filtering with Optimized Rotation Invariance, + * Journal of Visual Communication and Image Representation 2002 + */ +void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder) { + Scharr(src, dst, CV_32F, xorder, yorder, 1.0, 0, BORDER_DEFAULT); +} + +/* ************************************************************************* */ +/** + * @brief This function computes the Perona and Malik conductivity coefficient g1 + * g1 = exp(-|dL|^2/k^2) + * @param _Lx First order image derivative in X-direction (horizontal) + * @param _Ly First order image derivative in Y-direction (vertical) + * @param _dst Output image + * @param k Contrast factor parameter + */ +void pm_g1(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) { + _dst.create(_Lx.size(), _Lx.type()); + Mat Lx = _Lx.getMat(); + Mat Ly = _Ly.getMat(); + Mat dst = _dst.getMat(); + + Size sz = Lx.size(); + float inv_k = 1.0f / (k*k); + for (int y = 0; y < sz.height; y++) { + + const float* Lx_row = Lx.ptr(y); + const float* Ly_row = Ly.ptr(y); + float* dst_row = dst.ptr(y); + + for (int x = 0; x < sz.width; x++) { + dst_row[x] = (-inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x])); + } + } + + exp(dst, dst); +} + +/* ************************************************************************* */ +/** + * @brief This function computes the Perona and Malik conductivity coefficient g2 + * g2 = 1 / (1 + dL^2 / k^2) + * @param _Lx First order image derivative in X-direction (horizontal) + * @param _Ly First order image derivative in Y-direction (vertical) + * @param _dst Output image + * @param k Contrast factor parameter + */ +void pm_g2(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) { + CV_INSTRUMENT_REGION(); + + _dst.create(_Lx.size(), _Lx.type()); + Mat Lx = _Lx.getMat(); + Mat Ly = _Ly.getMat(); + Mat dst = _dst.getMat(); + + Size sz = Lx.size(); + dst.create(sz, Lx.type()); + float k2inv = 1.0f / (k * k); + + for(int y = 0; y < sz.height; y++) { + const float *Lx_row = Lx.ptr(y); + const float *Ly_row = Ly.ptr(y); + float* dst_row = dst.ptr(y); + for(int x = 0; x < sz.width; x++) { + dst_row[x] = 1.0f / (1.0f + ((Lx_row[x] * Lx_row[x] + Ly_row[x] * Ly_row[x]) * k2inv)); + } + } +} +/* ************************************************************************* */ +/** + * @brief This function computes Weickert conductivity coefficient gw + * @param _Lx First order image derivative in X-direction (horizontal) + * @param _Ly First order image derivative in Y-direction (vertical) + * @param _dst Output image + * @param k Contrast factor parameter + * @note For more information check the following paper: J. Weickert + * Applications of nonlinear diffusion in image processing and computer vision, + * Proceedings of Algorithmy 2000 + */ +void weickert_diffusivity(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) { + _dst.create(_Lx.size(), _Lx.type()); + Mat Lx = _Lx.getMat(); + Mat Ly = _Ly.getMat(); + Mat dst = _dst.getMat(); + + Size sz = Lx.size(); + float inv_k = 1.0f / (k*k); + for (int y = 0; y < sz.height; y++) { + + const float* Lx_row = Lx.ptr(y); + const float* Ly_row = Ly.ptr(y); + float* dst_row = dst.ptr(y); + + for (int x = 0; x < sz.width; x++) { + float dL = inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x]); + dst_row[x] = -3.315f/(dL*dL*dL*dL); + } + } + + exp(dst, dst); + dst = 1.0 - dst; +} + + +/* ************************************************************************* */ +/** +* @brief This function computes Charbonnier conductivity coefficient gc +* gc = 1 / sqrt(1 + dL^2 / k^2) +* @param _Lx First order image derivative in X-direction (horizontal) +* @param _Ly First order image derivative in Y-direction (vertical) +* @param _dst Output image +* @param k Contrast factor parameter +* @note For more information check the following paper: J. Weickert +* Applications of nonlinear diffusion in image processing and computer vision, +* Proceedings of Algorithmy 2000 +*/ +void charbonnier_diffusivity(InputArray _Lx, InputArray _Ly, OutputArray _dst, float k) { + _dst.create(_Lx.size(), _Lx.type()); + Mat Lx = _Lx.getMat(); + Mat Ly = _Ly.getMat(); + Mat dst = _dst.getMat(); + + Size sz = Lx.size(); + float inv_k = 1.0f / (k*k); + for (int y = 0; y < sz.height; y++) { + + const float* Lx_row = Lx.ptr(y); + const float* Ly_row = Ly.ptr(y); + float* dst_row = dst.ptr(y); + + for (int x = 0; x < sz.width; x++) { + float den = sqrt(1.0f+inv_k*(Lx_row[x]*Lx_row[x] + Ly_row[x]*Ly_row[x])); + dst_row[x] = 1.0f / den; + } + } +} + + +/* ************************************************************************* */ +/** + * @brief This function computes a good empirical value for the k contrast factor + * given an input image, the percentile (0-1), the gradient scale and the number of + * bins in the histogram + * @param img Input image + * @param perc Percentile of the image gradient histogram (0-1) + * @param gscale Scale for computing the image gradient histogram + * @param nbins Number of histogram bins + * @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel + * @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel + * @return k contrast factor + */ +float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y) { + CV_INSTRUMENT_REGION(); + + int nbin = 0, nelements = 0, nthreshold = 0, k = 0; + float kperc = 0.0, modg = 0.0; + float npoints = 0.0; + float hmax = 0.0; + + // Create the array for the histogram + std::vector hist(nbins, 0); + + // Create the matrices + Mat gaussian = Mat::zeros(img.rows, img.cols, CV_32F); + Mat Lx = Mat::zeros(img.rows, img.cols, CV_32F); + Mat Ly = Mat::zeros(img.rows, img.cols, CV_32F); + + // Perform the Gaussian convolution + gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale); + + // Compute the Gaussian derivatives Lx and Ly + Scharr(gaussian, Lx, CV_32F, 1, 0, 1, 0, cv::BORDER_DEFAULT); + Scharr(gaussian, Ly, CV_32F, 0, 1, 1, 0, cv::BORDER_DEFAULT); + + // Skip the borders for computing the histogram + for (int i = 1; i < gaussian.rows - 1; i++) { + const float *lx = Lx.ptr(i); + const float *ly = Ly.ptr(i); + for (int j = 1; j < gaussian.cols - 1; j++) { + modg = lx[j]*lx[j] + ly[j]*ly[j]; + + // Get the maximum + if (modg > hmax) { + hmax = modg; + } + } + } + hmax = sqrt(hmax); + // Skip the borders for computing the histogram + for (int i = 1; i < gaussian.rows - 1; i++) { + const float *lx = Lx.ptr(i); + const float *ly = Ly.ptr(i); + for (int j = 1; j < gaussian.cols - 1; j++) { + modg = lx[j]*lx[j] + ly[j]*ly[j]; + + // Find the correspondent bin + if (modg != 0.0) { + nbin = (int)floor(nbins*(sqrt(modg) / hmax)); + + if (nbin == nbins) { + nbin--; + } + + hist[nbin]++; + npoints++; + } + } + } + + // Now find the perc of the histogram percentile + nthreshold = (int)(npoints*perc); + + for (k = 0; nelements < nthreshold && k < nbins; k++) { + nelements = nelements + hist[k]; + } + + if (nelements < nthreshold) { + kperc = 0.03f; + } + else { + kperc = hmax*((float)(k) / (float)nbins); + } + + return kperc; +} + +/* ************************************************************************* */ +/** + * @brief This function computes Scharr image derivatives + * @param src Input image + * @param dst Output image + * @param xorder Derivative order in X-direction (horizontal) + * @param yorder Derivative order in Y-direction (vertical) + * @param scale Scale factor for the derivative size + */ +void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale) { + Mat kx, ky; + compute_derivative_kernels(kx, ky, xorder, yorder, scale); + sepFilter2D(src, dst, CV_32F, kx, ky); +} + +/* ************************************************************************* */ +/** + * @brief Compute derivative kernels for sizes different than 3 + * @param _kx Horizontal kernel ues + * @param _ky Vertical kernel values + * @param dx Derivative order in X-direction (horizontal) + * @param dy Derivative order in Y-direction (vertical) + * @param scale Scale factor or derivative size + */ +void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale) { + CV_INSTRUMENT_REGION(); + + int ksize = 3 + 2 * (scale - 1); + + // The standard Scharr kernel + if (scale == 1) { + getDerivKernels(_kx, _ky, dx, dy, 0, true, CV_32F); + return; + } + + _kx.create(ksize, 1, CV_32F, -1, true); + _ky.create(ksize, 1, CV_32F, -1, true); + Mat kx = _kx.getMat(); + Mat ky = _ky.getMat(); + std::vector kerI; + + float w = 10.0f / 3.0f; + float norm = 1.0f / (2.0f*scale*(w + 2.0f)); + + for (int k = 0; k < 2; k++) { + Mat* kernel = k == 0 ? &kx : &ky; + int order = k == 0 ? dx : dy; + kerI.assign(ksize, 0.0f); + + if (order == 0) { + kerI[0] = norm, kerI[ksize / 2] = w*norm, kerI[ksize - 1] = norm; + } + else if (order == 1) { + kerI[0] = -1, kerI[ksize / 2] = 0, kerI[ksize - 1] = 1; + } + + Mat temp(kernel->rows, kernel->cols, CV_32F, &kerI[0]); + temp.copyTo(*kernel); + } +} + +class Nld_Step_Scalar_Invoker : public cv::ParallelLoopBody +{ +public: + Nld_Step_Scalar_Invoker(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float _stepsize) + : _Ld(&Ld) + , _c(&c) + , _Lstep(&Lstep) + , stepsize(_stepsize) + { + } + + virtual ~Nld_Step_Scalar_Invoker() + { + + } + + void operator()(const cv::Range& range) const CV_OVERRIDE + { + cv::Mat& Ld = *_Ld; + const cv::Mat& c = *_c; + cv::Mat& Lstep = *_Lstep; + + for (int i = range.start; i < range.end; i++) + { + const float *c_prev = c.ptr(i - 1); + const float *c_curr = c.ptr(i); + const float *c_next = c.ptr(i + 1); + const float *ld_prev = Ld.ptr(i - 1); + const float *ld_curr = Ld.ptr(i); + const float *ld_next = Ld.ptr(i + 1); + + float *dst = Lstep.ptr(i); + + for (int j = 1; j < Lstep.cols - 1; j++) + { + float xpos = (c_curr[j] + c_curr[j+1])*(ld_curr[j+1] - ld_curr[j]); + float xneg = (c_curr[j-1] + c_curr[j]) *(ld_curr[j] - ld_curr[j-1]); + float ypos = (c_curr[j] + c_next[j]) *(ld_next[j] - ld_curr[j]); + float yneg = (c_prev[j] + c_curr[j]) *(ld_curr[j] - ld_prev[j]); + dst[j] = 0.5f*stepsize*(xpos - xneg + ypos - yneg); + } + } + } +private: + cv::Mat * _Ld; + const cv::Mat * _c; + cv::Mat * _Lstep; + float stepsize; +}; + +/* ************************************************************************* */ +/** +* @brief This function performs a scalar non-linear diffusion step +* @param Ld Output image in the evolution +* @param c Conductivity image +* @param Lstep Previous image in the evolution +* @param stepsize The step size in time units +* @note Forward Euler Scheme 3x3 stencil +* The function c is a scalar value that depends on the gradient norm +* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy +*/ +void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize) { + CV_INSTRUMENT_REGION(); + + cv::parallel_for_(cv::Range(1, Lstep.rows - 1), Nld_Step_Scalar_Invoker(Ld, c, Lstep, stepsize), (double)Ld.total()/(1 << 16)); + + float xneg, xpos, yneg, ypos; + float* dst = Lstep.ptr(0); + const float* cprv = NULL; + const float* ccur = c.ptr(0); + const float* cnxt = c.ptr(1); + const float* ldprv = NULL; + const float* ldcur = Ld.ptr(0); + const float* ldnxt = Ld.ptr(1); + for (int j = 1; j < Lstep.cols - 1; j++) { + xpos = (ccur[j] + ccur[j+1]) * (ldcur[j+1] - ldcur[j]); + xneg = (ccur[j-1] + ccur[j]) * (ldcur[j] - ldcur[j-1]); + ypos = (ccur[j] + cnxt[j]) * (ldnxt[j] - ldcur[j]); + dst[j] = 0.5f*stepsize*(xpos - xneg + ypos); + } + + dst = Lstep.ptr(Lstep.rows - 1); + ccur = c.ptr(Lstep.rows - 1); + cprv = c.ptr(Lstep.rows - 2); + ldcur = Ld.ptr(Lstep.rows - 1); + ldprv = Ld.ptr(Lstep.rows - 2); + + for (int j = 1; j < Lstep.cols - 1; j++) { + xpos = (ccur[j] + ccur[j+1]) * (ldcur[j+1] - ldcur[j]); + xneg = (ccur[j-1] + ccur[j]) * (ldcur[j] - ldcur[j-1]); + yneg = (cprv[j] + ccur[j]) * (ldcur[j] - ldprv[j]); + dst[j] = 0.5f*stepsize*(xpos - xneg - yneg); + } + + ccur = c.ptr(1); + ldcur = Ld.ptr(1); + cprv = c.ptr(0); + ldprv = Ld.ptr(0); + + int r0 = Lstep.cols - 1; + int r1 = Lstep.cols - 2; + + for (int i = 1; i < Lstep.rows - 1; i++) { + cnxt = c.ptr(i + 1); + ldnxt = Ld.ptr(i + 1); + dst = Lstep.ptr(i); + + xpos = (ccur[0] + ccur[1]) * (ldcur[1] - ldcur[0]); + ypos = (ccur[0] + cnxt[0]) * (ldnxt[0] - ldcur[0]); + yneg = (cprv[0] + ccur[0]) * (ldcur[0] - ldprv[0]); + dst[0] = 0.5f*stepsize*(xpos + ypos - yneg); + + xneg = (ccur[r1] + ccur[r0]) * (ldcur[r0] - ldcur[r1]); + ypos = (ccur[r0] + cnxt[r0]) * (ldnxt[r0] - ldcur[r0]); + yneg = (cprv[r0] + ccur[r0]) * (ldcur[r0] - ldprv[r0]); + dst[r0] = 0.5f*stepsize*(-xneg + ypos - yneg); + + cprv = ccur; + ccur = cnxt; + ldprv = ldcur; + ldcur = ldnxt; + } + Ld += Lstep; +} + +/* ************************************************************************* */ +/** +* @brief This function downsamples the input image using OpenCV resize +* @param src Input image to be downsampled +* @param dst Output image with half of the resolution of the input image +*/ +void halfsample_image(const cv::Mat& src, cv::Mat& dst) { + // Make sure the destination image is of the right size + CV_Assert(src.cols / 2 == dst.cols); + CV_Assert(src.rows / 2 == dst.rows); + resize(src, dst, dst.size(), 0, 0, cv::INTER_AREA); +} + +/* ************************************************************************* */ +/** + * @brief This function checks if a given pixel is a maximum in a local neighbourhood + * @param img Input image where we will perform the maximum search + * @param dsize Half size of the neighbourhood + * @param value Response value at (x,y) position + * @param row Image row coordinate + * @param col Image column coordinate + * @param same_img Flag to indicate if the image value at (x,y) is in the input image + * @return 1->is maximum, 0->otherwise + */ +bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img) { + + bool response = true; + + for (int i = row - dsize; i <= row + dsize; i++) { + for (int j = col - dsize; j <= col + dsize; j++) { + if (i >= 0 && i < img.rows && j >= 0 && j < img.cols) { + if (same_img == true) { + if (i != row || j != col) { + if ((*(img.ptr(i)+j)) > value) { + response = false; + return response; + } + } + } + else { + if ((*(img.ptr(i)+j)) > value) { + response = false; + return response; + } + } + } + } + } + + return response; +} + +} diff --git a/modules/xfeatures2d/src/kaze/nldiffusion_functions.h b/modules/xfeatures2d/src/kaze/nldiffusion_functions.h new file mode 100644 index 00000000000..4254edc6a0a --- /dev/null +++ b/modules/xfeatures2d/src/kaze/nldiffusion_functions.h @@ -0,0 +1,47 @@ +/** + * @file nldiffusion_functions.h + * @brief Functions for non-linear diffusion applications: + * 2D Gaussian Derivatives + * Perona and Malik conductivity equations + * Perona and Malik evolution + * @date Dec 27, 2011 + * @author Pablo F. Alcantarilla + */ + +#ifndef __OPENCV_FEATURES_2D_NLDIFFUSION_FUNCTIONS_H__ +#define __OPENCV_FEATURES_2D_NLDIFFUSION_FUNCTIONS_H__ + +/* ************************************************************************* */ +// Declaration of functions + +namespace cv +{ + +// Gaussian 2D convolution +void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma); + +// Diffusivity functions +void pm_g1(InputArray Lx, InputArray Ly, OutputArray dst, float k); +void pm_g2(InputArray Lx, InputArray Ly, OutputArray dst, float k); +void weickert_diffusivity(InputArray Lx, InputArray Ly, OutputArray dst, float k); +void charbonnier_diffusivity(InputArray Lx, InputArray Ly, OutputArray dst, float k); + +float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y); + +// Image derivatives +void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale); +void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale); +void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder); + +// Nonlinear diffusion filtering scalar step +void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize); + +// For non-maxima suppression +bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img); + +// Image downsampling +void halfsample_image(const cv::Mat& src, cv::Mat& dst); + +} + +#endif diff --git a/modules/xfeatures2d/src/kaze/utils.h b/modules/xfeatures2d/src/kaze/utils.h new file mode 100644 index 00000000000..63199430628 --- /dev/null +++ b/modules/xfeatures2d/src/kaze/utils.h @@ -0,0 +1,42 @@ +#ifndef __OPENCV_FEATURES_2D_KAZE_UTILS_H__ +#define __OPENCV_FEATURES_2D_KAZE_UTILS_H__ + +/* ************************************************************************* */ +/** + * @brief This function computes the value of a 2D Gaussian function + * @param x X Position + * @param y Y Position + * @param sigma Standard Deviation + */ +inline float gaussian(float x, float y, float sigma) { + return expf(-(x*x + y*y) / (2.0f*sigma*sigma)); +} + +/* ************************************************************************* */ +/** + * @brief This function checks descriptor limits + * @param x X Position + * @param y Y Position + * @param width Image width + * @param height Image height + */ +inline void checkDescriptorLimits(int &x, int &y, int width, int height) { + + if (x < 0) { + x = 0; + } + + if (y < 0) { + y = 0; + } + + if (x > width - 1) { + x = width - 1; + } + + if (y > height - 1) { + y = height - 1; + } +} + +#endif diff --git a/modules/xfeatures2d/src/opencl/akaze.cl b/modules/xfeatures2d/src/opencl/akaze.cl new file mode 100644 index 00000000000..40f5c2b59c0 --- /dev/null +++ b/modules/xfeatures2d/src/opencl/akaze.cl @@ -0,0 +1,122 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + + +/** + * @brief This function computes the Perona and Malik conductivity coefficient g2 + * g2 = 1 / (1 + dL^2 / k^2) + * @param lx First order image derivative in X-direction (horizontal) + * @param ly First order image derivative in Y-direction (vertical) + * @param dst Output image + * @param k Contrast factor parameter + */ +__kernel void +AKAZE_pm_g2(__global const float* lx, __global const float* ly, __global float* dst, + float k, int size) +{ + int i = get_global_id(0); + // OpenCV plays with dimensions so we need explicit check for this + if (!(i < size)) + { + return; + } + + const float k2inv = 1.0f / (k * k); + dst[i] = 1.0f / (1.0f + ((lx[i] * lx[i] + ly[i] * ly[i]) * k2inv)); +} + +__kernel void +AKAZE_nld_step_scalar(__global const float* lt, int lt_step, int lt_offset, int rows, int cols, + __global const float* lf, __global float* dst, float step_size) +{ + /* The labeling scheme for this five star stencil: + [ a ] + [ -1 c +1 ] + [ b ] + */ + // column-first indexing + int i = get_global_id(1); + int j = get_global_id(0); + + // OpenCV plays with dimensions so we need explicit check for this + if (!(i < rows && j < cols)) + { + return; + } + + // get row indexes + int a = (i - 1) * cols; + int c = (i ) * cols; + int b = (i + 1) * cols; + // compute stencil + float res = 0.0f; + if (i == 0) // first rows + { + if (j == 0 || j == (cols - 1)) + { + res = 0.0f; + } else + { + res = (lf[c + j] + lf[c + j + 1])*(lt[c + j + 1] - lt[c + j]) + + (lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) + + (lf[c + j] + lf[b + j ])*(lt[b + j ] - lt[c + j]); + } + } else if (i == (rows - 1)) // last row + { + if (j == 0 || j == (cols - 1)) + { + res = 0.0f; + } else + { + res = (lf[c + j] + lf[c + j + 1])*(lt[c + j + 1] - lt[c + j]) + + (lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) + + (lf[c + j] + lf[a + j ])*(lt[a + j ] - lt[c + j]); + } + } else // inner rows + { + if (j == 0) // first column + { + res = (lf[c + 0] + lf[c + 1])*(lt[c + 1] - lt[c + 0]) + + (lf[c + 0] + lf[b + 0])*(lt[b + 0] - lt[c + 0]) + + (lf[c + 0] + lf[a + 0])*(lt[a + 0] - lt[c + 0]); + } else if (j == (cols - 1)) // last column + { + res = (lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) + + (lf[c + j] + lf[b + j ])*(lt[b + j ] - lt[c + j]) + + (lf[c + j] + lf[a + j ])*(lt[a + j ] - lt[c + j]); + } else // inner stencil + { + res = (lf[c + j] + lf[c + j + 1])*(lt[c + j + 1] - lt[c + j]) + + (lf[c + j] + lf[c + j - 1])*(lt[c + j - 1] - lt[c + j]) + + (lf[c + j] + lf[b + j ])*(lt[b + j ] - lt[c + j]) + + (lf[c + j] + lf[a + j ])*(lt[a + j ] - lt[c + j]); + } + } + + dst[c + j] = res * step_size; +} + +/** + * @brief Compute determinant from hessians + * @details Compute Ldet by (Lxx.mul(Lyy) - Lxy.mul(Lxy)) * sigma + * + * @param lxx spatial derivates + * @param lxy spatial derivates + * @param lyy spatial derivates + * @param dst output determinant + * @param sigma determinant will be scaled by this sigma + */ +__kernel void +AKAZE_compute_determinant(__global const float* lxx, __global const float* lxy, __global const float* lyy, + __global float* dst, float sigma, int size) +{ + int i = get_global_id(0); + // OpenCV plays with dimensions so we need explicit check for this + if (!(i < size)) + { + return; + } + + dst[i] = (lxx[i] * lyy[i] - lxy[i] * lxy[i]) * sigma; +} diff --git a/modules/xfeatures2d/src/precomp.hpp b/modules/xfeatures2d/src/precomp.hpp index 376999600bc..92bf4c1badf 100644 --- a/modules/xfeatures2d/src/precomp.hpp +++ b/modules/xfeatures2d/src/precomp.hpp @@ -52,6 +52,7 @@ #include "opencv2/core/private.hpp" #include "opencv2/core/private.cuda.hpp" #include "opencv2/core/ocl.hpp" +#include "opencv2/core/hal/hal.hpp" #include "opencv2/opencv_modules.hpp" diff --git a/modules/xfeatures2d/test/test_agast.cpp b/modules/xfeatures2d/test/test_agast.cpp new file mode 100644 index 00000000000..64fa7507141 --- /dev/null +++ b/modules/xfeatures2d/test/test_agast.cpp @@ -0,0 +1,138 @@ +/*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 "test_precomp.hpp" + +namespace opencv_test { namespace { + +class CV_AgastTest : public cvtest::BaseTest +{ +public: + CV_AgastTest(); + ~CV_AgastTest(); +protected: + void run(int); +}; + +CV_AgastTest::CV_AgastTest() {} +CV_AgastTest::~CV_AgastTest() {} + +void CV_AgastTest::run( int ) +{ + for(int type=0; type <= 2; ++type) { + Mat image1 = imread(string(ts->get_data_path()) + "inpaint/orig.png"); + Mat image2 = imread(string(ts->get_data_path()) + "cameracalibration/chess9.png"); + string xml = string(ts->get_data_path()) + format("agast/result%d.xml", type); + + if (image1.empty() || image2.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat gray1, gray2; + cvtColor(image1, gray1, COLOR_BGR2GRAY); + cvtColor(image2, gray2, COLOR_BGR2GRAY); + + vector keypoints1; + vector keypoints2; + AGAST(gray1, keypoints1, 30, true, static_cast(type)); + AGAST(gray2, keypoints2, (type > 0 ? 30 : 20), true, static_cast(type)); + + for(size_t i = 0; i < keypoints1.size(); ++i) + { + const KeyPoint& kp = keypoints1[i]; + cv::circle(image1, kp.pt, cvRound(kp.size/2), Scalar(255, 0, 0)); + } + + for(size_t i = 0; i < keypoints2.size(); ++i) + { + const KeyPoint& kp = keypoints2[i]; + cv::circle(image2, kp.pt, cvRound(kp.size/2), Scalar(255, 0, 0)); + } + + Mat kps1(1, (int)(keypoints1.size() * sizeof(KeyPoint)), CV_8U, &keypoints1[0]); + Mat kps2(1, (int)(keypoints2.size() * sizeof(KeyPoint)), CV_8U, &keypoints2[0]); + + FileStorage fs(xml, FileStorage::READ); + if (!fs.isOpened()) + { + fs.open(xml, FileStorage::WRITE); + if (!fs.isOpened()) + { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + return; + } + fs << "exp_kps1" << kps1; + fs << "exp_kps2" << kps2; + fs.release(); + fs.open(xml, FileStorage::READ); + if (!fs.isOpened()) + { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + return; + } + } + + Mat exp_kps1, exp_kps2; + read( fs["exp_kps1"], exp_kps1, Mat() ); + read( fs["exp_kps2"], exp_kps2, Mat() ); + fs.release(); + + if ( exp_kps1.size != kps1.size || 0 != cvtest::norm(exp_kps1, kps1, NORM_L2) || + exp_kps2.size != kps2.size || 0 != cvtest::norm(exp_kps2, kps2, NORM_L2)) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return; + } + + /*cv::namedWindow("Img1"); cv::imshow("Img1", image1); + cv::namedWindow("Img2"); cv::imshow("Img2", image2); + cv::waitKey(0);*/ + } + + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Features2d_AGAST, regression) { CV_AgastTest test; test.safe_run(); } + +}} // namespace diff --git a/modules/xfeatures2d/test/test_akaze.cpp b/modules/xfeatures2d/test/test_akaze.cpp new file mode 100644 index 00000000000..aafa8a75458 --- /dev/null +++ b/modules/xfeatures2d/test/test_akaze.cpp @@ -0,0 +1,48 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#include "test_precomp.hpp" + +namespace opencv_test { namespace { + +TEST(Features2d_AKAZE, detect_and_compute_split) +{ + Mat testImg(100, 100, CV_8U); + RNG rng(101); + rng.fill(testImg, RNG::UNIFORM, Scalar(0), Scalar(255), true); + + Ptr ext = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.001f, 1, 1, KAZE::DIFF_PM_G2); + vector detAndCompKps; + Mat desc; + ext->detectAndCompute(testImg, noArray(), detAndCompKps, desc); + + vector detKps; + ext->detect(testImg, detKps); + + ASSERT_EQ(detKps.size(), detAndCompKps.size()); + + for(size_t i = 0; i < detKps.size(); i++) + ASSERT_EQ(detKps[i].hash(), detAndCompKps[i].hash()); +} + +/** + * This test is here to guard propagation of NaNs that happens on this image. NaNs are guarded + * by debug asserts in AKAZE, which should fire for you if you are lucky. + * + * This test also reveals problems with uninitialized memory that happens only on this image. + * This is very hard to hit and depends a lot on particular allocator. Run this test in valgrind and check + * for uninitialized values if you think you are hitting this problem again. + */ +TEST(Features2d_AKAZE, uninitialized_and_nans) +{ + Mat b1 = imread(cvtest::TS::ptr()->get_data_path() + "../stitching/b1.png"); + ASSERT_FALSE(b1.empty()); + + vector keypoints; + Mat desc; + Ptr akaze = AKAZE::create(); + akaze->detectAndCompute(b1, noArray(), keypoints, desc); +} + +}} // namespace diff --git a/modules/xfeatures2d/test/test_brisk.cpp b/modules/xfeatures2d/test/test_brisk.cpp new file mode 100644 index 00000000000..783b694f894 --- /dev/null +++ b/modules/xfeatures2d/test/test_brisk.cpp @@ -0,0 +1,108 @@ +/*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 "test_precomp.hpp" + +namespace opencv_test { namespace { + +class CV_BRISKTest : public cvtest::BaseTest +{ +public: + CV_BRISKTest(); + ~CV_BRISKTest(); +protected: + void run(int); +}; + +CV_BRISKTest::CV_BRISKTest() {} +CV_BRISKTest::~CV_BRISKTest() {} + +void CV_BRISKTest::run( int ) +{ + Mat image1 = imread(string(ts->get_data_path()) + "inpaint/orig.png"); + Mat image2 = imread(string(ts->get_data_path()) + "cameracalibration/chess9.png"); + + if (image1.empty() || image2.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat gray1, gray2; + cvtColor(image1, gray1, COLOR_BGR2GRAY); + cvtColor(image2, gray2, COLOR_BGR2GRAY); + + Ptr detector = BRISK::create(); + + // Check parameter get/set functions. + BRISK* detectorTyped = dynamic_cast(detector.get()); + ASSERT_NE(nullptr, detectorTyped); + detectorTyped->setOctaves(3); + detectorTyped->setThreshold(30); + ASSERT_EQ(detectorTyped->getOctaves(), 3); + ASSERT_EQ(detectorTyped->getThreshold(), 30); + detectorTyped->setOctaves(4); + detectorTyped->setThreshold(29); + ASSERT_EQ(detectorTyped->getOctaves(), 4); + ASSERT_EQ(detectorTyped->getThreshold(), 29); + + vector keypoints1; + vector keypoints2; + detector->detect(image1, keypoints1); + detector->detect(image2, keypoints2); + + for(size_t i = 0; i < keypoints1.size(); ++i) + { + const KeyPoint& kp = keypoints1[i]; + ASSERT_NE(kp.angle, -1); + } + + for(size_t i = 0; i < keypoints2.size(); ++i) + { + const KeyPoint& kp = keypoints2[i]; + ASSERT_NE(kp.angle, -1); + } +} + +TEST(Features2d_BRISK, regression) { CV_BRISKTest test; test.safe_run(); } + +}} // namespace diff --git a/modules/xfeatures2d/test/test_feature2d.ocl.cpp b/modules/xfeatures2d/test/test_feature2d.ocl.cpp new file mode 100644 index 00000000000..82af75961a1 --- /dev/null +++ b/modules/xfeatures2d/test/test_feature2d.ocl.cpp @@ -0,0 +1,73 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#include "test_precomp.hpp" +#include "cvconfig.h" +#include "opencv2/ts/ocl_test.hpp" +#include + +#ifdef HAVE_OPENCL + +namespace opencv_test { +namespace ocl { + +#define TEST_IMAGES testing::Values(\ + "detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\ + "../stitching/a3.png", \ + "../stitching/s2.jpg") + +PARAM_TEST_CASE(Feature2DFixture, std::function()>, std::string) +{ + std::string filename; + Mat image, descriptors; + vector keypoints; + UMat uimage, udescriptors; + vector ukeypoints; + Ptr feature; + + virtual void SetUp() + { + feature = GET_PARAM(0)(); + filename = GET_PARAM(1); + + image = readImage(filename); + + ASSERT_FALSE(image.empty()); + + image.copyTo(uimage); + + OCL_OFF(feature->detect(image, keypoints)); + OCL_ON(feature->detect(uimage, ukeypoints)); + // note: we use keypoints from CPU for GPU too, to test descriptors separately + OCL_OFF(feature->compute(image, keypoints, descriptors)); + OCL_ON(feature->compute(uimage, keypoints, udescriptors)); + } +}; + +OCL_TEST_P(Feature2DFixture, KeypointsSame) +{ + EXPECT_EQ(keypoints.size(), ukeypoints.size()); + + for (size_t i = 0; i < keypoints.size(); ++i) + { + EXPECT_GE(KeyPoint::overlap(keypoints[i], ukeypoints[i]), 0.95); + EXPECT_NEAR(keypoints[i].angle, ukeypoints[i].angle, 0.05); + } +} + +OCL_TEST_P(Feature2DFixture, DescriptorsSame) +{ + EXPECT_MAT_NEAR(descriptors, udescriptors, 0.001); +} + +OCL_INSTANTIATE_TEST_CASE_P(AKAZE, Feature2DFixture, + testing::Combine(testing::Values([]() { return AKAZE::create(); }), TEST_IMAGES)); + +OCL_INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, Feature2DFixture, + testing::Combine(testing::Values([]() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }), TEST_IMAGES)); + +}//ocl +}//cvtest + +#endif //HAVE_OPENCL diff --git a/modules/xfeatures2d/test/test_features2d.cpp b/modules/xfeatures2d/test/test_features2d.cpp index 4a10fdebc7f..429470a767b 100644 --- a/modules/xfeatures2d/test/test_features2d.cpp +++ b/modules/xfeatures2d/test/test_features2d.cpp @@ -91,6 +91,36 @@ TEST(Features2d_Detector_TBMR_Affine, regression) test.safe_run(); } +TEST( Features2d_Detector_BRISK, regression ) +{ + CV_FeatureDetectorTest test( "detector-brisk", BRISK::create() ); + test.safe_run(); +} + +TEST( Features2d_Detector_AGAST, regression ) +{ + CV_FeatureDetectorTest test( "detector-agast", AgastFeatureDetector::create() ); + test.safe_run(); +} + +TEST( Features2d_Detector_KAZE, regression ) +{ + CV_FeatureDetectorTest test( "detector-kaze", KAZE::create() ); + test.safe_run(); +} + +TEST( Features2d_Detector_AKAZE, regression ) +{ + CV_FeatureDetectorTest test( "detector-akaze", AKAZE::create() ); + test.safe_run(); +} + +TEST( Features2d_Detector_AKAZE_DESCRIPTOR_KAZE, regression ) +{ + CV_FeatureDetectorTest test( "detector-akaze-with-kaze-desc", AKAZE::create(AKAZE::DESCRIPTOR_KAZE) ); + test.safe_run(); +} + /* * Descriptors */ @@ -199,6 +229,39 @@ TEST(Features2d_DescriptorExtractor_TEBLID, regression ) test.safe_run(); } +TEST( Features2d_DescriptorExtractor_BRISK, regression ) +{ + CV_DescriptorExtractorTest test( "descriptor-brisk", + (CV_DescriptorExtractorTest::DistanceType)2.f, + BRISK::create() ); + test.safe_run(); +} + +TEST( Features2d_DescriptorExtractor_KAZE, regression ) +{ + CV_DescriptorExtractorTest< L2 > test( "descriptor-kaze", 0.03f, + KAZE::create(), + L2(), KAZE::create() ); + test.safe_run(); +} + +TEST( Features2d_DescriptorExtractor_AKAZE, regression ) +{ + CV_DescriptorExtractorTest test( "descriptor-akaze", + (CV_DescriptorExtractorTest::DistanceType)(486*0.05f), + AKAZE::create(), + Hamming(), AKAZE::create()); + test.safe_run(); +} + +TEST( Features2d_DescriptorExtractor_AKAZE_DESCRIPTOR_KAZE, regression ) +{ + CV_DescriptorExtractorTest< L2 > test( "descriptor-akaze-with-kaze-desc", 0.03f, + AKAZE::create(AKAZE::DESCRIPTOR_KAZE), + L2(), AKAZE::create(AKAZE::DESCRIPTOR_KAZE)); + test.safe_run(); +} + #ifdef OPENCV_XFEATURES2D_HAS_VGG_DATA TEST( Features2d_DescriptorExtractor_VGG, regression ) { @@ -318,6 +381,70 @@ TEST(Features2d_BruteForceDescriptorMatcher_knnMatch, regression) } #endif +class DescriptorImage : public TestWithParam +{ +protected: + virtual void SetUp() { + pattern = GetParam(); + } + + std::string pattern; +}; + +TEST_P(DescriptorImage, no_crash) +{ + vector fnames; + glob(cvtest::TS::ptr()->get_data_path() + pattern, fnames, false); + std::sort(fnames.begin(), fnames.end()); + + Ptr akaze_mldb = AKAZE::create(AKAZE::DESCRIPTOR_MLDB); + Ptr akaze_mldb_upright = AKAZE::create(AKAZE::DESCRIPTOR_MLDB_UPRIGHT); + Ptr akaze_mldb_256 = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 256); + Ptr akaze_mldb_upright_256 = AKAZE::create(AKAZE::DESCRIPTOR_MLDB_UPRIGHT, 256); + Ptr akaze_kaze = AKAZE::create(AKAZE::DESCRIPTOR_KAZE); + Ptr akaze_kaze_upright = AKAZE::create(AKAZE::DESCRIPTOR_KAZE_UPRIGHT); + Ptr kaze = KAZE::create(); + Ptr brisk = BRISK::create(); + size_t n = fnames.size(); + vector keypoints; + Mat descriptors; + + for(size_t i = 0; i < n; i++ ) + { + printf("%d. image: %s:\n", (int)i, fnames[i].c_str()); + if( strstr(fnames[i].c_str(), "MP.png") != 0 ) + { + printf("\tskip\n"); + continue; + } + bool checkCount = strstr(fnames[i].c_str(), "templ.png") == 0; + + Mat img = imread(fnames[i], -1); + + printf("\t%dx%d\n", img.cols, img.rows); + +#define TEST_DETECTOR(name, descriptor) \ + keypoints.clear(); descriptors.release(); \ + printf("\t" name "\n"); fflush(stdout); \ + descriptor->detectAndCompute(img, noArray(), keypoints, descriptors); \ + printf("\t\t\t(%d keypoints, descriptor size = %d)\n", (int)keypoints.size(), descriptors.cols); fflush(stdout); \ + if (checkCount) \ + { \ + EXPECT_GT((int)keypoints.size(), 0); \ + } \ + ASSERT_EQ(descriptors.rows, (int)keypoints.size()); + + TEST_DETECTOR("AKAZE:MLDB", akaze_mldb); + TEST_DETECTOR("AKAZE:MLDB_UPRIGHT", akaze_mldb_upright); + TEST_DETECTOR("AKAZE:MLDB_256", akaze_mldb_256); + TEST_DETECTOR("AKAZE:MLDB_UPRIGHT_256", akaze_mldb_upright_256); + TEST_DETECTOR("AKAZE:KAZE", akaze_kaze); + TEST_DETECTOR("AKAZE:KAZE_UPRIGHT", akaze_kaze_upright); + TEST_DETECTOR("KAZE", kaze); + TEST_DETECTOR("BRISK", brisk); + } +} + class CV_DetectPlanarTest : public cvtest::BaseTest { public: diff --git a/modules/xfeatures2d/test/test_keypoints.cpp b/modules/xfeatures2d/test/test_keypoints.cpp index 5b296b2f41c..d673b1db69d 100644 --- a/modules/xfeatures2d/test/test_keypoints.cpp +++ b/modules/xfeatures2d/test/test_keypoints.cpp @@ -145,4 +145,31 @@ TEST(Features2d_Detector_Keypoints_TBMRDetector, validation) test.safe_run(); } +TEST(Features2d_Detector_Keypoints_BRISK, validation) +{ + CV_FeatureDetectorKeypointsTest test(BRISK::create()); + test.safe_run(); +} + +TEST(Features2d_Detector_Keypoints_AGAST, validation) +{ + CV_FeatureDetectorKeypointsTest test(AgastFeatureDetector::create()); + test.safe_run(); +} + +TEST(Features2d_Detector_Keypoints_KAZE, validation) +{ + CV_FeatureDetectorKeypointsTest test(KAZE::create()); + test.safe_run(); +} + +TEST(Features2d_Detector_Keypoints_AKAZE, validation) +{ + CV_FeatureDetectorKeypointsTest test_kaze(AKAZE::create(AKAZE::DESCRIPTOR_KAZE)); + test_kaze.safe_run(); + + CV_FeatureDetectorKeypointsTest test_mldb(AKAZE::create(AKAZE::DESCRIPTOR_MLDB)); + test_mldb.safe_run(); +} + }} // namespace diff --git a/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp b/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp index ce7281d6c06..68b5105ae0f 100644 --- a/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp +++ b/modules/xfeatures2d/test/test_rotation_and_scale_invariance.cpp @@ -26,6 +26,33 @@ INSTANTIATE_TEST_CASE_P(SURF, DescriptorRotationInvariance, Values( #endif // NONFREE +INSTANTIATE_TEST_CASE_P(BRISK, DetectorRotationInvariance, Values( + make_tuple(IMAGE_TSUKUBA, []() { return BRISK::create(); }, 0.45f, 0.76f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE, DetectorRotationInvariance, Values( + make_tuple(IMAGE_TSUKUBA, []() { return AKAZE::create(); }, 0.5f, 0.71f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DetectorRotationInvariance, Values( + make_tuple(IMAGE_TSUKUBA, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, 0.5f, 0.71f) +)); + +INSTANTIATE_TEST_CASE_P(BRISK, DescriptorRotationInvariance, Values( + make_tuple(IMAGE_TSUKUBA, []() { return BRISK::create(); }, []() { return BRISK::create(); }, 0.99f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE, DescriptorRotationInvariance, Values( + make_tuple(IMAGE_TSUKUBA, []() { return AKAZE::create(); }, []() { return AKAZE::create();} , 0.99f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DescriptorRotationInvariance, Values( + make_tuple(IMAGE_TSUKUBA, + []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, + []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, + 0.99f) +)); + INSTANTIATE_TEST_CASE_P(LATCH, DescriptorRotationInvariance, Values( make_tuple(IMAGE_TSUKUBA, []() { return SIFT::create(); }, []() { return LATCH::create(); }, 0.98f) )); @@ -35,7 +62,7 @@ INSTANTIATE_TEST_CASE_P(BEBLID, DescriptorRotationInvariance, Values( )); INSTANTIATE_TEST_CASE_P(TEBLID, DescriptorRotationInvariance, Values( - make_tuple(IMAGE_TSUKUBA, []() { return SIFT::create(); }, []() { return TEBLID::create(6.75); }, 0.98f) + make_tuple(IMAGE_TSUKUBA, []() { return SIFT::create(); }, []() { return TEBLID::create(6.75); }, 0.98f) )); INSTANTIATE_TEST_CASE_P(DAISY, DescriptorRotationInvariance, Values( @@ -44,6 +71,7 @@ INSTANTIATE_TEST_CASE_P(DAISY, DescriptorRotationInvariance, Values( []() { return DAISY::create(15, 3, 8, 8, DAISY::NRM_NONE, noArray(), true, true); }, 0.79f) )); + #ifdef OPENCV_XFEATURES2D_HAS_VGG_DATA INSTANTIATE_TEST_CASE_P(VGG120, DescriptorRotationInvariance, Values( make_tuple(IMAGE_TSUKUBA, @@ -177,6 +205,33 @@ INSTANTIATE_TEST_CASE_P(DISABLED_DAISY, DescriptorScaleInvariance, Values( )); #endif +INSTANTIATE_TEST_CASE_P(BRISK, DetectorScaleInvariance, Values( + make_tuple(IMAGE_BIKES, []() { return BRISK::create(); }, 0.08f, 0.49f) +)); + +INSTANTIATE_TEST_CASE_P(KAZE, DetectorScaleInvariance, Values( + make_tuple(IMAGE_BIKES, []() { return KAZE::create(); }, 0.08f, 0.49f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE, DetectorScaleInvariance, Values( + make_tuple(IMAGE_BIKES, []() { return AKAZE::create(); }, 0.08f, 0.49f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DetectorScaleInvariance, Values( + make_tuple(IMAGE_BIKES, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, 0.08f, 0.49f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE, DescriptorScaleInvariance, Values( + make_tuple(IMAGE_BIKES, []() { return AKAZE::create(); }, []() { return AKAZE::create(); }, 0.6f) +)); + +INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DescriptorScaleInvariance, Values( + make_tuple(IMAGE_BIKES, + []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, + []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, + 0.55f) +)); + #ifdef OPENCV_XFEATURES2D_HAS_VGG_DATA INSTANTIATE_TEST_CASE_P(VGG120, DescriptorScaleInvariance, Values( make_tuple(IMAGE_BIKES, diff --git a/modules/xfeatures2d/tutorials/py_brief/py_brief.markdown b/modules/xfeatures2d/tutorials/py_brief/py_brief.markdown new file mode 100644 index 00000000000..8b7e66ea608 --- /dev/null +++ b/modules/xfeatures2d/tutorials/py_brief/py_brief.markdown @@ -0,0 +1,92 @@ +BRIEF (Binary Robust Independent Elementary Features) {#tutorial_py_brief} +===================================================== + +Goal +---- + +In this chapter + - We will see the basics of BRIEF algorithm + +Theory +------ + +We know SIFT uses 128-dim vector for descriptors. Since it is using floating point numbers, it takes +basically 512 bytes. Similarly SURF also takes minimum of 256 bytes (for 64-dim). Creating such a +vector for thousands of features takes a lot of memory which are not feasible for resource-constraint +applications especially for embedded systems. Larger the memory, longer the time it takes for +matching. + +But all these dimensions may not be needed for actual matching. We can compress it using several +methods like PCA, LDA etc. Even other methods like hashing using LSH (Locality Sensitive Hashing) is +used to convert these SIFT descriptors in floating point numbers to binary strings. These binary +strings are used to match features using Hamming distance. This provides better speed-up because +finding hamming distance is just applying XOR and bit count, which are very fast in modern CPUs with +SSE instructions. But here, we need to find the descriptors first, then only we can apply hashing, +which doesn't solve our initial problem on memory. + +BRIEF comes into picture at this moment. It provides a shortcut to find the binary strings directly +without finding descriptors. It takes smoothened image patch and selects a set of \f$n_d\f$ (x,y) +location pairs in an unique way (explained in paper). Then some pixel intensity comparisons are done +on these location pairs. For eg, let first location pairs be \f$p\f$ and \f$q\f$. If \f$I(p) < I(q)\f$, then its +result is 1, else it is 0. This is applied for all the \f$n_d\f$ location pairs to get a +\f$n_d\f$-dimensional bitstring. + +This \f$n_d\f$ can be 128, 256 or 512. OpenCV supports all of these, but by default, it would be 256 +(OpenCV represents it in bytes. So the values will be 16, 32 and 64). So once you get this, you can +use Hamming Distance to match these descriptors. + +One important point is that BRIEF is a feature descriptor, it doesn't provide any method to find the +features. So you will have to use any other feature detectors like SIFT, SURF etc. The paper +recommends to use CenSurE which is a fast detector and BRIEF works even slightly better for CenSurE +points than for SURF points. + +In short, BRIEF is a faster method feature descriptor calculation and matching. It also provides +high recognition rate unless there is large in-plane rotation. + +STAR(CenSurE) in OpenCV +------ +STAR is a feature detector derived from CenSurE. +Unlike CenSurE however, which uses polygons like squares, hexagons and octagons to approach a circle, +Star emulates a circle with 2 overlapping squares: 1 upright and 1 45-degree rotated. These polygons are bi-level. +They can be seen as polygons with thick borders. The borders and the enclosed area have weights of opposing signs. +This has better computational characteristics than other scale-space detectors and it is capable of real-time implementation. +In contrast to SIFT and SURF, which find extrema at sub-sampled pixels that compromises accuracy at larger scales, +CenSurE creates a feature vector using full spatial resolution at all scales in the pyramid. +BRIEF in OpenCV +--------------- + +Below code shows the computation of BRIEF descriptors with the help of CenSurE detector. + +note, that you need [opencv contrib](https://github.com/opencv/opencv_contrib) to use this. +@code{.py} +import numpy as np +import cv2 as cv +from matplotlib import pyplot as plt + +img = cv.imread('simple.jpg', cv.IMREAD_GRAYSCALE) + +# Initiate FAST detector +star = cv.xfeatures2d.StarDetector_create() + +# Initiate BRIEF extractor +brief = cv.xfeatures2d.BriefDescriptorExtractor_create() + +# find the keypoints with STAR +kp = star.detect(img,None) + +# compute the descriptors with BRIEF +kp, des = brief.compute(img, kp) + +print( brief.descriptorSize() ) +print( des.shape ) +@endcode +The function brief.getDescriptorSize() gives the \f$n_d\f$ size used in bytes. By default it is 32. Next one +is matching, which will be done in another chapter. + +Additional Resources +-------------------- + +-# Michael Calonder, Vincent Lepetit, Christoph Strecha, and Pascal Fua, "BRIEF: Binary Robust + Independent Elementary Features", 11th European Conference on Computer Vision (ECCV), Heraklion, + Crete. LNCS Springer, September 2010. +2. [LSH (Locality Sensitive Hashing)](https://en.wikipedia.org/wiki/Locality-sensitive_hashing) at wikipedia. diff --git a/modules/xfeatures2d/tutorials/py_surf_intro/images/surf_boxfilter.jpg b/modules/xfeatures2d/tutorials/py_surf_intro/images/surf_boxfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2f63d1d5d85504743fe19864135aefba44e7ec1a GIT binary patch literal 12995 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 literal 0 HcmV?d00001 diff --git a/modules/xfeatures2d/tutorials/py_surf_intro/images/surf_kp1.jpg b/modules/xfeatures2d/tutorials/py_surf_intro/images/surf_kp1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9193e85f9a010ce15dd6a1901f0aad1782f1e721 GIT binary patch literal 27166 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 CCQ}9g literal 0 HcmV?d00001 diff --git a/modules/xfeatures2d/tutorials/py_surf_intro/images/surf_kp2.jpg b/modules/xfeatures2d/tutorials/py_surf_intro/images/surf_kp2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05673bd4aecddabfa0399fd5c8a0344178c10ef0 GIT binary patch literal 28476 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 I0Q3330O)j2zW@LL literal 0 HcmV?d00001 diff --git a/modules/xfeatures2d/tutorials/py_surf_intro/py_surf_intro.markdown b/modules/xfeatures2d/tutorials/py_surf_intro/py_surf_intro.markdown new file mode 100644 index 00000000000..5bcd91cce8d --- /dev/null +++ b/modules/xfeatures2d/tutorials/py_surf_intro/py_surf_intro.markdown @@ -0,0 +1,163 @@ +Introduction to SURF (Speeded-Up Robust Features) {#tutorial_py_surf_intro} +================================================= + +Goal +---- + +In this chapter, + - We will see the basics of SURF + - We will see SURF functionalities in OpenCV + +Theory +------ + +In last chapter, we saw SIFT for keypoint detection and description. But it was comparatively slow +and people needed more speeded-up version. In 2006, three people, Bay, H., Tuytelaars, T. and Van +Gool, L, published another paper, "SURF: Speeded Up Robust Features" which introduced a new +algorithm called SURF. As name suggests, it is a speeded-up version of SIFT. + +In SIFT, Lowe approximated Laplacian of Gaussian with Difference of Gaussian for finding +scale-space. SURF goes a little further and approximates LoG with Box Filter. Below image shows a +demonstration of such an approximation. One big advantage of this approximation is that, convolution +with box filter can be easily calculated with the help of integral images. And it can be done in +parallel for different scales. Also the SURF rely on determinant of Hessian matrix for both scale +and location. + +![image](images/surf_boxfilter.jpg) + +For orientation assignment, SURF uses wavelet responses in horizontal and vertical direction for a +neighbourhood of size 6s. Adequate gaussian weights are also applied to it. Then they are plotted in +a space as given in below image. The dominant orientation is estimated by calculating the sum of all +responses within a sliding orientation window of angle 60 degrees. Interesting thing is that, +wavelet response can be found out using integral images very easily at any scale. For many +applications, rotation invariance is not required, so no need of finding this orientation, which +speeds up the process. SURF provides such a functionality called Upright-SURF or U-SURF. It improves +speed and is robust upto \f$\pm 15^{\circ}\f$. OpenCV supports both, depending upon the flag, +**upright**. If it is 0, orientation is calculated. If it is 1, orientation is not calculated and it +is faster. + +![image](images/surf_orientation.jpg) + +For feature description, SURF uses Wavelet responses in horizontal and vertical direction (again, +use of integral images makes things easier). A neighbourhood of size 20sX20s is taken around the +keypoint where s is the size. It is divided into 4x4 subregions. For each subregion, horizontal and +vertical wavelet responses are taken and a vector is formed like this, +\f$v=( \sum{d_x}, \sum{d_y}, \sum{|d_x|}, \sum{|d_y|})\f$. This when represented as a vector gives SURF +feature descriptor with total 64 dimensions. Lower the dimension, higher the speed of computation +and matching, but provide better distinctiveness of features. + +For more distinctiveness, SURF feature descriptor has an extended 128 dimension version. The sums of +\f$d_x\f$ and \f$|d_x|\f$ are computed separately for \f$d_y < 0\f$ and \f$d_y \geq 0\f$. Similarly, the sums of +\f$d_y\f$ and \f$|d_y|\f$ are split up according to the sign of \f$d_x\f$ , thereby doubling the number of +features. It doesn't add much computation complexity. OpenCV supports both by setting the value of +flag **extended** with 0 and 1 for 64-dim and 128-dim respectively (default is 128-dim) + +Another important improvement is the use of sign of Laplacian (trace of Hessian Matrix) for +underlying interest point. It adds no computation cost since it is already computed during +detection. The sign of the Laplacian distinguishes bright blobs on dark backgrounds from the reverse +situation. In the matching stage, we only compare features if they have the same type of contrast +(as shown in image below). This minimal information allows for faster matching, without reducing the +descriptor's performance. + +![image](images/surf_matching.jpg) + +In short, SURF adds a lot of features to improve the speed in every step. Analysis shows it is 3 +times faster than SIFT while performance is comparable to SIFT. SURF is good at handling images with +blurring and rotation, but not good at handling viewpoint change and illumination change. + +SURF in OpenCV +-------------- + +OpenCV provides SURF functionalities just like SIFT. You initiate a SURF object with some optional +conditions like 64/128-dim descriptors, Upright/Normal SURF etc. All the details are well explained +in docs. Then as we did in SIFT, we can use SURF.detect(), SURF.compute() etc for finding keypoints +and descriptors. + +First we will see a simple demo on how to find SURF keypoints and descriptors and draw it. All +examples are shown in Python terminal since it is just same as SIFT only. +@code{.py} +>>> img = cv.imread('fly.png', cv.IMREAD_GRAYSCALE) + +# Create SURF object. You can specify params here or later. +# Here I set Hessian Threshold to 400 +>>> surf = cv.xfeatures2d.SURF_create(400) + +# Find keypoints and descriptors directly +>>> kp, des = surf.detectAndCompute(img,None) + +>>> len(kp) + 699 +@endcode +1199 keypoints is too much to show in a picture. We reduce it to some 50 to draw it on an image. +While matching, we may need all those features, but not now. So we increase the Hessian Threshold. +@code{.py} +# Check present Hessian threshold +>>> print( surf.getHessianThreshold() ) +400.0 + +# We set it to some 50000. Remember, it is just for representing in picture. +# In actual cases, it is better to have a value 300-500 +>>> surf.setHessianThreshold(50000) + +# Again compute keypoints and check its number. +>>> kp, des = surf.detectAndCompute(img,None) + +>>> print( len(kp) ) +47 +@endcode +It is less than 50. Let's draw it on the image. +@code{.py} +>>> img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4) + +>>> plt.imshow(img2),plt.show() +@endcode +See the result below. You can see that SURF is more like a blob detector. It detects the white blobs +on wings of butterfly. You can test it with other images. + +![image](images/surf_kp1.jpg) + +Now I want to apply U-SURF, so that it won't find the orientation. +@code{.py} +# Check upright flag, if it False, set it to True +>>> print( surf.getUpright() ) +False + +>>> surf.setUpright(True) + +# Recompute the feature points and draw it +>>> kp = surf.detect(img,None) +>>> img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4) + +>>> plt.imshow(img2),plt.show() +@endcode +See the results below. All the orientations are shown in same direction. It is faster than +previous. If you are working on cases where orientation is not a problem (like panorama stitching) +etc, this is better. + +![image](images/surf_kp2.jpg) + +Finally we check the descriptor size and change it to 128 if it is only 64-dim. +@code{.py} +# Find size of descriptor +>>> print( surf.descriptorSize() ) +64 + +# That means flag, "extended" is False. +>>> surf.getExtended() + False + +# So we make it to True to get 128-dim descriptors. +>>> surf.setExtended(True) +>>> kp, des = surf.detectAndCompute(img,None) +>>> print( surf.descriptorSize() ) +128 +>>> print( des.shape ) +(47, 128) +@endcode +Remaining part is matching which we will do in another chapter. + +Additional Resources +-------------------- + +Exercises +--------- diff --git a/modules/xfeatures2d/tutorials/table_of_content_xfeatures2d.markdown b/modules/xfeatures2d/tutorials/table_of_content_xfeatures2d.markdown new file mode 100644 index 00000000000..53f52c85444 --- /dev/null +++ b/modules/xfeatures2d/tutorials/table_of_content_xfeatures2d.markdown @@ -0,0 +1,15 @@ +Feature Detection and Description (xfeatures module) {#tutorial_table_of_content_xfeatures2d} +============================================================================================= + +- @subpage tutorial_py_surf_intro + + SIFT is really good, + but not fast enough, so people came up with a speeded-up version called SURF. + +- @subpage tutorial_py_brief + + SIFT uses a feature + descriptor with 128 floating point numbers. Consider thousands of such features. It takes lots of + memory and more time for matching. We can compress it to make it faster. But still we have to + calculate it first. There comes BRIEF which gives the shortcut to find binary descriptors with + less memory, faster matching, still higher recognition rate. \ No newline at end of file