diff --git a/modules/flann/src/miniflann.cpp b/modules/flann/src/miniflann.cpp index 30e193b5cd..443c705b5d 100644 --- a/modules/flann/src/miniflann.cpp +++ b/modules/flann/src/miniflann.cpp @@ -663,33 +663,51 @@ int Index::radiusSearch(InputArray _query, OutputArray _indices, if( algo == FLANN_INDEX_LSH ) CV_Error( Error::StsNotImplemented, "LSH index does not support radiusSearch operation" ); + int rsearch_ret; switch( distType ) { case FLANN_DIST_HAMMING: - return runRadiusSearch< HammingDistance >(index, query, indices, dists, radius, params); - + rsearch_ret = runRadiusSearch< HammingDistance >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_L2: - return runRadiusSearch< ::cvflann::L2 >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::L2 >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_L1: - return runRadiusSearch< ::cvflann::L1 >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::L1 >(index, query, indices, dists, radius, params); + break; #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES case FLANN_DIST_DNAMMING: - return runRadiusSearch< DNAmmingDistance >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< DNAmmingDistance >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_MAX: - return runRadiusSearch< ::cvflann::MaxDistance >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::MaxDistance >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_HIST_INTERSECT: - return runRadiusSearch< ::cvflann::HistIntersectionDistance >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::HistIntersectionDistance >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_HELLINGER: - return runRadiusSearch< ::cvflann::HellingerDistance >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::HellingerDistance >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_CHI_SQUARE: - return runRadiusSearch< ::cvflann::ChiSquareDistance >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::ChiSquareDistance >(index, query, indices, dists, radius, params); + break; case FLANN_DIST_KL: - return runRadiusSearch< ::cvflann::KL_Divergence >(index, query, indices, dists, radius, params); + rsearch_ret = runRadiusSearch< ::cvflann::KL_Divergence >(index, query, indices, dists, radius, params); + break; #endif default: CV_Error(Error::StsBadArg, "Unknown/unsupported distance type"); + return -1; } - return -1; + if (rsearch_ret > maxResults) + rsearch_ret = maxResults; + if (rsearch_ret < maxResults) { + if (_indices.needed()) + indices.colRange(0, rsearch_ret).copyTo(_indices); + if (_dists.needed()) + dists.colRange(0, rsearch_ret).copyTo(_dists); + } + return rsearch_ret; } flann_distance_t Index::getDistance() const diff --git a/modules/flann/test/test_radius_search.cpp b/modules/flann/test/test_radius_search.cpp new file mode 100644 index 0000000000..5973a2380e --- /dev/null +++ b/modules/flann/test/test_radius_search.cpp @@ -0,0 +1,81 @@ +// 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 { + +// Regression test: radiusSearch returned nn < maxResults but left the output +// vectors sized to maxResults, so nn != indices.size() and nn > maxResults +// could both occur for queries with fewer actual neighbors than maxResults. +TEST(Flann_Index, radiusSearch_output_size_matches_returned_count) +{ + std::vector corners = { + {3679.83f,1857.22f},{3324.43f,1850.67f},{3278.83f,1502.32f},{3621.32f,1508.69f}, + {3662.26f,1837.97f},{3336.06f,1839.28f},{3291.74f,1516.03f},{3608.94f,1518.72f}, + {2980.66f,1843.22f},{2628.11f,1837.14f},{2607.73f,1491.57f},{2948.22f,1496.76f}, + {2289.31f,1830.19f},{1943.99f,1824.17f},{1945.51f,1482.34f},{2280.68f,1487.39f}, + {1607.47f,1819.11f},{1260.04f,1813.26f},{1283.94f,1470.34f},{1620.03f,1475.85f}, + {923.063f,1808.08f},{576.193f,1802.4f},{624.713f,1459.78f},{959.715f,1464.93f}, + {3270.25f,1494.98f},{2952.95f,1492.19f},{2922.75f,1190.02f},{3231.05f,1194.81f}, + {3284.82f,1507.62f},{2942.74f,1502.59f},{2912.32f,1178.33f},{3242.98f,1183.19f}, + {2612.82f,1496.37f},{2276.44f,1491.63f},{2267.61f,1170.13f},{2593.64f,1174.43f}, + {1949.73f,1486.61f},{1614.92f,1480.64f},{1626.77f,1160.34f},{1952.0f,1165.51f}, + {1289.38f,1476.21f},{953.709f,1470.21f},{986.779f,1148.92f},{1311.98f,1154.89f}, + {3567.28f,1195.1f},{3237.51f,1189.03f},{3197.63f,884.15f},{3518.61f,888.76f}, + {2918.31f,1183.62f},{2588.69f,1179.37f},{2570.64f,875.672f},{2889.87f,878.902f}, + {2271.97f,1174.25f},{1947.62f,1169.61f},{1948.56f,868.197f},{2263.8f,872.533f}, + {1630.99f,1164.6f},{1306.74f,1159.52f},{1327.81f,858.358f},{1642.69f,862.765f}, + {992.896f,1155.52f},{666.107f,1149.96f},{705.246f,845.776f},{1023.25f,851.582f}, + {3204.48f,889.981f},{2883.49f,885.252f},{2859.31f,593.752f},{3175.43f,594.736f}, + {2575.86f,880.331f},{2259.44f,876.647f},{2252.33f,589.235f},{2560.47f,592.332f}, + {1954.36f,873.708f},{1636.7f,868.068f},{1646.93f,580.76f},{1956.14f,584.797f}, + {1332.02f,862.624f},{1017.11f,856.71f},{1045.32f,572.178f},{1350.95f,577.635f}, + {3481.36f,605.324f},{3169.05f,601.083f},{3138.84f,324.116f},{3446.12f,325.545f}, + {2866.14f,599.61f},{2555.38f,597.142f},{2541.51f,320.931f},{2845.5f,322.419f}, + {2256.79f,593.253f},{1950.17f,590.12f},{1951.8f,317.445f},{2250.88f,319.418f}, + {1654.16f,587.663f},{1344.83f,582.787f},{1362.8f,309.253f},{1663.89f,313.056f}, + {1050.94f,577.867f},{741.476f,571.648f},{776.433f,300.444f},{1076.97f,304.56f}, + {3327.05f,1847.65f},{2977.74f,1840.48f},{2945.48f,1499.68f},{3281.82f,1504.97f}, + {2630.85f,1834.22f},{2287.2f,1828.06f},{2278.56f,1489.51f},{2610.64f,1494.31f}, + {1946.11f,1822.05f},{1604.75f,1816.18f},{1617.11f,1478.59f},{1947.62f,1484.48f}, + {1262.96f,1810.53f},{920.46f,1805.05f},{956.712f,1467.57f},{1286.66f,1473.27f}, + {3618.7f,1511.71f},{3281.82f,1504.97f},{3240.24f,1186.11f},{3564.22f,1192.53f}, + {2945.48f,1499.68f},{2610.64f,1494.31f},{2591.52f,1176.55f},{2915.32f,1180.97f}, + {2278.56f,1489.51f},{1947.62f,1484.48f},{1949.81f,1167.56f},{2269.79f,1172.18f}, + {1617.11f,1478.59f},{1286.66f,1473.27f},{1308.98f,1157.53f},{1628.88f,1162.47f}, + {956.712f,1467.57f},{627.315f,1462.81f},{669.943f,1146.75f},{989.494f,1151.86f}, + {3240.25f,1186.11f},{2915.32f,1180.98f},{2887.03f,881.727f},{3200.69f,886.725f}, + {2591.52f,1176.55f},{2269.79f,1172.19f},{2261.62f,874.587f},{2573.63f,878.324f}, + {1949.81f,1167.55f},{1628.88f,1162.47f},{1640.44f,864.751f},{1950.74f,870.259f}, + {1308.98f,1157.53f},{989.494f,1151.86f},{1019.41f,854.787f},{1329.92f,860.49f}, + {3515.88f,891.68f},{3200.69f,886.725f},{3171.89f,598.263f},{3478.26f,602.785f}, + {2887.04f,881.725f},{2573.63f,878.324f},{2558.28f,594.392f},{2863.1f,597.005f}, + {2261.62f,874.587f},{1950.74f,870.259f},{1952.4f,588.114f},{2254.56f,591.241f}, + {1640.44f,864.751f},{1329.92f,860.49f},{1348.65f,579.559f},{1650.55f,584.209f}, + {1019.41f,854.787f},{708.649f,849.44f},{745.388f,568.534f},{1047.42f,574.313f}, + {3171.89f,598.263f},{2863.1f,597.005f},{2842.6f,325.169f},{3141.93f,326.654f}, + {2558.28f,594.392f},{2254.56f,591.241f},{2248.65f,321.425f},{2544.55f,323.537f}, + {1952.4f,588.113f},{1650.55f,584.209f},{1660.07f,316.284f},{1954.02f,319.457f}, + {1348.65f,579.559f},{1047.43f,574.312f},{1073.06f,307.674f},{1366.42f,312.707f} + }; + + cv::flann::KDTreeIndexParams indexParams(1); + cv::Mat data = cv::Mat(corners).reshape(1, static_cast(corners.size())); + cv::flann::Index index(data, indexParams); + + const int maxResults = 4; + + for (int i = 0; i < (int)corners.size(); i++) + { + SCOPED_TRACE(cv::format("Data row: %d", i)); + std::vector indices(maxResults); + std::vector dists(maxResults); + int nn = index.radiusSearch(data.row(i), indices, dists, 100, maxResults); + EXPECT_EQ(nn, (int)indices.size()); + EXPECT_LE(nn, maxResults); + } +} + +}} // namespace