diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..7aca75262b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,31 @@ +# https://editorconfig.org/ + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[{CMakeLists.*,*.cmake}] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab + +[*.{bat,cmd,cmd.*}] +end_of_line = crlf +indent_style = space +indent_size = 2 + +[*.{ps1,ps1.*}] +end_of_line = crlf +indent_style = space +indent_size = 4 + +[*.{md,markdown}] +indent_size = 2 diff --git a/modules/aruco/include/opencv2/aruco/aruco_calib.hpp b/modules/aruco/include/opencv2/aruco/aruco_calib.hpp index fc86dab843..a1973b680f 100644 --- a/modules/aruco/include/opencv2/aruco/aruco_calib.hpp +++ b/modules/aruco/include/opencv2/aruco/aruco_calib.hpp @@ -26,7 +26,7 @@ enum PatternPositionType { * (markerLength/2, -markerLength/2, 0), (-markerLength/2, -markerLength/2, 0). * * These pattern points define this coordinate system: - * ![Image with axes drawn](tutorials/images/singlemarkersaxes.jpg) + * ![Image with axes drawn](tutorials/images/singlemarkersaxes2.jpg) */ ARUCO_CCW_CENTER, /** @brief The marker coordinate system is centered on the top-left corner of the marker. @@ -36,7 +36,7 @@ enum PatternPositionType { * (markerLength, markerLength, 0), (0, markerLength, 0). * * These pattern points define this coordinate system: - * ![Image with axes drawn](tutorials/images/singlemarkersaxes2.jpg) + * ![Image with axes drawn](tutorials/images/singlemarkersaxes.jpg) * * These pattern dots are convenient to use with a chessboard/ChArUco board. */ diff --git a/modules/aruco/samples/aruco_dict_utils.cpp b/modules/aruco/samples/aruco_dict_utils.cpp deleted file mode 100644 index 75fd2ee8b9..0000000000 --- a/modules/aruco/samples/aruco_dict_utils.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include -#include -#include - -using namespace cv; -using namespace std; - -static inline int _getSelfDistance(const Mat &marker) { - Mat bytes = aruco::Dictionary::getByteListFromBits(marker); - int minHamming = (int)marker.total() + 1; - for(int r = 1; r < 4; r++) { - int currentHamming = cv::hal::normHamming(bytes.ptr(), bytes.ptr() + bytes.cols*r, bytes.cols); - if(currentHamming < minHamming) minHamming = currentHamming; - } - Mat b; - flip(marker, b, 0); - Mat flipBytes = aruco::Dictionary::getByteListFromBits(b); - for(int r = 0; r < 4; r++) { - int currentHamming = cv::hal::normHamming(flipBytes.ptr(), bytes.ptr() + bytes.cols*r, bytes.cols); - if(currentHamming < minHamming) minHamming = currentHamming; - } - flip(marker, b, 1); - flipBytes = aruco::Dictionary::getByteListFromBits(b); - for(int r = 0; r < 4; r++) { - int currentHamming = cv::hal::normHamming(flipBytes.ptr(), bytes.ptr() + bytes.cols*r, bytes.cols); - if(currentHamming < minHamming) minHamming = currentHamming; - } - return minHamming; -} - -static inline int getFlipDistanceToId(const aruco::Dictionary& dict, InputArray bits, int id, bool allRotations = true) { - Mat bytesList = dict.bytesList; - CV_Assert(id >= 0 && id < bytesList.rows); - - unsigned int nRotations = 4; - if(!allRotations) nRotations = 1; - - Mat candidateBytes = aruco::Dictionary::getByteListFromBits(bits.getMat()); - int currentMinDistance = int(bits.total() * bits.total()); - for(unsigned int r = 0; r < nRotations; r++) { - int currentHamming = cv::hal::normHamming( - bytesList.ptr(id) + r*candidateBytes.cols, - candidateBytes.ptr(), - candidateBytes.cols); - - if(currentHamming < currentMinDistance) { - currentMinDistance = currentHamming; - } - } - Mat b; - flip(bits.getMat(), b, 0); - candidateBytes = aruco::Dictionary::getByteListFromBits(b); - for(unsigned int r = 0; r < nRotations; r++) { - int currentHamming = cv::hal::normHamming( - bytesList.ptr(id) + r * candidateBytes.cols, - candidateBytes.ptr(), - candidateBytes.cols); - if (currentHamming < currentMinDistance) { - currentMinDistance = currentHamming; - } - } - - flip(bits.getMat(), b, 1); - candidateBytes = aruco::Dictionary::getByteListFromBits(b); - for(unsigned int r = 0; r < nRotations; r++) { - int currentHamming = cv::hal::normHamming( - bytesList.ptr(id) + r * candidateBytes.cols, - candidateBytes.ptr(), - candidateBytes.cols); - if (currentHamming < currentMinDistance) { - currentMinDistance = currentHamming; - } - } - return currentMinDistance; -} - -static inline aruco::Dictionary generateCustomAsymmetricDictionary(int nMarkers, int markerSize, - const aruco::Dictionary &baseDictionary, - int randomSeed) { - RNG rng((uint64)(randomSeed)); - - aruco::Dictionary out; - out.markerSize = markerSize; - - // theoretical maximum intermarker distance - // See S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014. - // "Automatic generation and detection of highly reliable fiducial markers under occlusion". - // Pattern Recogn. 47, 6 (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005 - int C = (int)std::floor(float(markerSize * markerSize) / 4.f); - int tau = 2 * (int)std::floor(float(C) * 4.f / 3.f); - - // if baseDictionary is provided, calculate its intermarker distance - if(baseDictionary.bytesList.rows > 0) { - CV_Assert(baseDictionary.markerSize == markerSize); - out.bytesList = baseDictionary.bytesList.clone(); - - int minDistance = markerSize * markerSize + 1; - for(int i = 0; i < out.bytesList.rows; i++) { - Mat markerBytes = out.bytesList.rowRange(i, i + 1); - Mat markerBits = aruco::Dictionary::getBitsFromByteList(markerBytes, markerSize); - minDistance = min(minDistance, _getSelfDistance(markerBits)); - for(int j = i + 1; j < out.bytesList.rows; j++) { - minDistance = min(minDistance, getFlipDistanceToId(out, markerBits, j)); - } - } - tau = minDistance; - } - - // current best option - int bestTau = 0; - Mat bestMarker; - - // after these number of unproductive iterations, the best option is accepted - const int maxUnproductiveIterations = 5000; - int unproductiveIterations = 0; - - while(out.bytesList.rows < nMarkers) { - Mat currentMarker(markerSize, markerSize, CV_8UC1, Scalar::all(0)); - rng.fill(currentMarker, RNG::UNIFORM, 0, 2); - - int selfDistance = _getSelfDistance(currentMarker); - int minDistance = selfDistance; - - // if self distance is better or equal than current best option, calculate distance - // to previous accepted markers - if(selfDistance >= bestTau) { - for(int i = 0; i < out.bytesList.rows; i++) { - int currentDistance = getFlipDistanceToId(out, currentMarker, i); - minDistance = min(currentDistance, minDistance); - if(minDistance <= bestTau) { - break; - } - } - } - - // if distance is high enough, accept the marker - if(minDistance >= tau) { - unproductiveIterations = 0; - bestTau = 0; - Mat bytes = aruco::Dictionary::getByteListFromBits(currentMarker); - out.bytesList.push_back(bytes); - } else { - unproductiveIterations++; - - // if distance is not enough, but is better than the current best option - if(minDistance > bestTau) { - bestTau = minDistance; - bestMarker = currentMarker; - } - - // if number of unproductive iterarions has been reached, accept the current best option - if(unproductiveIterations == maxUnproductiveIterations) { - unproductiveIterations = 0; - tau = bestTau; - bestTau = 0; - Mat bytes = aruco::Dictionary::getByteListFromBits(bestMarker); - out.bytesList.push_back(bytes); - } - } - } - - // update the maximum number of correction bits for the generated dictionary - out.maxCorrectionBits = (tau - 1) / 2; - - return out; -} - -static inline int getMinDistForDict(const aruco::Dictionary& dict) { - const int dict_size = dict.bytesList.rows; - const int marker_size = dict.markerSize; - int minDist = marker_size * marker_size; - for (int i = 0; i < dict_size; i++) { - Mat row = dict.bytesList.row(i); - Mat marker = dict.getBitsFromByteList(row, marker_size); - for (int j = 0; j < dict_size; j++) { - if (j != i) { - minDist = min(dict.getDistanceToId(marker, j), minDist); - } - } - } - return minDist; -} - -static inline int getMinAsymDistForDict(const aruco::Dictionary& dict) { - const int dict_size = dict.bytesList.rows; - const int marker_size = dict.markerSize; - int minDist = marker_size * marker_size; - for (int i = 0; i < dict_size; i++) - { - Mat row = dict.bytesList.row(i); - Mat marker = dict.getBitsFromByteList(row, marker_size); - for (int j = 0; j < dict_size; j++) - { - if (j != i) - { - minDist = min(getFlipDistanceToId(dict, marker, j), minDist); - } - } - } - return minDist; -} - -const char* keys = - "{@outfile | | Output file with custom dict }" - "{r | false | Calculate the metric considering flipped markers }" - "{d | | Dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," - "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " - "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" - "{nMarkers | | Number of markers in the dictionary }" - "{markerSize | | Marker size }" - "{cd | | Input file with custom dictionary }"; - -const char* about = - "This program can be used to calculate the ArUco dictionary metric.\n" - "To calculate the metric considering flipped markers use -'r' flag.\n" - "This program can be used to create and write the custom ArUco dictionary.\n"; - -int main(int argc, char *argv[]) -{ - CommandLineParser parser(argc, argv, keys); - parser.about(about); - - if(argc < 2) { - parser.printMessage(); - return 0; - } - string outputFile = parser.get(0); - int nMarkers = parser.get("nMarkers"); - int markerSize = parser.get("markerSize"); - bool checkFlippedMarkers = parser.get("r"); - - aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); - if (parser.has("d")) { - int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); - } - else if (parser.has("cd")) { - FileStorage fs(parser.get("cd"), FileStorage::READ); - bool readOk = dictionary.aruco::Dictionary::readDictionary(fs.root()); - if(!readOk) { - cerr << "Invalid dictionary file" << endl; - return 0; - } - } - else if (outputFile.empty() || nMarkers == 0 || markerSize == 0) { - cerr << "Dictionary not specified" << endl; - return 0; - } - - if (!outputFile.empty() && nMarkers > 0 && markerSize > 0) - { - FileStorage fs(outputFile, FileStorage::WRITE); - if (checkFlippedMarkers) - dictionary = generateCustomAsymmetricDictionary(nMarkers, markerSize, aruco::Dictionary(), 0); - else - dictionary = aruco::extendDictionary(nMarkers, markerSize, aruco::Dictionary(), 0); - dictionary.writeDictionary(fs); - } - - if (checkFlippedMarkers) { - cout << getMinAsymDistForDict(dictionary) << endl; - } - else { - cout << getMinDistForDict(dictionary) << endl; - } - return 0; -} diff --git a/modules/aruco/samples/calibrate_camera.cpp b/modules/aruco/samples/calibrate_camera.cpp index 3620f50248..13efb5f8a9 100644 --- a/modules/aruco/samples/calibrate_camera.cpp +++ b/modules/aruco/samples/calibrate_camera.cpp @@ -1,51 +1,17 @@ -/* -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 - (3-clause BSD License) - -Copyright (C) 2013, OpenCV Foundation, all rights reserved. -Third party copyrights are property of their respective owners. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the names of the copyright holders nor the names of the 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 copyright holders 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. -*/ +// 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 +#include +#include #include #include #include -#include #include #include -#include -#include -#include +#include #include "aruco_samples_utility.hpp" using namespace std; @@ -139,7 +105,9 @@ int main(int argc, char *argv[]) { aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); if (parser.has("d")) { int dictionaryId = parser.get("d"); - dictionary = aruco::getPredefinedDictionary(aruco::PredefinedDictionaryType(dictionaryId)); + dictionary = aruco::getPredefinedDictionary( + aruco::PredefinedDictionaryType(dictionaryId) + ); } else if (parser.has("cd")) { FileStorage fs(parser.get("cd"), FileStorage::READ); @@ -154,14 +122,13 @@ int main(int argc, char *argv[]) { return 0; } - // create board object - Ptr gridboard = new aruco::GridBoard(Size(markersX, markersY), markerLength, markerSeparation, dictionary); - Ptr board = gridboard.staticCast(); + // Create board object + aruco::GridBoard gridboard(Size(markersX, markersY), markerLength, markerSeparation, dictionary); - // collected frames for calibration - vector< vector< vector< Point2f > > > allCorners; - vector< vector< int > > allIds; - Size imgSize; + // Collected frames for calibration + vector>> allMarkerCorners; + vector> allMarkerIds; + Size imageSize; aruco::ArucoDetector detector(dictionary, detectorParams); @@ -169,65 +136,90 @@ int main(int argc, char *argv[]) { Mat image, imageCopy; inputVideo.retrieve(image); - vector< int > ids; - vector< vector< Point2f > > corners, rejected; + vector markerIds; + vector> markerCorners, rejectedMarkers; - // detect markers - detector.detectMarkers(image, corners, ids, rejected); + // Detect markers + detector.detectMarkers(image, markerCorners, markerIds, rejectedMarkers); - // refind strategy to detect more markers - if(refindStrategy) detector.refineDetectedMarkers(image, *board, corners, ids, rejected); + // Refind strategy to detect more markers + if(refindStrategy) { + detector.refineDetectedMarkers( + image, gridboard, markerCorners, markerIds, rejectedMarkers + ); + } - // draw results + // Draw results image.copyTo(imageCopy); - if(ids.size() > 0) aruco::drawDetectedMarkers(imageCopy, corners, ids); - putText(imageCopy, "Press 'c' to add current frame. 'ESC' to finish and calibrate", - Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2); + if(!markerIds.empty()) { + aruco::drawDetectedMarkers(imageCopy, markerCorners, markerIds); + } + + putText( + imageCopy, "Press 'c' to add current frame. 'ESC' to finish and calibrate", + Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2 + ); imshow("out", imageCopy); + + // Wait for key pressed char key = (char)waitKey(waitTime); - if(key == 27) break; - if(key == 'c' && ids.size() > 0) { + + if(key == 27) { + break; + } + + if(key == 'c' && !markerIds.empty()) { cout << "Frame captured" << endl; - allCorners.push_back(corners); - allIds.push_back(ids); - imgSize = image.size(); + allMarkerCorners.push_back(markerCorners); + allMarkerIds.push_back(markerIds); + imageSize = image.size(); } } - if(allIds.size() < 1) { + if(allMarkerIds.empty()) { cerr << "Not enough captures for calibration" << endl; return 0; } Mat cameraMatrix, distCoeffs; - vector< Mat > rvecs, tvecs; - double repError; if(calibrationFlags & CALIB_FIX_ASPECT_RATIO) { cameraMatrix = Mat::eye(3, 3, CV_64F); - cameraMatrix.at< double >(0, 0) = aspectRatio; + cameraMatrix.at(0, 0) = aspectRatio; } - // prepare data for calibration - vector< vector< Point2f > > allCornersConcatenated; - vector< int > allIdsConcatenated; - vector< int > markerCounterPerFrame; - markerCounterPerFrame.reserve(allCorners.size()); - for(unsigned int i = 0; i < allCorners.size(); i++) { - markerCounterPerFrame.push_back((int)allCorners[i].size()); - for(unsigned int j = 0; j < allCorners[i].size(); j++) { - allCornersConcatenated.push_back(allCorners[i][j]); - allIdsConcatenated.push_back(allIds[i][j]); + // Prepare data for calibration + vector objectPoints; + vector imagePoints; + vector processedObjectPoints, processedImagePoints; + size_t nFrames = allMarkerCorners.size(); + + for(size_t frame = 0; frame < nFrames; frame++) { + Mat currentImgPoints, currentObjPoints; + + gridboard.matchImagePoints( + allMarkerCorners[frame], allMarkerIds[frame], + currentObjPoints, currentImgPoints + ); + + if(currentImgPoints.total() > 0 && currentObjPoints.total() > 0) { + processedImagePoints.push_back(currentImgPoints); + processedObjectPoints.push_back(currentObjPoints); } } - // calibrate camera - repError = aruco::calibrateCameraAruco(allCornersConcatenated, allIdsConcatenated, - markerCounterPerFrame, board, imgSize, cameraMatrix, - distCoeffs, rvecs, tvecs, calibrationFlags); - bool saveOk = saveCameraParams(outputFile, imgSize, aspectRatio, calibrationFlags, cameraMatrix, - distCoeffs, repError); + // Calibrate camera + double repError = calibrateCamera( + processedObjectPoints, processedImagePoints, imageSize, + cameraMatrix, distCoeffs, noArray(), noArray(), noArray(), + noArray(), noArray(), calibrationFlags + ); + + bool saveOk = saveCameraParams( + outputFile, imageSize, aspectRatio, calibrationFlags, cameraMatrix, + distCoeffs, repError + ); if(!saveOk) { cerr << "Cannot save output file" << endl; diff --git a/modules/aruco/samples/calibrate_camera_charuco.cpp b/modules/aruco/samples/calibrate_camera_charuco.cpp index 7ea6ff8d84..159ec525c0 100644 --- a/modules/aruco/samples/calibrate_camera_charuco.cpp +++ b/modules/aruco/samples/calibrate_camera_charuco.cpp @@ -1,49 +1,15 @@ -/* -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 - (3-clause BSD License) - -Copyright (C) 2013, OpenCV Foundation, all rights reserved. -Third party copyrights are property of their respective owners. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the names of the copyright holders nor the names of the 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 copyright holders 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. -*/ - +// 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 +#include #include #include #include #include #include -#include -#include +#include #include "aruco_samples_utility.hpp" using namespace std; @@ -103,10 +69,10 @@ int main(int argc, char *argv[]) { if(parser.get("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST; if(parser.get("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT; - Ptr detectorParams = makePtr(); + aruco::DetectorParameters detectorParams = aruco::DetectorParameters(); if(parser.has("dp")) { FileStorage fs(parser.get("dp"), FileStorage::READ); - bool readOk = detectorParams->readDetectorParameters(fs.root()); + bool readOk = detectorParams.readDetectorParameters(fs.root()); if(!readOk) { cerr << "Invalid detector parameters file" << endl; return 0; @@ -154,146 +120,131 @@ int main(int argc, char *argv[]) { return 0; } - // create charuco board object - Ptr charucoboard = new aruco::CharucoBoard(Size(squaresX, squaresY), squareLength, markerLength, dictionary); - Ptr board = charucoboard.staticCast(); + // Create charuco board object + aruco::CharucoBoard board(Size(squaresX, squaresY), squareLength, markerLength, dictionary); + aruco::CharucoParameters charucoParams; + + if(refindStrategy) { + charucoParams.tryRefineMarkers = true; + } + + aruco::CharucoDetector detector(board, charucoParams, detectorParams); + + // Collect data from each frame + vector allCharucoCorners; + vector allCharucoIds; + + vector> allImagePoints; + vector> allObjectPoints; - // collect data from each frame - vector< vector< vector< Point2f > > > allCorners; - vector< vector< int > > allIds; - vector< Mat > allImgs; - Size imgSize; + vector allImages; + Size imageSize; while(inputVideo.grab()) { Mat image, imageCopy; inputVideo.retrieve(image); - vector< int > ids; - vector< vector< Point2f > > corners, rejected; + vector markerIds; + vector> markerCorners, rejectedMarkers; + Mat currentCharucoCorners; + Mat currentCharucoIds; + vector currentObjectPoints; + vector currentImagePoints; - // detect markers - aruco::detectMarkers(image, makePtr(dictionary), corners, ids, detectorParams, rejected); + // Detect ChArUco board + detector.detectBoard(image, currentCharucoCorners, currentCharucoIds); - // refind strategy to detect more markers - if(refindStrategy) aruco::refineDetectedMarkers(image, board, corners, ids, rejected); - - // interpolate charuco corners - Mat currentCharucoCorners, currentCharucoIds; - if(ids.size() > 0) - aruco::interpolateCornersCharuco(corners, ids, image, charucoboard, currentCharucoCorners, - currentCharucoIds); - - // draw results + // Draw results image.copyTo(imageCopy); - if(ids.size() > 0) aruco::drawDetectedMarkers(imageCopy, corners); + if(!markerIds.empty()) { + aruco::drawDetectedMarkers(imageCopy, markerCorners); + } - if(currentCharucoCorners.total() > 0) + if(currentCharucoCorners.total() > 3) { aruco::drawDetectedCornersCharuco(imageCopy, currentCharucoCorners, currentCharucoIds); + } putText(imageCopy, "Press 'c' to add current frame. 'ESC' to finish and calibrate", Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2); imshow("out", imageCopy); + + // Wait for key pressed char key = (char)waitKey(waitTime); - if(key == 27) break; - if(key == 'c' && ids.size() > 0) { + + if(key == 27) { + break; + } + + if(key == 'c' && currentCharucoCorners.total() > 3) { + // Match image points + board.matchImagePoints(currentCharucoCorners, currentCharucoIds, currentObjectPoints, currentImagePoints); + + if(currentImagePoints.empty() || currentObjectPoints.empty()) { + cout << "Point matching failed, try again." << endl; + continue; + } + cout << "Frame captured" << endl; - allCorners.push_back(corners); - allIds.push_back(ids); - allImgs.push_back(image); - imgSize = image.size(); + + allCharucoCorners.push_back(currentCharucoCorners); + allCharucoIds.push_back(currentCharucoIds); + allImagePoints.push_back(currentImagePoints); + allObjectPoints.push_back(currentObjectPoints); + allImages.push_back(image); + + imageSize = image.size(); } } - if(allIds.size() < 1) { - cerr << "Not enough captures for calibration" << endl; + if(allCharucoCorners.size() < 4) { + cerr << "Not enough corners for calibration" << endl; return 0; } Mat cameraMatrix, distCoeffs; - vector< Mat > rvecs, tvecs; - double repError; if(calibrationFlags & CALIB_FIX_ASPECT_RATIO) { cameraMatrix = Mat::eye(3, 3, CV_64F); - cameraMatrix.at< double >(0, 0) = aspectRatio; + cameraMatrix.at(0, 0) = aspectRatio; } - // prepare data for calibration - vector< vector< Point2f > > allCornersConcatenated; - vector< int > allIdsConcatenated; - vector< int > markerCounterPerFrame; - markerCounterPerFrame.reserve(allCorners.size()); - for(unsigned int i = 0; i < allCorners.size(); i++) { - markerCounterPerFrame.push_back((int)allCorners[i].size()); - for(unsigned int j = 0; j < allCorners[i].size(); j++) { - allCornersConcatenated.push_back(allCorners[i][j]); - allIdsConcatenated.push_back(allIds[i][j]); - } - } - - // calibrate camera using aruco markers - double arucoRepErr; - arucoRepErr = aruco::calibrateCameraAruco(allCornersConcatenated, allIdsConcatenated, - markerCounterPerFrame, board, imgSize, cameraMatrix, - distCoeffs, noArray(), noArray(), calibrationFlags); - - // prepare data for charuco calibration - int nFrames = (int)allCorners.size(); - vector< Mat > allCharucoCorners; - vector< Mat > allCharucoIds; - vector< Mat > filteredImages; - allCharucoCorners.reserve(nFrames); - allCharucoIds.reserve(nFrames); - - for(int i = 0; i < nFrames; i++) { - // interpolate using camera parameters - Mat currentCharucoCorners, currentCharucoIds; - aruco::interpolateCornersCharuco(allCorners[i], allIds[i], allImgs[i], charucoboard, - currentCharucoCorners, currentCharucoIds, cameraMatrix, - distCoeffs); - - allCharucoCorners.push_back(currentCharucoCorners); - allCharucoIds.push_back(currentCharucoIds); - filteredImages.push_back(allImgs[i]); - } - - if(allCharucoCorners.size() < 4) { - cerr << "Not enough corners for calibration" << endl; - return 0; - } + // Calibrate camera using ChArUco + double repError = calibrateCamera( + allObjectPoints, allImagePoints, imageSize, + cameraMatrix, distCoeffs, noArray(), noArray(), noArray(), + noArray(), noArray(), calibrationFlags + ); - // calibrate camera using charuco - repError = - aruco::calibrateCameraCharuco(allCharucoCorners, allCharucoIds, charucoboard, imgSize, - cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags); + bool saveOk = saveCameraParams( + outputFile, imageSize, aspectRatio, calibrationFlags, + cameraMatrix, distCoeffs, repError + ); - bool saveOk = saveCameraParams(outputFile, imgSize, aspectRatio, calibrationFlags, - cameraMatrix, distCoeffs, repError); if(!saveOk) { cerr << "Cannot save output file" << endl; return 0; } cout << "Rep Error: " << repError << endl; - cout << "Rep Error Aruco: " << arucoRepErr << endl; cout << "Calibration saved to " << outputFile << endl; - // show interpolated charuco corners for debugging + // Show interpolated charuco corners for debugging if(showChessboardCorners) { - for(unsigned int frame = 0; frame < filteredImages.size(); frame++) { - Mat imageCopy = filteredImages[frame].clone(); - if(allIds[frame].size() > 0) { - - if(allCharucoCorners[frame].total() > 0) { - aruco::drawDetectedCornersCharuco( imageCopy, allCharucoCorners[frame], - allCharucoIds[frame]); - } + for(size_t frame = 0; frame < allImages.size(); frame++) { + Mat imageCopy = allImages[frame].clone(); + + if(allCharucoCorners[frame].total() > 0) { + aruco::drawDetectedCornersCharuco( + imageCopy, allCharucoCorners[frame], allCharucoIds[frame] + ); } imshow("out", imageCopy); char key = (char)waitKey(0); - if(key == 27) break; + if(key == 27) { + break; + } } } diff --git a/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown b/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown index 936658765c..0f466f9f33 100644 --- a/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown +++ b/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown @@ -33,40 +33,58 @@ visible in all the viewpoints. ![ChArUco calibration viewpoints](images/charucocalibration.png) -The function to calibrate is ```calibrateCameraCharuco()```. Example: +The function to calibrate is `cv::calibrateCamera()`. Example: @code{.cpp} - cv::Ptr board = ... // create charuco board - cv::Size imgSize = ... // camera image size - - std::vector> allCharucoCorners; - std::vector> allCharucoIds; - // Detect charuco board from several viewpoints and fill allCharucoCorners and allCharucoIds - ... - ... + Ptr board = ... // create charuco board + Size imageSize = ... // camera image size + + vector> allCharucoCorners; + vector> allCharucoIds; + vector> allImagePoints; + vector> allObjectPoints; + + // Detect charuco board from several viewpoints and fill + // allCharucoCorners, allCharucoIds, allImagePoints and allObjectPoints + while(inputVideo.grab()) { + detector.detectBoard( + image, currentCharucoCorners, currentCharucoIds + ); + board.matchImagePoints( + currentCharucoCorners, currentCharucoIds, + currentObjectPoints, currentImagePoints + ); + + ... + } // After capturing in several viewpoints, start calibration - cv::Mat cameraMatrix, distCoeffs; - std::vector rvecs, tvecs; - int calibrationFlags = ... // Set calibration flags (same than in calibrateCamera() function) + Mat cameraMatrix, distCoeffs; + vector rvecs, tvecs; + + // Set calibration flags (same than in calibrateCamera() function) + int calibrationFlags = ... - double repError = cv::aruco::calibrateCameraCharuco(allCharucoCorners, allCharucoIds, board, imgSize, cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags); + double repError = calibrateCamera( + allObjectPoints, allImagePoints, imageSize, + cameraMatrix, distCoeffs, rvecs, tvecs, noArray(), + noArray(), noArray(), calibrationFlags + ); @endcode The ChArUco corners and ChArUco identifiers captured on each viewpoint are stored in the vectors ```allCharucoCorners``` and ```allCharucoIds```, one element per viewpoint. -The ```calibrateCameraCharuco()``` function will fill the ```cameraMatrix``` and ```distCoeffs``` arrays with the camera calibration parameters. It will return the reprojection -error obtained from the calibration. The elements in ```rvecs``` and ```tvecs``` will be filled with the estimated pose of the camera (respect to the ChArUco board) +The `calibrateCamera()` function will fill the `cameraMatrix` and `distCoeffs` arrays with the camera calibration parameters. It will return the reprojection +error obtained from the calibration. The elements in `rvecs` and `tvecs` will be filled with the estimated pose of the camera (respect to the ChArUco board) in each of the viewpoints. -Finally, the ```calibrationFlags``` parameter determines some of the options for the calibration. Its format is equivalent to the flags parameter in the OpenCV -```calibrateCamera()``` function. +Finally, the `calibrationFlags` parameter determines some of the options for the calibration. -A full working example is included in the `calibrate_camera_charuco.cpp` inside the `modules/aruco/samples/`. +A full working example is included in the `calibrate_camera_charuco.cpp` inside the `samples` folder. Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like @code{.cpp} - "output_path/camera_calib.txt" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 + "camera_calib.txt" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 -v="path_aruco/tutorials/aruco_calibration/images/img_%02d.jpg -c=path_aruco/samples/tutorial_camera_params.yml @endcode @@ -78,40 +96,43 @@ Calibration with ArUco Boards As it has been stated, it is recommended the use of ChAruco boards instead of ArUco boards for camera calibration, since ChArUco corners are more accurate than marker corners. However, in some special cases it must be required to use calibration -based on ArUco boards. For these cases, the ```calibrateCameraAruco()``` function is provided. As in the previous case, it -requires the detections of an ArUco board from different viewpoints. +based on ArUco boards. As in the previous case, it requires the detections of an ArUco board from different viewpoints. ![ArUco calibration viewpoints](images/arucocalibration.png) Example of ```calibrateCameraAruco()``` use: @code{.cpp} - cv::Ptr board = ... // create aruco board - cv::Size imgSize = ... // camera image size + Ptr board = ... // create aruco board + Size imgSize = ... // camera image size - std::vector> allCornersConcatenated; - std::vector allIdsConcatenated; - std::vector markerCounterPerFrame; - // Detect aruco board from several viewpoints and fill allCornersConcatenated, allIdsConcatenated and markerCounterPerFrame - ... + vector>> allMarkerCorners; + vector> allMarkerIds; + + // Detect aruco board from several viewpoints and fill allMarkerCorners, allMarkerIds + detector.detectMarkers(image, markerCorners, markerIds, rejectedMarkers); ... - // After capturing in several viewpoints, start calibration - cv::Mat cameraMatrix, distCoeffs; - std::vector rvecs, tvecs; + // After capturing in several viewpoints, match image points and start calibration + board->matchImagePoints( + allMarkerCorners[frame], allMarkerIds[frame], + currentObjPoints, currentImgPoints + ); + + Mat cameraMatrix, distCoeffs; + vector rvecs, tvecs; int calibrationFlags = ... // Set calibration flags (same than in calibrateCamera() function) - double repError = cv::aruco::calibrateCameraAruco(allCornersConcatenated, allIdsConcatenated, markerCounterPerFrame, board, imgSize, cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags); + double repError = calibrateCamera( + processedObjectPoints, processedImagePoints, imageSize, + cameraMatrix, distCoeffs, rvecs, tvecs, noArray(), + noArray(), noArray(), calibrationFlags + ); @endcode -In this case, and contrary to the ```calibrateCameraCharuco()``` function, the detected markers on each viewpoint are concatenated in the arrays ```allCornersConcatenated``` and -```allCornersConcatenated``` (the first two parameters). The third parameter, the array ```markerCounterPerFrame```, indicates the number of marker detected on each viewpoint. -The rest of parameters are the same than in ```calibrateCameraCharuco()```, except the board layout object which does not need to be a ```CharucoBoard``` object, it can be -any ```Board``` object. - -A full working example is included in the `calibrate_camera.cpp` inside the `modules/aruco/samples/`. +A full working example is included in the `calibrate_camera.cpp` inside the `samples` folder. Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like @code{.cpp} - "_path_/calib.txt" -w=5 -h=7 -l=100 -s=10 -d=10 + "camera_calib.txt" -w=5 -h=7 -l=100 -s=10 -d=10 @endcode diff --git a/modules/aruco/tutorials/aruco_faq/aruco_faq.markdown b/modules/aruco/tutorials/aruco_faq/aruco_faq.markdown index 9d1183ef79..c65eafb299 100644 --- a/modules/aruco/tutorials/aruco_faq/aruco_faq.markdown +++ b/modules/aruco/tutorials/aruco_faq/aruco_faq.markdown @@ -128,7 +128,7 @@ If you are using one of the predefined dictionaries, it is not necessary. Otherw - Do I need to store the Board information in a file so I can use it in different executions? -If you are using a ```GridBoard``` or a ```ChArUco``` board you only need to store the board measurements that are provided to the ```GridBoard::create()``` or ```ChArUco::create()``` functions. +If you are using a ```GridBoard``` or a ```ChArUco``` board you only need to store the board measurements that are provided to the ```GridBoard::create()``` function or in or `ChArUco` constructor. If you manually modify the marker ids of the boards, or if you use a different type of board, you should save your board object to file. - Does the aruco module provide functions to save the Dictionary or Board to file? @@ -158,6 +158,5 @@ It is important to remark that the estimation of the pose using only 4 coplanar In general, the ambiguity can be solved, if the camera is near to the marker. However, as the marker becomes small, the errors in the corner estimation grows and ambiguity comes as a problem. Try increasing the size of the marker you're using, and you can also try non-symmetrical (aruco_dict_utils.cpp) markers to avoid collisions. -Use multiple markers (ArUco/ChArUco/Diamonds boards) and pose estimation with estimatePoseBoard(), estimatePoseCharucoBoard(). -Use solvePnP() with the ```SOLVEPNP_IPPE_SQUARE``` option. +Use multiple markers (ArUco/ChArUco/Diamonds boards) and pose estimation with solvePnP() with the ```SOLVEPNP_IPPE_SQUARE``` option. More in [this issue](https://github.com/opencv/opencv/issues/8813). diff --git a/modules/barcode/perf/perf_barcode.cpp b/modules/barcode/perf/perf_barcode.cpp new file mode 100644 index 0000000000..0d814a6126 --- /dev/null +++ b/modules/barcode/perf/perf_barcode.cpp @@ -0,0 +1,113 @@ +// 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 "perf_precomp.hpp" + +namespace opencv_test{namespace{ + +typedef ::perf::TestBaseWithParam< tuple > Perf_Barcode_multi; +typedef ::perf::TestBaseWithParam< tuple > Perf_Barcode_single; + +PERF_TEST_P_(Perf_Barcode_multi, detect) +{ + const string root = "cv/barcode/multiple/"; + const string name_current_image = get<0>(GetParam()); + const cv::Size sz = get<1>(GetParam()); + const string image_path = findDataFile(root + name_current_image); + + Mat src = imread(image_path); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + cv::resize(src, src, sz); + + vector< Point > corners; + auto bardet = barcode::BarcodeDetector(); + bool res = false; + TEST_CYCLE() + { + res = bardet.detect(src, corners); + } + SANITY_CHECK_NOTHING(); + ASSERT_TRUE(res); +} + +PERF_TEST_P_(Perf_Barcode_multi, detect_decode) +{ + const string root = "cv/barcode/multiple/"; + const string name_current_image = get<0>(GetParam()); + const cv::Size sz = get<1>(GetParam()); + const string image_path = findDataFile(root + name_current_image); + + Mat src = imread(image_path); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + cv::resize(src, src, sz); + + vector decoded_info; + vector decoded_type; + vector< Point > corners; + auto bardet = barcode::BarcodeDetector(); + bool res = false; + TEST_CYCLE() + { + res = bardet.detectAndDecode(src, decoded_info, decoded_type, corners); + } + SANITY_CHECK_NOTHING(); + ASSERT_TRUE(res); +} + +PERF_TEST_P_(Perf_Barcode_single, detect) +{ + const string root = "cv/barcode/single/"; + const string name_current_image = get<0>(GetParam()); + const cv::Size sz = get<1>(GetParam()); + const string image_path = findDataFile(root + name_current_image); + + Mat src = imread(image_path); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + cv::resize(src, src, sz); + + vector< Point > corners; + auto bardet = barcode::BarcodeDetector(); + bool res = false; + TEST_CYCLE() + { + res = bardet.detect(src, corners); + } + SANITY_CHECK_NOTHING(); + ASSERT_TRUE(res); +} + +PERF_TEST_P_(Perf_Barcode_single, detect_decode) +{ + const string root = "cv/barcode/single/"; + const string name_current_image = get<0>(GetParam()); + const cv::Size sz = get<1>(GetParam()); + const string image_path = findDataFile(root + name_current_image); + + Mat src = imread(image_path); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + cv::resize(src, src, sz); + + vector decoded_info; + vector decoded_type; + vector< Point > corners; + auto bardet = barcode::BarcodeDetector(); + bool res = false; + TEST_CYCLE() + { + res = bardet.detectAndDecode(src, decoded_info, decoded_type, corners); + } + SANITY_CHECK_NOTHING(); + ASSERT_TRUE(res); +} + +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Barcode_multi, + testing::Combine( + testing::Values("4_barcodes.jpg"), + testing::Values(cv::Size(2041, 2722), cv::Size(1361, 1815), cv::Size(680, 907)))); +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Barcode_single, + testing::Combine( + testing::Values("book.jpg", "bottle_1.jpg", "bottle_2.jpg"), + testing::Values(cv::Size(480, 360), cv::Size(640, 480), cv::Size(800, 600)))); + +}} //namespace diff --git a/modules/barcode/perf/perf_main.cpp b/modules/barcode/perf/perf_main.cpp new file mode 100644 index 0000000000..7de147e131 --- /dev/null +++ b/modules/barcode/perf/perf_main.cpp @@ -0,0 +1,9 @@ +// 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 "perf_precomp.hpp" + +using namespace perf; + +CV_PERF_TEST_MAIN(barcode) diff --git a/modules/barcode/perf/perf_precomp.hpp b/modules/barcode/perf/perf_precomp.hpp new file mode 100644 index 0000000000..dea5503b40 --- /dev/null +++ b/modules/barcode/perf/perf_precomp.hpp @@ -0,0 +1,11 @@ +// 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. + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/barcode.hpp" + +#endif diff --git a/modules/barcode/src/decoder/ean8_decoder.cpp b/modules/barcode/src/decoder/ean8_decoder.cpp index 66b5fec83e..74ac2fdb0b 100644 --- a/modules/barcode/src/decoder/ean8_decoder.cpp +++ b/modules/barcode/src/decoder/ean8_decoder.cpp @@ -27,7 +27,6 @@ Result Ean8Decoder::decode(const vector &data) const uint start = pattern.second; Counter counter(vector{0, 0, 0, 0}); size_t end = data.size(); - int first_char_bit = 0; for (int i = 0; i < 4 && start < end; ++i) { int bestMatch = decodeDigit(data, counter, start, get_A_or_C_Patterns()); @@ -37,7 +36,6 @@ Result Ean8Decoder::decode(const vector &data) const } decode_result[i] = static_cast('0' + bestMatch % 10); start = counter.sum + start; - first_char_bit += (bestMatch >= 10) << i; } Counter middle_counter(vector(MIDDLE_PATTERN().size())); diff --git a/modules/ccalib/src/ccalib.cpp b/modules/ccalib/src/ccalib.cpp index dd3a64d4b3..3c6658c112 100644 --- a/modules/ccalib/src/ccalib.cpp +++ b/modules/ccalib/src/ccalib.cpp @@ -247,23 +247,14 @@ void CustomPattern::check_matches(vector& matched, const vector proj; perspectiveTransform(pattern, proj, H); - int deleted = 0; - double error_sum = 0; - double error_sum_filtered = 0; for (uint i = 0; i < proj.size(); ++i) { double error = norm(matched[i] - proj[i]); - error_sum += error; if (error >= MAX_PROJ_ERROR_PX) { deleteStdVecElem(good, i); deleteStdVecElem(matched, i); deleteStdVecElem(pattern_3d, i); - ++deleted; - } - else - { - error_sum_filtered += error; } } } diff --git a/modules/cudacodec/include/opencv2/cudacodec.hpp b/modules/cudacodec/include/opencv2/cudacodec.hpp index d61673cd71..602f9ff17e 100644 --- a/modules/cudacodec/include/opencv2/cudacodec.hpp +++ b/modules/cudacodec/include/opencv2/cudacodec.hpp @@ -310,7 +310,7 @@ enum DeinterlaceMode struct CV_EXPORTS_W_SIMPLE FormatInfo { CV_WRAP FormatInfo() : nBitDepthMinus8(-1), ulWidth(0), ulHeight(0), width(0), height(0), ulMaxWidth(0), ulMaxHeight(0), valid(false), - fps(0), ulNumDecodeSurfaces(0) {}; + fps(0), ulNumDecodeSurfaces(0), videoFullRangeFlag(false) {}; CV_PROP_RW Codec codec; CV_PROP_RW ChromaFormat chromaFormat; @@ -329,6 +329,7 @@ struct CV_EXPORTS_W_SIMPLE FormatInfo CV_PROP_RW cv::Size targetSz;//!< Post-processed size of the output frame. CV_PROP_RW cv::Rect srcRoi;//!< Region of interest decoded from video source. CV_PROP_RW cv::Rect targetRoi;//!< Region of interest in the output frame containing the decoded frame. + CV_PROP_RW bool videoFullRangeFlag;//!< Output value indicating if the black level, luma and chroma of the source are represented using the full or limited range (AKA TV or "analogue" range) of values as defined in Annex E of the ITU-T Specification. Internally the conversion from NV12 to BGR obeys ITU 709. }; /** @brief cv::cudacodec::VideoReader generic properties identifier. diff --git a/modules/cudacodec/src/cuda/nv12_to_rgb.cu b/modules/cudacodec/src/cuda/nv12_to_rgb.cu index 744983b043..049041a758 100644 --- a/modules/cudacodec/src/cuda/nv12_to_rgb.cu +++ b/modules/cudacodec/src/cuda/nv12_to_rgb.cu @@ -66,14 +66,20 @@ namespace { __constant__ float constHueColorSpaceMat[9] = {1.1644f, 0.0f, 1.596f, 1.1644f, -0.3918f, -0.813f, 1.1644f, 2.0172f, 0.0f}; + template __device__ static void YUV2RGB(const uint* yuvi, float* red, float* green, float* blue) { float luma, chromaCb, chromaCr; - - // Prepare for hue adjustment - luma = (float)yuvi[0]; - chromaCb = (float)((int)yuvi[1] - 512.0f); - chromaCr = (float)((int)yuvi[2] - 512.0f); + if (fullRange) { + luma = (float)(((int)yuvi[0] * 219.0f / 255.0f)); + chromaCb = (float)(((int)yuvi[1] - 512.0f) * 224.0f / 255.0f); + chromaCr = (float)(((int)yuvi[2] - 512.0f) * 224.0f / 255.0f); + } + else { + luma = (float)((int)yuvi[0] - 64.0f); + chromaCb = (float)((int)yuvi[1] - 512.0f); + chromaCr = (float)((int)yuvi[2] - 512.0f); + } // Convert YUV To RGB with hue adjustment *red = (luma * constHueColorSpaceMat[0]) + @@ -112,6 +118,7 @@ namespace #define COLOR_COMPONENT_BIT_SIZE 10 #define COLOR_COMPONENT_MASK 0x3FF + template __global__ void NV12_to_BGRA(const uchar* srcImage, size_t nSourcePitch, uint* dstImage, size_t nDestPitch, uint width, uint height) @@ -135,31 +142,11 @@ namespace const int y_chroma = y >> 1; - if (y & 1) // odd scanline ? - { - uint chromaCb = srcImage[chromaOffset + y_chroma * nSourcePitch + x ]; - uint chromaCr = srcImage[chromaOffset + y_chroma * nSourcePitch + x + 1]; - - if (y_chroma < ((height >> 1) - 1)) // interpolate chroma vertically - { - chromaCb = (chromaCb + srcImage[chromaOffset + (y_chroma + 1) * nSourcePitch + x ] + 1) >> 1; - chromaCr = (chromaCr + srcImage[chromaOffset + (y_chroma + 1) * nSourcePitch + x + 1] + 1) >> 1; - } + yuv101010Pel[0] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x ] << ( COLOR_COMPONENT_BIT_SIZE + 2)); + yuv101010Pel[0] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x + 1] << ((COLOR_COMPONENT_BIT_SIZE << 1) + 2)); - yuv101010Pel[0] |= (chromaCb << ( COLOR_COMPONENT_BIT_SIZE + 2)); - yuv101010Pel[0] |= (chromaCr << ((COLOR_COMPONENT_BIT_SIZE << 1) + 2)); - - yuv101010Pel[1] |= (chromaCb << ( COLOR_COMPONENT_BIT_SIZE + 2)); - yuv101010Pel[1] |= (chromaCr << ((COLOR_COMPONENT_BIT_SIZE << 1) + 2)); - } - else - { - yuv101010Pel[0] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x ] << ( COLOR_COMPONENT_BIT_SIZE + 2)); - yuv101010Pel[0] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x + 1] << ((COLOR_COMPONENT_BIT_SIZE << 1) + 2)); - - yuv101010Pel[1] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x ] << ( COLOR_COMPONENT_BIT_SIZE + 2)); - yuv101010Pel[1] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x + 1] << ((COLOR_COMPONENT_BIT_SIZE << 1) + 2)); - } + yuv101010Pel[1] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x ] << ( COLOR_COMPONENT_BIT_SIZE + 2)); + yuv101010Pel[1] |= ((uint)srcImage[chromaOffset + y_chroma * nSourcePitch + x + 1] << ((COLOR_COMPONENT_BIT_SIZE << 1) + 2)); // this steps performs the color conversion uint yuvi[6]; @@ -174,8 +161,8 @@ namespace yuvi[5] = ((yuv101010Pel[1] >> (COLOR_COMPONENT_BIT_SIZE << 1)) & COLOR_COMPONENT_MASK); // YUV to RGB Transformation conversion - YUV2RGB(&yuvi[0], &red[0], &green[0], &blue[0]); - YUV2RGB(&yuvi[3], &red[1], &green[1], &blue[1]); + YUV2RGB(&yuvi[0], &red[0], &green[0], &blue[0]); + YUV2RGB(&yuvi[3], &red[1], &green[1], &blue[1]); // Clamp the results to RGBA @@ -186,13 +173,15 @@ namespace } } -void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream) +void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const bool videoFullRangeFlag, cudaStream_t stream) { outFrame.create(height, width, CV_8UC4); dim3 block(32, 8); dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y)); - NV12_to_BGRA<< > > (decodedFrame.ptr(), decodedFrame.step, - outFrame.ptr(), outFrame.step, width, height); + if (videoFullRangeFlag) + NV12_to_BGRA << > > (decodedFrame.ptr(), decodedFrame.step, outFrame.ptr(), outFrame.step, width, height); + else + NV12_to_BGRA << > > (decodedFrame.ptr(), decodedFrame.step, outFrame.ptr(), outFrame.step, width, height); CV_CUDEV_SAFE_CALL(cudaGetLastError()); if (stream == 0) CV_CUDEV_SAFE_CALL(cudaDeviceSynchronize()); diff --git a/modules/cudacodec/src/ffmpeg_video_source.cpp b/modules/cudacodec/src/ffmpeg_video_source.cpp index 815e5c8ce6..de0f349c4d 100644 --- a/modules/cudacodec/src/ffmpeg_video_source.cpp +++ b/modules/cudacodec/src/ffmpeg_video_source.cpp @@ -192,6 +192,10 @@ void cv::cudacodec::detail::FFmpegVideoSource::updateFormat(const FormatInfo& vi bool cv::cudacodec::detail::FFmpegVideoSource::get(const int propertyId, double& propertyVal) const { + propertyVal = cap.get(propertyId); + if (propertyVal != 0.) + return true; + CV_Assert(videoCaptureParams.size() % 2 == 0); for (std::size_t i = 0; i < videoCaptureParams.size(); i += 2) { if (videoCaptureParams.at(i) == propertyId) { @@ -199,6 +203,7 @@ bool cv::cudacodec::detail::FFmpegVideoSource::get(const int propertyId, double& return true; } } + return false; } diff --git a/modules/cudacodec/src/precomp.hpp b/modules/cudacodec/src/precomp.hpp index 99a788a012..004cf85c88 100644 --- a/modules/cudacodec/src/precomp.hpp +++ b/modules/cudacodec/src/precomp.hpp @@ -82,6 +82,7 @@ #include "frame_queue.hpp" #include "video_decoder.hpp" #include "video_parser.hpp" + #include #endif #if defined(HAVE_NVCUVENC) #include diff --git a/modules/cudacodec/src/video_parser.cpp b/modules/cudacodec/src/video_parser.cpp index 8bccd065a8..ce8b80fe10 100644 --- a/modules/cudacodec/src/video_parser.cpp +++ b/modules/cudacodec/src/video_parser.cpp @@ -115,6 +115,7 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa format->min_num_decode_surfaces != thiz->videoDecoder_->nDecodeSurfaces()) { FormatInfo newFormat; + newFormat.videoFullRangeFlag = format->video_signal_description.video_full_range_flag; newFormat.codec = static_cast(format->codec); newFormat.chromaFormat = static_cast(format->chroma_format); newFormat.nBitDepthMinus8 = format->bit_depth_luma_minus8; @@ -122,16 +123,16 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa newFormat.ulHeight = format->coded_height; newFormat.fps = format->frame_rate.numerator / static_cast(format->frame_rate.denominator); newFormat.targetSz = thiz->videoDecoder_->getTargetSz(); - newFormat.width = newFormat.targetSz.width ? newFormat.targetSz.width : format->coded_width; - newFormat.height = newFormat.targetSz.height ? newFormat.targetSz.height : format->coded_height; newFormat.srcRoi = thiz->videoDecoder_->getSrcRoi(); if (newFormat.srcRoi.empty()) { - format->display_area.right = format->coded_width; - format->display_area.bottom = format->coded_height; newFormat.displayArea = Rect(Point(format->display_area.left, format->display_area.top), Point(format->display_area.right, format->display_area.bottom)); + if (newFormat.targetSz.empty()) + newFormat.targetSz = Size((format->display_area.right - format->display_area.left), (format->display_area.bottom - format->display_area.top)); } else newFormat.displayArea = newFormat.srcRoi; + newFormat.width = newFormat.targetSz.width ? newFormat.targetSz.width : format->coded_width; + newFormat.height = newFormat.targetSz.height ? newFormat.targetSz.height : format->coded_height; newFormat.targetRoi = thiz->videoDecoder_->getTargetRoi(); newFormat.ulNumDecodeSurfaces = min(!thiz->allowFrameDrop_ ? max(thiz->videoDecoder_->nDecodeSurfaces(), static_cast(format->min_num_decode_surfaces)) : format->min_num_decode_surfaces * 2, 32); diff --git a/modules/cudacodec/src/video_reader.cpp b/modules/cudacodec/src/video_reader.cpp index a566bd4de7..3d71c3532e 100644 --- a/modules/cudacodec/src/video_reader.cpp +++ b/modules/cudacodec/src/video_reader.cpp @@ -53,27 +53,54 @@ Ptr cv::cudacodec::createVideoReader(const Ptr&, co #else // HAVE_NVCUVID -void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream); +void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const bool videoFullRangeFlag, cudaStream_t stream); bool ValidColorFormat(const ColorFormat colorFormat); -void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const ColorFormat colorFormat, +void cvtFromNv12(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const ColorFormat colorFormat, const bool videoFullRangeFlag, Stream stream) { + CV_Assert(decodedFrame.cols == width && decodedFrame.rows == height * 1.5f); if (colorFormat == ColorFormat::BGRA) { - nv12ToBgra(decodedFrame, outFrame, width, height, StreamAccessor::getStream(stream)); + nv12ToBgra(decodedFrame, outFrame, width, height, videoFullRangeFlag, StreamAccessor::getStream(stream)); } else if (colorFormat == ColorFormat::BGR) { outFrame.create(height, width, CV_8UC3); Npp8u* pSrc[2] = { decodedFrame.data, &decodedFrame.data[decodedFrame.step * height] }; NppiSize oSizeROI = { width,height }; +#if (CUDART_VERSION < 9200) + CV_Error(Error::StsUnsupportedFormat, "ColorFormat::BGR is not supported until CUDA 9.2, use default ColorFormat::BGRA."); +#elif (CUDART_VERSION < 10100) + cv::cuda::NppStreamHandler h(stream); + if (videoFullRangeFlag) + nppSafeCall(nppiNV12ToBGR_709HDTV_8u_P2C3R(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI)); + else { + CV_LOG_DEBUG(NULL, "Color reproduction may be inaccurate due CUDA version <= 11.0, for better results upgrade CUDA runtime or try ColorFormat::BGRA."); + nppSafeCall(nppiNV12ToBGR_8u_P2C3R(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI)); + } +#elif (CUDART_VERSION >= 10100) NppStreamContext nppStreamCtx; nppSafeCall(nppGetStreamContext(&nppStreamCtx)); nppStreamCtx.hStream = StreamAccessor::getStream(stream); - nppSafeCall(nppiNV12ToBGR_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); + if (videoFullRangeFlag) + nppSafeCall(nppiNV12ToBGR_709HDTV_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); + else { +#if (CUDART_VERSION < 11000) + CV_LOG_DEBUG(NULL, "Color reproduction may be inaccurate due CUDA version <= 11.0, for better results upgrade CUDA runtime or try ColorFormat::BGRA."); + nppSafeCall(nppiNV12ToBGR_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); +#else + nppSafeCall(nppiNV12ToBGR_709CSC_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); +#endif + } +#endif } else if (colorFormat == ColorFormat::GRAY) { outFrame.create(height, width, CV_8UC1); - cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, StreamAccessor::getStream(stream)); + if(videoFullRangeFlag) + cudaSafeCall(cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, StreamAccessor::getStream(stream))); + else { + cv::cuda::subtract(decodedFrame(Rect(0,0,width,height)), 16, outFrame, noArray(), CV_8U, stream); + cv::cuda::multiply(outFrame, 255.0f / 219.0f, outFrame, 1.0, CV_8U, stream); + } } else if (colorFormat == ColorFormat::NV_NV12) { decodedFrame.copyTo(outFrame, stream); @@ -222,9 +249,7 @@ namespace // map decoded video frame to CUDA surface GpuMat decodedFrame = videoDecoder_->mapFrame(frameInfo.first.picture_index, frameInfo.second); - // perform post processing on the CUDA surface (performs colors space conversion and post processing) - // comment this out if we include the line of code seen above - videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), colorFormat, stream); + cvtFromNv12(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), colorFormat, videoDecoder_->format().videoFullRangeFlag, stream); // unmap video frame // unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding) diff --git a/modules/cudacodec/test/test_video.cpp b/modules/cudacodec/test/test_video.cpp index b9b4e9f25c..a925123041 100644 --- a/modules/cudacodec/test/test_video.cpp +++ b/modules/cudacodec/test/test_video.cpp @@ -58,10 +58,19 @@ PARAM_TEST_CASE(Scaling, cv::cuda::DeviceInfo, std::string, Size2f, Rect2f, Rect { }; +struct DisplayResolution : testing::TestWithParam +{ +}; + PARAM_TEST_CASE(Video, cv::cuda::DeviceInfo, std::string) { }; +typedef tuple color_conversion_params_t; +PARAM_TEST_CASE(ColorConversion, cv::cuda::DeviceInfo, cv::cudacodec::ColorFormat, color_conversion_params_t) +{ +}; + PARAM_TEST_CASE(VideoReadRaw, cv::cuda::DeviceInfo, std::string) { }; @@ -220,7 +229,38 @@ CUDA_TEST_P(Scaling, Reader) cv::cuda::resize(frameOr(srcRoiOut), frameGs, targetRoiOut.size(), 0, 0, INTER_AREA); // assert on mean absolute error due to different resize algorithms const double mae = cv::cuda::norm(frameGs, frame(targetRoiOut), NORM_L1)/frameGs.size().area(); - ASSERT_LT(mae, 2.35); + ASSERT_LT(mae, 2.75); +} + +CUDA_TEST_P(DisplayResolution, Reader) +{ + cv::cuda::setDevice(GetParam().deviceID()); + std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/video/1920x1080.avi"; + const Rect displayArea(0, 0, 1920, 1080); + GpuMat frame; + + { + // verify the output frame is the diplay size (1920x1080) and not the coded size (1920x1088) + cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); + reader->set(cudacodec::ColorFormat::GRAY); + ASSERT_TRUE(reader->nextFrame(frame)); + const cudacodec::FormatInfo format = reader->format(); + ASSERT_TRUE(format.displayArea == displayArea); + ASSERT_TRUE(frame.size() == displayArea.size() && frame.size() == format.targetSz); + } + + { + // extra check to verify display frame has not been post-processed and is just a cropped version of the coded sized frame + cudacodec::VideoReaderInitParams params; + params.srcRoi = Rect(0, 0, 1920, 1088); + cv::Ptr readerCodedSz = cv::cudacodec::createVideoReader(inputFile, {}, params); + readerCodedSz->set(cudacodec::ColorFormat::GRAY); + GpuMat frameCodedSz; + ASSERT_TRUE(readerCodedSz->nextFrame(frameCodedSz)); + const cudacodec::FormatInfo formatCodedSz = readerCodedSz->format(); + const double err = cv::cuda::norm(frame, frameCodedSz(displayArea), NORM_INF); + ASSERT_TRUE(err == 0); + } } CUDA_TEST_P(Video, Reader) @@ -265,6 +305,33 @@ CUDA_TEST_P(Video, Reader) } } +CUDA_TEST_P(ColorConversion, Reader) +{ + cv::cuda::setDevice(GET_PARAM(0).deviceID()); + const cv::cudacodec::ColorFormat colorFormat = GET_PARAM(1); + const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + get<0>(GET_PARAM(2)); + const bool videoFullRangeFlag = get<1>(GET_PARAM(2)); + cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); + reader->set(colorFormat); + cv::VideoCapture cap(inputFile); + + cv::cuda::GpuMat frame; + Mat frameHost, frameHostGs, frameFromDevice; + for (int i = 0; i < 10; i++) + { + reader->nextFrame(frame); + frame.download(frameFromDevice); + cap.read(frameHost); + const cv::cudacodec::FormatInfo fmt = reader->format(); + ASSERT_TRUE(fmt.valid && fmt.videoFullRangeFlag == videoFullRangeFlag); + if (colorFormat == cv::cudacodec::ColorFormat::BGRA) + cv::cvtColor(frameHost, frameHostGs, COLOR_BGR2BGRA); + else + frameHostGs = frameHost; + EXPECT_MAT_NEAR(frameHostGs, frameFromDevice, 2.0); + } +} + CUDA_TEST_P(VideoReadRaw, Reader) { cv::cuda::setDevice(GET_PARAM(0).deviceID()); @@ -363,6 +430,19 @@ CUDA_TEST_P(CheckParams, Reader) } } +CUDA_TEST_P(CheckParams, CaptureProps) +{ + std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.mp4"; + cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); + double width, height, fps; + ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH, width)); + ASSERT_EQ(672, width); + ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT, height)); + ASSERT_EQ(384, height); + ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_FPS, fps)); + ASSERT_EQ(24, fps); +} + CUDA_TEST_P(CheckDecodeSurfaces, Reader) { cv::cuda::setDevice(GET_PARAM(0).deviceID()); @@ -487,6 +567,7 @@ CUDA_TEST_P(TransCode, H264ToH265) } INSTANTIATE_TEST_CASE_P(CUDA_Codec, TransCode, ALL_DEVICES); + #endif #if defined(HAVE_NVCUVENC) @@ -664,6 +745,8 @@ INSTANTIATE_TEST_CASE_P(CUDA_Codec, CheckSet, testing::Combine( INSTANTIATE_TEST_CASE_P(CUDA_Codec, Scaling, testing::Combine( ALL_DEVICES, testing::Values(VIDEO_SRC_SCALING), testing::Values(TARGET_SZ), testing::Values(SRC_ROI), testing::Values(TARGET_ROI))); +INSTANTIATE_TEST_CASE_P(CUDA_Codec, DisplayResolution, ALL_DEVICES); + #define VIDEO_SRC_R "highgui/video/big_buck_bunny.mp4", "cv/video/768x576.avi", "cv/video/1920x1080.avi", "highgui/video/big_buck_bunny.avi", \ "highgui/video/big_buck_bunny.h264", "highgui/video/big_buck_bunny.h265", "highgui/video/big_buck_bunny.mpg", \ "highgui/video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4", "highgui/video/sample_322x242_15frames.yuv420p.libaom-av1.mp4", \ @@ -672,6 +755,18 @@ INSTANTIATE_TEST_CASE_P(CUDA_Codec, Video, testing::Combine( ALL_DEVICES, testing::Values(VIDEO_SRC_R))); +const color_conversion_params_t color_conversion_params[] = +{ + color_conversion_params_t("highgui/video/big_buck_bunny.h264", false), + color_conversion_params_t("highgui/video/big_buck_bunny_full_color_range.h264", true), +}; + +#define VIDEO_COLOR_OUTPUTS cv::cudacodec::ColorFormat::BGRA, cv::cudacodec::ColorFormat::BGRA +INSTANTIATE_TEST_CASE_P(CUDA_Codec, ColorConversion, testing::Combine( + ALL_DEVICES, + testing::Values(VIDEO_COLOR_OUTPUTS), + testing::ValuesIn(color_conversion_params))); + #define VIDEO_SRC_RW "highgui/video/big_buck_bunny.h264", "highgui/video/big_buck_bunny.h265" INSTANTIATE_TEST_CASE_P(CUDA_Codec, VideoReadRaw, testing::Combine( ALL_DEVICES, diff --git a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp index e9ad379b95..9ee50c7305 100644 --- a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp +++ b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp @@ -425,6 +425,9 @@ class CV_EXPORTS_W HoughSegmentDetector : public Algorithm CV_WRAP virtual void setMaxLines(int maxLines) = 0; CV_WRAP virtual int getMaxLines() const = 0; + + CV_WRAP virtual void setThreshold(int threshold) = 0; + CV_WRAP virtual int getThreshold() const = 0; }; /** @brief Creates implementation for cuda::HoughSegmentDetector . @@ -434,8 +437,10 @@ class CV_EXPORTS_W HoughSegmentDetector : public Algorithm @param minLineLength Minimum line length. Line segments shorter than that are rejected. @param maxLineGap Maximum allowed gap between points on the same line to link them. @param maxLines Maximum number of output lines. +@param threshold %Accumulator threshold parameter. Only those lines are returned that get enough +votes ( \f$>\texttt{threshold}\f$ ). */ -CV_EXPORTS_W Ptr createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096); +CV_EXPORTS_W Ptr createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096, int threshold = -1); ////////////////////////////////////// // HoughCircles diff --git a/modules/cudaimgproc/src/cuda/hough_segments.cu b/modules/cudaimgproc/src/cuda/hough_segments.cu index 3f4c3aff87..2ad7f1f1da 100644 --- a/modules/cudaimgproc/src/cuda/hough_segments.cu +++ b/modules/cudaimgproc/src/cuda/hough_segments.cu @@ -55,6 +55,7 @@ namespace cv { namespace cuda { namespace device int4* out, const int maxSize, const float rho, const float theta, const int lineGap, const int lineLength, + const int threshold, const int rows, const int cols, int* counterPtr) { @@ -65,8 +66,9 @@ namespace cv { namespace cuda { namespace device return; const int curVotes = accum(n + 1, r + 1); + const int threshold_ = (threshold > 0) ? threshold : lineLength; - if (curVotes >= lineLength && + if (curVotes >= threshold_ && curVotes > accum(n, r) && curVotes > accum(n, r + 1) && curVotes > accum(n, r + 2) && @@ -213,7 +215,7 @@ namespace cv { namespace cuda { namespace device } } - int houghLinesProbabilistic_gpu(GpuMat &mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength, int* counterPtr, cudaStream_t stream) + int houghLinesProbabilistic_gpu(GpuMat &mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength, int threshold, int* counterPtr, cudaStream_t stream) { cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) ); @@ -225,11 +227,11 @@ namespace cv { namespace cuda { namespace device mask.locateROI(wholeSize, ofs); if (ofs.x || ofs.y) { cv::cudev::TextureOff texMask(wholeSize.height, wholeSize.width, mask.datastart, mask.step, ofs.y, ofs.x); - houghLinesProbabilistic><<>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, mask.rows, mask.cols, counterPtr); + houghLinesProbabilistic><<>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, threshold, mask.rows, mask.cols, counterPtr); } else { cv::cudev::Texture texMask(mask); - houghLinesProbabilistic><<>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, mask.rows, mask.cols, counterPtr); + houghLinesProbabilistic><<>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, threshold, mask.rows, mask.cols, counterPtr); } cudaSafeCall( cudaGetLastError() ); diff --git a/modules/cudaimgproc/src/hough_segments.cpp b/modules/cudaimgproc/src/hough_segments.cpp index 70bd84f00a..d4e2e95f40 100644 --- a/modules/cudaimgproc/src/hough_segments.cpp +++ b/modules/cudaimgproc/src/hough_segments.cpp @@ -47,7 +47,7 @@ using namespace cv::cuda; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -Ptr cv::cuda::createHoughSegmentDetector(float, float, int, int, int) { throw_no_cuda(); return Ptr(); } +Ptr cv::cuda::createHoughSegmentDetector(float, float, int, int, int, int) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -65,7 +65,7 @@ namespace cv { namespace cuda { namespace device namespace hough_segments { - int houghLinesProbabilistic_gpu(GpuMat &mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength, int* counterPtr, cudaStream_t stream); + int houghLinesProbabilistic_gpu(GpuMat &mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength, int threshold, int* counterPtr, cudaStream_t stream); } }}} @@ -74,7 +74,7 @@ namespace class HoughSegmentDetectorImpl : public HoughSegmentDetector { public: - HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines); + HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines, int threshold); ~HoughSegmentDetectorImpl(); void detect(InputArray src, OutputArray lines, Stream& stream); @@ -94,6 +94,9 @@ namespace void setMaxLines(int maxLines) { maxLines_ = maxLines; } int getMaxLines() const { return maxLines_; } + void setThreshold(int threshold) { threshold_ = threshold; } + int getThreshold() const { return threshold_; } + void write(FileStorage& fs) const { writeFormat(fs); @@ -102,7 +105,8 @@ namespace << "theta" << theta_ << "minLineLength" << minLineLength_ << "maxLineGap" << maxLineGap_ - << "maxLines" << maxLines_; + << "maxLines" << maxLines_ + << "threshold" << threshold_; } void read(const FileNode& fn) @@ -113,6 +117,7 @@ namespace minLineLength_ = (int)fn["minLineLength"]; maxLineGap_ = (int)fn["maxLineGap"]; maxLines_ = (int)fn["maxLines"]; + threshold_ = (int)fn["threshold"]; } private: @@ -121,6 +126,7 @@ namespace int minLineLength_; int maxLineGap_; int maxLines_; + int threshold_; GpuMat accum_; GpuMat list_; @@ -129,8 +135,8 @@ namespace int* counterPtr_; }; - HoughSegmentDetectorImpl::HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) : - rho_(rho), theta_(theta), minLineLength_(minLineLength), maxLineGap_(maxLineGap), maxLines_(maxLines) + HoughSegmentDetectorImpl::HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines, int threshold) : + rho_(rho), theta_(theta), minLineLength_(minLineLength), maxLineGap_(maxLineGap), maxLines_(maxLines), threshold_(threshold) { cudaSafeCall(cudaMalloc(&counterPtr_, sizeof(int))); } @@ -178,7 +184,7 @@ namespace ensureSizeIsEnough(1, maxLines_, CV_32SC4, result_); - int linesCount = houghLinesProbabilistic_gpu(src, accum_, result_.ptr(), maxLines_, rho_, theta_, maxLineGap_, minLineLength_, counterPtr_, cudaStream); + int linesCount = houghLinesProbabilistic_gpu(src, accum_, result_.ptr(), maxLines_, rho_, theta_, maxLineGap_, minLineLength_, threshold_, counterPtr_, cudaStream); if (linesCount == 0) { @@ -191,9 +197,9 @@ namespace } } -Ptr cv::cuda::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) +Ptr cv::cuda::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines, int threshold) { - return makePtr(rho, theta, minLineLength, maxLineGap, maxLines); + return makePtr(rho, theta, minLineLength, maxLineGap, maxLines, threshold); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/datasets/src/fr_adience.cpp b/modules/datasets/src/fr_adience.cpp index 7517aa4a99..49fa242f9d 100644 --- a/modules/datasets/src/fr_adience.cpp +++ b/modules/datasets/src/fr_adience.cpp @@ -172,7 +172,6 @@ void FR_adienceImp::cv5ToSplits(vector< Ptr > fileList[5]) void FR_adienceImp::loadDataset(const string &path) { // collect real image names - unsigned int num = 0; vector userNames; getDirList(path+"faces/", userNames); for (vector::iterator itU=userNames.begin(); itU!=userNames.end(); ++itU) @@ -185,11 +184,9 @@ void FR_adienceImp::loadDataset(const string &path) if (name.length()>3 && name.substr(name.length()-4) == ".jpg") { realNames[*itU].push_back(name); - num++; } } } - //printf("total images number: %u\n", num); vector< Ptr > fileList[5]; for (unsigned int i=0; i<5; ++i) diff --git a/modules/datasets/src/track_alov.cpp b/modules/datasets/src/track_alov.cpp index 2213c0f68a..0862ba0f84 100644 --- a/modules/datasets/src/track_alov.cpp +++ b/modules/datasets/src/track_alov.cpp @@ -247,7 +247,6 @@ void TRACK_alovImpl::loadDataset(const string &rootPath) void TRACK_alovImpl::loadDatasetAnnotatedOnly(const string &rootPath) { vector datasetsLengths; - int currDatasetID = 0; printf("ALOV300++ Annotated Dataset Initialization...\n"); @@ -258,7 +257,6 @@ void TRACK_alovImpl::loadDatasetAnnotatedOnly(const string &rootPath) for (int k = 0; k < sectionSizes[i]; k++) { vector > objects; - currDatasetID++; //Open dataset's ground truth (annotation) file string annoPath = fullAnnoPath(rootPath, i, k); diff --git a/modules/intensity_transform/src/bimef.cpp b/modules/intensity_transform/src/bimef.cpp index 72555ed977..2500d2abe8 100644 --- a/modules/intensity_transform/src/bimef.cpp +++ b/modules/intensity_transform/src/bimef.cpp @@ -345,7 +345,6 @@ static double minimize_scalar_bounded(const Mat_& I, double begin, double double rat = 0.0, e = 0.0; double x = xf; double fx = -entropy(applyK(I, static_cast(x))); - int num = 1; double fu = std::numeric_limits::infinity(); double ffulc = fx, fnfc = fx; @@ -398,7 +397,6 @@ static double minimize_scalar_bounded(const Mat_& I, double begin, double double si = sgn(rat) + (rat == 0); x = xf + si * std::max(std::abs(rat), tol1); fu = -entropy(applyK(I, static_cast(x))); - num += 1; if (fu <= fx) { if (x >= xf) { diff --git a/modules/line_descriptor/src/binary_descriptor_matcher.cpp b/modules/line_descriptor/src/binary_descriptor_matcher.cpp index b74a8acc2d..93e0b55076 100644 --- a/modules/line_descriptor/src/binary_descriptor_matcher.cpp +++ b/modules/line_descriptor/src/binary_descriptor_matcher.cpp @@ -639,14 +639,6 @@ void BinaryDescriptorMatcher::Mihasher::query( UINT32* results, UINT32* numres, /* number of results so far obtained (up to a distance of s per chunk) */ UINT32 n = 0; - /* number of candidates tested with full codes (not counting duplicates) */ - UINT32 nc = 0; - - /* counting everything retrieved (duplicates are counted multiple times) - number of lookups (and xors) */ - UINT32 nl = 0; - - UINT32 nd = 0; UINT32 *arr; int size = 0; UINT32 index; @@ -672,8 +664,6 @@ void BinaryDescriptorMatcher::Mihasher::query( UINT32* results, UINT32* numres, else curb = b - 1; UINT64 chunksk = chunks[k]; - /* number of bit-strings with s number of 1s */ - nl += xornum[s + 1] - xornum[s]; /* the bit-string with s number of 1s */ UINT64 bitstr = 0; @@ -706,7 +696,6 @@ void BinaryDescriptorMatcher::Mihasher::query( UINT32* results, UINT32* numres, arr = H[k].query( chunksk ^ bitstr, &size ); // lookup if( size ) { /* the corresponding bucket is not empty */ - nd += size; for ( int c = 0; c < size; c++ ) { index = arr[c]; @@ -715,7 +704,6 @@ void BinaryDescriptorMatcher::Mihasher::query( UINT32* results, UINT32* numres, counter->set( index ); hammd = cv::line_descriptor::match( codes.ptr() + (UINT64) index * ( B_over_8 ), Query, B_over_8 ); - nc++; if( hammd <= D && numres[hammd] < maxres ) res[hammd * K + numres[hammd]] = index + 1; diff --git a/modules/optflow/src/motempl.cpp b/modules/optflow/src/motempl.cpp index 83ff017390..5f74c7a46c 100644 --- a/modules/optflow/src/motempl.cpp +++ b/modules/optflow/src/motempl.cpp @@ -157,8 +157,6 @@ void calcMotionGradient( InputArray _mhi, OutputArray _mask, double delta1, double delta2, int aperture_size ) { - static int runcase = 0; runcase++; - Mat mhi = _mhi.getMat(); Size size = mhi.size(); diff --git a/modules/optflow/src/rlof/berlof_invoker.hpp b/modules/optflow/src/rlof/berlof_invoker.hpp index ac866fe534..8fde6e457c 100644 --- a/modules/optflow/src/rlof/berlof_invoker.hpp +++ b/modules/optflow/src/rlof/berlof_invoker.hpp @@ -189,9 +189,6 @@ class TrackerInvoker : public cv::ParallelLoopBody int buffIdx = 0; cv::Mat GMc0, GMc1, GMc2, GMc3; cv::Vec2f Mc0, Mc1, Mc2, Mc3; - int noIteration = 0; - int noReusedIteration = 0; - int noSolvedIteration = 0; for( j = 0; j < criteria.maxCount; j++ ) { cv::Point2f delta(0,0); @@ -536,7 +533,6 @@ class TrackerInvoker : public cv::ParallelLoopBody { nextPts[ptidx] = backUpNextPt; } - noIteration++; break; } @@ -612,13 +608,10 @@ class TrackerInvoker : public cv::ParallelLoopBody delta.y = inextPt.y + b - nextPt.y; } // isIn1 != isIn2 } - if( hasSolved == false) - noIteration++; } else { hasSolved = false; - noReusedIteration++; } if( hasSolved == false ) { @@ -635,7 +628,6 @@ class TrackerInvoker : public cv::ParallelLoopBody { nextPt += delta; nextPts[ptidx] = nextPt - halfWin; - noSolvedIteration++; break; } @@ -832,9 +824,6 @@ class TrackerInvoker : public cv::ParallelLoopBody int buffIdx = 0; cv::Mat GMc0, GMc1, GMc2, GMc3; cv::Vec4f Mc0, Mc1, Mc2, Mc3; - int noIteration = 0; - int noReusedIteration = 0; - int noSolvedIteration = 0; for( j = 0; j < criteria.maxCount; j++ ) { cv::Point2f delta(0,0); @@ -859,7 +848,6 @@ class TrackerInvoker : public cv::ParallelLoopBody nextPts[ptidx] = backUpNextPt; gainVecs[ptidx] = backUpGain; } - noIteration++; break; } @@ -1287,7 +1275,6 @@ class TrackerInvoker : public cv::ParallelLoopBody nextPts[ptidx] = backUpNextPt; gainVecs[ptidx] = backUpGain; } - noIteration++; break; } @@ -1399,13 +1386,10 @@ class TrackerInvoker : public cv::ParallelLoopBody } // isIn1 != isIn2 } - if( hasSolved == false) - noIteration++; } else { hasSolved = false; - noReusedIteration++; } if( hasSolved == false ) { @@ -1430,7 +1414,6 @@ class TrackerInvoker : public cv::ParallelLoopBody nextPt += delta; nextPts[ptidx] = nextPt - halfWin; gainVecs[ptidx]= gainVec + deltaGain; - noSolvedIteration++; break; } @@ -1998,9 +1981,6 @@ namespace radial { int j; cv::Mat GMc0, GMc1, GMc2, GMc3; cv::Vec4f Mc0, Mc1, Mc2, Mc3; - int noIteration = 0; - int noReusedIteration = 0; - int noSolvedIteration = 0; for (j = 0; j < criteria.maxCount; j++) { cv::Point2f delta(0, 0); @@ -2025,7 +2005,6 @@ namespace radial { nextPts[ptidx] = backUpNextPt; gainVecs[ptidx] = backUpGain; } - noIteration++; break; } @@ -2291,7 +2270,6 @@ namespace radial { nextPts[ptidx] = backUpNextPt; gainVecs[ptidx] = backUpGain; } - noIteration++; break; } @@ -2403,13 +2381,10 @@ namespace radial { } // isIn1 != isIn2 } - if (hasSolved == false) - noIteration++; } else { hasSolved = false; - noReusedIteration++; } if (hasSolved == false) { @@ -2434,7 +2409,6 @@ namespace radial { nextPt += delta; nextPts[ptidx] = nextPt - halfWin; gainVecs[ptidx] = gainVec + deltaGain; - noSolvedIteration++; break; } diff --git a/modules/optflow/src/rlof/geo_interpolation.cpp b/modules/optflow/src/rlof/geo_interpolation.cpp index 0ac2e1715d..4e625a1a95 100644 --- a/modules/optflow/src/rlof/geo_interpolation.cpp +++ b/modules/optflow/src/rlof/geo_interpolation.cpp @@ -297,15 +297,12 @@ Mat interpolate_irregular_knn( } } - int global_time = 0; - bool done = false; while (!done) { if (my_agents.size() == 0) { done = true; break; } - global_time++; std::multimap::iterator current_it = my_agents.begin(); std::pair current_p = *current_it; diff --git a/modules/rgbd/src/nonrigid_icp.cpp b/modules/rgbd/src/nonrigid_icp.cpp index bd3419aeb4..43f0c951ac 100644 --- a/modules/rgbd/src/nonrigid_icp.cpp +++ b/modules/rgbd/src/nonrigid_icp.cpp @@ -365,9 +365,6 @@ bool ICPImpl::estimateWarpNodes(WarpField& currentWarp, const Affine3f &pose, std::cout << "median: " << med << " from " << residuals.size() << " residuals " << std::endl; float sigma = MAD_SCALE * median(residuals); - float total_error = 0; - int pix_count = 0; - for(int y = 0; y < oldPoints.size().height; y++) { for(int x = 0; x < oldPoints.size().width; x++) @@ -395,9 +392,6 @@ bool ICPImpl::estimateWarpNodes(WarpField& currentWarp, const Affine3f &pose, float rd = Nc.at(y, x).dot(diff); - total_error += tukeyWeight(rd, sigma) * rd * rd; - pix_count++; - int n; nodeNeighboursType neighbours = volume->getVoxelNeighbours(p, n); float totalNeighbourWeight = 0.f; diff --git a/modules/structured_light/src/graycodepattern.cpp b/modules/structured_light/src/graycodepattern.cpp index 315a96fbc6..f37bc3bb52 100644 --- a/modules/structured_light/src/graycodepattern.cpp +++ b/modules/structured_light/src/graycodepattern.cpp @@ -259,9 +259,6 @@ bool GrayCodePattern_Impl::decode( const std::vector< std::vector >& patter Mat& disparityMap_ = *( Mat* ) disparityMap.getObj(); disparityMap_ = Mat( cam_height, cam_width, CV_64F, double( 0 ) ); - double number_of_pixels_cam1 = 0; - double number_of_pixels_cam2 = 0; - for( int i = 0; i < params.width; i++ ) { for( int j = 0; j < params.height; j++ ) @@ -278,8 +275,6 @@ bool GrayCodePattern_Impl::decode( const std::vector< std::vector >& patter double sump1x = 0; double sump2x = 0; - number_of_pixels_cam1 += cam1Pixs.size(); - number_of_pixels_cam2 += cam2Pixs.size(); for( int c1 = 0; c1 < (int) cam1Pixs.size(); c1++ ) { p1 = cam1Pixs[c1]; diff --git a/modules/surface_matching/src/icp.cpp b/modules/surface_matching/src/icp.cpp index 684ebd5660..b3c07ecc4c 100644 --- a/modules/surface_matching/src/icp.cpp +++ b/modules/surface_matching/src/icp.cpp @@ -367,7 +367,7 @@ int ICP::registerModelToScene(const Mat& srcPC, const Mat& dstPC, double& residu if (node) { // select the first node - size_t idx = reinterpret_cast(node->data)-1, dn=0; + size_t idx = reinterpret_cast(node->data)-1; int dup = (int)node->key-1; size_t minIdxD = idx; float minDist = distances[idx]; @@ -383,7 +383,6 @@ int ICP::registerModelToScene(const Mat& srcPC, const Mat& dstPC, double& residu } node = node->next; - dn++; } indicesModel[ selInd ] = newI[ minIdxD ]; diff --git a/modules/text/include/opencv2/text/ocr.hpp b/modules/text/include/opencv2/text/ocr.hpp index 6cb23fa4ee..a0c967e87b 100644 --- a/modules/text/include/opencv2/text/ocr.hpp +++ b/modules/text/include/opencv2/text/ocr.hpp @@ -153,14 +153,16 @@ class CV_EXPORTS_W OCRTesseract : public BaseOCR @param datapath the name of the parent directory of tessdata ended with "/", or NULL to use the system's default directory. @param language an ISO 639-3 code or NULL will default to "eng". - @param char_whitelist specifies the list of characters used for recognition. NULL defaults to - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ". + @param char_whitelist specifies the list of characters used for recognition. NULL defaults to "" + (All characters will be used for recognition). @param oem tesseract-ocr offers different OCR Engine Modes (OEM), by default tesseract::OEM_DEFAULT is used. See the tesseract-ocr API documentation for other possible values. @param psmode tesseract-ocr offers different Page Segmentation Modes (PSM) tesseract::PSM_AUTO (fully automatic layout analysis) is used. See the tesseract-ocr API documentation for other possible values. + + @note The char_whitelist default is changed after OpenCV 4.7.0/3.19.0 from "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" to "". */ CV_WRAP static Ptr create(const char* datapath=NULL, const char* language=NULL, const char* char_whitelist=NULL, int oem=OEM_DEFAULT, int psmode=PSM_AUTO); diff --git a/modules/text/src/ocr_beamsearch_decoder.cpp b/modules/text/src/ocr_beamsearch_decoder.cpp index 6f34056ed9..2bf630da71 100644 --- a/modules/text/src/ocr_beamsearch_decoder.cpp +++ b/modules/text/src/ocr_beamsearch_decoder.cpp @@ -611,7 +611,6 @@ void OCRBeamSearchClassifierCNN::eval( InputArray _src, vector< vector > img = src(Rect(Point(x_c,0),Size(window_size,window_size))); - int patch_count = 0; vector< vector > data_pool(9); @@ -652,7 +651,6 @@ void OCRBeamSearchClassifierCNN::eval( InputArray _src, vector< vector > data_pool[7].insert(data_pool[7].end(),patch.begin(),patch.end()); if ((quad_id == 19)||(quad_id == 24)||(quad_id == 20)||(quad_id == 25)) data_pool[8].insert(data_pool[8].end(),patch.begin(),patch.end()); - patch_count++; } } diff --git a/modules/text/src/ocr_hmm_decoder.cpp b/modules/text/src/ocr_hmm_decoder.cpp index 6d61578bda..688b529ea3 100644 --- a/modules/text/src/ocr_hmm_decoder.cpp +++ b/modules/text/src/ocr_hmm_decoder.cpp @@ -1028,7 +1028,6 @@ void OCRHMMClassifierCNN::eval( InputArray _src, vector& out_class, vector< Mat quad; Mat tmp; - int patch_count = 0; vector< vector > data_pool(9); @@ -1071,7 +1070,6 @@ void OCRHMMClassifierCNN::eval( InputArray _src, vector& out_class, vector< data_pool[7].insert(data_pool[7].end(),patch.begin(),patch.end()); if ((quad_id == 19)||(quad_id == 24)||(quad_id == 20)||(quad_id == 25)) data_pool[8].insert(data_pool[8].end(),patch.begin(),patch.end()); - patch_count++; } } diff --git a/modules/text/src/ocr_tesseract.cpp b/modules/text/src/ocr_tesseract.cpp index d04c698e17..90a29ea420 100644 --- a/modules/text/src/ocr_tesseract.cpp +++ b/modules/text/src/ocr_tesseract.cpp @@ -163,10 +163,12 @@ class OCRTesseractImpl CV_FINAL : public OCRTesseract tesseract::PageSegMode pagesegmode = (tesseract::PageSegMode)psmode; tess.SetPageSegMode(pagesegmode); + // tessedit_whitelist default changes from [0-9a-zA-Z] to "". + // See https://github.com/opencv/opencv_contrib/issues/3457 if(char_whitelist != NULL) tess.SetVariable("tessedit_char_whitelist", char_whitelist); else - tess.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + tess.SetVariable("tessedit_char_whitelist", ""); tess.SetVariable("save_best_choices", "T"); #else diff --git a/modules/text/src/text_detector_swt.cpp b/modules/text/src/text_detector_swt.cpp index 75178a5df5..ba2d2dd0e2 100644 --- a/modules/text/src/text_detector_swt.cpp +++ b/modules/text/src/text_detector_swt.cpp @@ -597,7 +597,6 @@ vector findValidChains(const Mat& input_image, const Mat& SWTImage, co avgCompi.Blue /= compi.points.size(); colorAverages.push_back(avgCompi); } - int count = 0; std::vector chains; for (size_t i = 0; i < components.size(); i++) { const Component& compi = components[i]; @@ -632,7 +631,6 @@ vector findValidChains(const Mat& input_image, const Mat& SWTImage, co dir.y = dy; chain.dir = dir; chains.push_back(chain); - count++; } } diff --git a/modules/tracking/src/multiTracker.cpp b/modules/tracking/src/multiTracker.cpp index 963e6eb657..a1451857b9 100644 --- a/modules/tracking/src/multiTracker.cpp +++ b/modules/tracking/src/multiTracker.cpp @@ -207,15 +207,12 @@ using namespace impl; tld::TrackerTLDImpl::Nexpert nExpert(imageForDetector, boundingBoxes[k], tldModel->detector, tracker->params); std::vector > examplesForModel, examplesForEnsemble; examplesForModel.reserve(100); examplesForEnsemble.reserve(100); - int negRelabeled = 0; for (int i = 0; i < (int)detectorResults[k].size(); i++) { bool expertResult; if (detectorResults[k][i].isObject) { expertResult = nExpert(detectorResults[k][i].rect); - if (expertResult != detectorResults[k][i].isObject) - negRelabeled++; } else { @@ -279,8 +276,6 @@ namespace impl { Mat tmp; int dx = initSize.width / 10, dy = initSize.height / 10; Size2d size = img.size(); - double scale = 1.0; - int npos = 0, nneg = 0; double maxSc = -5.0; Rect2d maxScRect; int scaleID; @@ -348,7 +343,6 @@ namespace impl { scaleID++; size.width /= tld::SCALE_STEP; size.height /= tld::SCALE_STEP; - scale *= tld::SCALE_STEP; resize(img, tmp, size, 0, 0, tld::DOWNSCALE_MODE); resized_imgs.push_back(tmp); GaussianBlur(resized_imgs[scaleID], tmp, tld::GaussBlurKernelSize, 0.0f); @@ -406,8 +400,6 @@ namespace impl { //TLD Model Extraction tldModel = ((tld::TrackerTLDModel*)static_cast(tracker->getModel())); - npos = 0; - nneg = 0; maxSc = -5.0; for (int i = 0; i < (int)ensBuffer[k].size(); i++) @@ -429,13 +421,8 @@ namespace impl { if (!labPatch.isObject) { - nneg++; continue; } - else - { - npos++; - } scValue = tldModel->detector->Sc(standardPatch); if (scValue > maxSc) { @@ -474,8 +461,6 @@ namespace impl { Mat tmp; int dx = initSize.width / 10, dy = initSize.height / 10; Size2d size = img.size(); - double scale = 1.0; - int npos = 0, nneg = 0; double maxSc = -5.0; Rect2d maxScRect; int scaleID; @@ -543,7 +528,6 @@ namespace impl { scaleID++; size.width /= tld::SCALE_STEP; size.height /= tld::SCALE_STEP; - scale *= tld::SCALE_STEP; resize(img, tmp, size, 0, 0, tld::DOWNSCALE_MODE); resized_imgs.push_back(tmp); GaussianBlur(resized_imgs[scaleID], tmp, tld::GaussBlurKernelSize, 0.0f); @@ -600,8 +584,6 @@ namespace impl { tracker = static_cast(trackerPtr); //TLD Model Extraction tldModel = ((tld::TrackerTLDModel*)static_cast(tracker->getModel())); - npos = 0; - nneg = 0; maxSc = -5.0; //Prepare batch of patches @@ -641,13 +623,8 @@ namespace impl { if (!labPatch.isObject) { - nneg++; continue; } - else - { - npos++; - } scValue = resultSc[i]; if (scValue > maxSc) { diff --git a/modules/tracking/src/tldDetector.cpp b/modules/tracking/src/tldDetector.cpp index 8268821355..b3612a1a96 100644 --- a/modules/tracking/src/tldDetector.cpp +++ b/modules/tracking/src/tldDetector.cpp @@ -363,8 +363,6 @@ namespace tld { Mat tmp; int dx = initSize.width / 10, dy = initSize.height / 10; Size2d size = img.size(); - double scale = 1.0; - int npos = 0, nneg = 0; double maxSc = -5.0; Rect2d maxScRect; int scaleID; @@ -398,7 +396,6 @@ namespace tld { scaleID++; size.width /= SCALE_STEP; size.height /= SCALE_STEP; - scale *= SCALE_STEP; resize(img, tmp, size, 0, 0, DOWNSCALE_MODE); resized_imgs.push_back(tmp); GaussianBlur(resized_imgs[scaleID], tmp, GaussBlurKernelSize, 0.0f); @@ -453,13 +450,8 @@ namespace tld { if (!labPatch.isObject) { - nneg++; continue; } - else - { - npos++; - } if (scValue > maxSc) { @@ -485,8 +477,6 @@ namespace tld { Mat tmp; int dx = initSize.width / 10, dy = initSize.height / 10; Size2d size = img.size(); - double scale = 1.0; - int npos = 0, nneg = 0; double maxSc = -5.0; Rect2d maxScRect; int scaleID; @@ -516,7 +506,6 @@ namespace tld { scaleID++; size.width /= SCALE_STEP; size.height /= SCALE_STEP; - scale *= SCALE_STEP; resize(img, tmp, size, 0, 0, DOWNSCALE_MODE); resized_imgs.push_back(tmp); GaussianBlur(resized_imgs[scaleID], tmp, GaussBlurKernelSize, 0.0f); @@ -572,13 +561,8 @@ namespace tld { if (!labPatch.isObject) { - nneg++; continue; } - else - { - npos++; - } scValue = resultSc[i]; if (scValue > maxSc) { diff --git a/modules/tracking/src/tldModel.cpp b/modules/tracking/src/tldModel.cpp index ad787ab8e0..8f9a8f43c8 100644 --- a/modules/tracking/src/tldModel.cpp +++ b/modules/tracking/src/tldModel.cpp @@ -150,7 +150,6 @@ namespace tld { void TrackerTLDModel::integrateRelabeled(Mat& img, Mat& imgBlurred, const std::vector& patches) { Mat_ standardPatch(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE), blurredPatch(minSize_); - int positiveIntoModel = 0, negativeIntoModel = 0, positiveIntoEnsemble = 0, negativeIntoEnsemble = 0; for (int k = 0; k < (int)patches.size(); k++) { if (patches[k].shouldBeIntegrated) @@ -158,12 +157,10 @@ namespace tld { resample(img, patches[k].rect, standardPatch); if (patches[k].isObject) { - positiveIntoModel++; pushIntoModel(standardPatch, true); } else { - negativeIntoModel++; pushIntoModel(standardPatch, false); } } @@ -175,10 +172,6 @@ namespace tld { #endif { resample(imgBlurred, patches[k].rect, blurredPatch); - if (patches[k].isObject) - positiveIntoEnsemble++; - else - negativeIntoEnsemble++; for (int i = 0; i < (int)detector->classifiers.size(); i++) detector->classifiers[i].integrate(blurredPatch, patches[k].isObject); } @@ -212,7 +205,6 @@ namespace tld { void TrackerTLDModel::integrateAdditional(const std::vector >& eForModel, const std::vector >& eForEnsemble, bool isPositive) { - int positiveIntoModel = 0, negativeIntoModel = 0, positiveIntoEnsemble = 0, negativeIntoEnsemble = 0; if ((int)eForModel.size() == 0) return; srValues.resize (eForModel.size ()); @@ -225,12 +217,10 @@ namespace tld { { if (isPositive) { - positiveIntoModel++; pushIntoModel(eForModel[k], true); } else { - negativeIntoModel++; pushIntoModel(eForModel[k], false); } } @@ -240,10 +230,6 @@ namespace tld { p /= detector->classifiers.size(); if ((p > ENSEMBLE_THRESHOLD) != isPositive) { - if (isPositive) - positiveIntoEnsemble++; - else - negativeIntoEnsemble++; for (int i = 0; i < (int)detector->classifiers.size(); i++) detector->classifiers[i].integrate(eForEnsemble[k], isPositive); } @@ -253,7 +239,6 @@ namespace tld { #ifdef HAVE_OPENCL void TrackerTLDModel::ocl_integrateAdditional(const std::vector >& eForModel, const std::vector >& eForEnsemble, bool isPositive) { - int positiveIntoModel = 0, negativeIntoModel = 0, positiveIntoEnsemble = 0, negativeIntoEnsemble = 0; if ((int)eForModel.size() == 0) return; //Prepare batch of patches @@ -279,12 +264,10 @@ namespace tld { { if (isPositive) { - positiveIntoModel++; pushIntoModel(eForModel[k], true); } else { - negativeIntoModel++; pushIntoModel(eForModel[k], false); } } @@ -294,10 +277,6 @@ namespace tld { p /= detector->classifiers.size(); if ((p > ENSEMBLE_THRESHOLD) != isPositive) { - if (isPositive) - positiveIntoEnsemble++; - else - negativeIntoEnsemble++; for (int i = 0; i < (int)detector->classifiers.size(); i++) detector->classifiers[i].integrate(eForEnsemble[k], isPositive); } diff --git a/modules/tracking/src/tldTracker.cpp b/modules/tracking/src/tldTracker.cpp index 92038ef2d5..d4219fbdee 100644 --- a/modules/tracking/src/tldTracker.cpp +++ b/modules/tracking/src/tldTracker.cpp @@ -207,15 +207,12 @@ bool TrackerTLDImpl::updateImpl(const Mat& image, Rect2d& boundingBox) Nexpert nExpert(imageForDetector, boundingBox, tldModel->detector, params); std::vector > examplesForModel, examplesForEnsemble; examplesForModel.reserve(100); examplesForEnsemble.reserve(100); - int negRelabeled = 0; for( int i = 0; i < (int)detectorResults.size(); i++ ) { bool expertResult; if( detectorResults[i].isObject ) { expertResult = nExpert(detectorResults[i].rect); - if( expertResult != detectorResults[i].isObject ) - negRelabeled++; } else { diff --git a/modules/tracking/src/trackerSamplerAlgorithm.cpp b/modules/tracking/src/trackerSamplerAlgorithm.cpp index 75dd9a296a..f75c371d12 100644 --- a/modules/tracking/src/trackerSamplerAlgorithm.cpp +++ b/modules/tracking/src/trackerSamplerAlgorithm.cpp @@ -349,20 +349,10 @@ std::vector TrackerSamplerCS::patchesRegularScan( const Mat& image, Rect tr return sample; } - int numPatchesX; - int numPatchesY; - - numPatchesX = 0; - numPatchesY = 0; for ( int curRow = 0; curRow < ROI.height - patchSize.height + 1; curRow += stepRow ) { - numPatchesY++; - for ( int curCol = 0; curCol < ROI.width - patchSize.width + 1; curCol += stepCol ) { - if( curRow == 0 ) - numPatchesX++; - Mat singleSample = image( Rect( curCol + ROI.x, curRow + ROI.y, patchSize.width, patchSize.height ) ); sample[curPatch] = singleSample; curPatch++; diff --git a/modules/viz/include/opencv2/viz/vizcore.hpp b/modules/viz/include/opencv2/viz/vizcore.hpp index 29cb0c9d65..767077e1b3 100644 --- a/modules/viz/include/opencv2/viz/vizcore.hpp +++ b/modules/viz/include/opencv2/viz/vizcore.hpp @@ -180,7 +180,7 @@ namespace cv */ CV_EXPORTS void writePose(const String& file, const Affine3d& pose, const String& tag = "pose"); - /** takes vector> with T = float/dobule and writes to a sequence of files with given filename format + /** takes vector> with T = float/double and writes to a sequence of files with given filename format * @param traj Trajectory containing a list of poses. It can be * - std::vector, each cv::Mat is of type CV_32F16 or CV_64FC16 * - std::vector, std::vector @@ -192,7 +192,7 @@ namespace cv */ CV_EXPORTS void writeTrajectory(InputArray traj, const String& files_format = "pose%05d.xml", int start = 0, const String& tag = "pose"); - /** takes vector> with T = float/dobule and loads poses from sequence of files + /** takes vector> with T = float/double and loads poses from sequence of files * * @param traj Output array containing a lists of poses. It can be * - std::vector, std::vector diff --git a/modules/wechat_qrcode/perf/perf_main.cpp b/modules/wechat_qrcode/perf/perf_main.cpp new file mode 100644 index 0000000000..aa695484b2 --- /dev/null +++ b/modules/wechat_qrcode/perf/perf_main.cpp @@ -0,0 +1,21 @@ +// 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 "perf_precomp.hpp" + +static +void initQRTests() +{ +#ifdef HAVE_OPENCV_DNN + const char* extraTestDataPath = +#ifdef WINRT + NULL; +#else + getenv("OPENCV_DNN_TEST_DATA_PATH"); +#endif + if (extraTestDataPath) + cvtest::addDataSearchPath(extraTestDataPath); +#endif // HAVE_OPENCV_DNN +} + +CV_PERF_TEST_MAIN(wechat_qrcode, initQRTests()) diff --git a/modules/wechat_qrcode/perf/perf_precomp.hpp b/modules/wechat_qrcode/perf/perf_precomp.hpp new file mode 100644 index 0000000000..8fc05902d9 --- /dev/null +++ b/modules/wechat_qrcode/perf/perf_precomp.hpp @@ -0,0 +1,15 @@ +// 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. + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/wechat_qrcode.hpp" + +namespace opencv_test { +using namespace cv::wechat_qrcode; +} + +#endif diff --git a/modules/wechat_qrcode/perf/perf_wechat_qrcode_pipeline.cpp b/modules/wechat_qrcode/perf/perf_wechat_qrcode_pipeline.cpp new file mode 100644 index 0000000000..fe00e0168b --- /dev/null +++ b/modules/wechat_qrcode/perf/perf_wechat_qrcode_pipeline.cpp @@ -0,0 +1,159 @@ +// 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 "perf_precomp.hpp" +namespace opencv_test +{ +namespace +{ +std::string qrcode_model_path[] = {"", "dnn/wechat_2021-01"}; + +std::string qrcode_images_name[] = { + "version_1_top.jpg", + "version_2_left.jpg", "version_2_up.jpg", "version_2_top.jpg", + "version_3_down.jpg", "version_3_top.jpg", + "version_4_top.jpg", + "version_5_down.jpg", "version_5_left.jpg", "version_5_up.jpg", "version_5_top.jpg", + "russian.jpg", "kanji.jpg", "link_wiki_cv.jpg"}; + +std::string qrcode_images_multiple[] = {"2_qrcodes.png", "3_qrcodes.png", "3_close_qrcodes.png", + "4_qrcodes.png", "5_qrcodes.png", "7_qrcodes.png"}; + +WeChatQRCode createQRDetectorWithDNN(std::string& model_path) +{ + string path_detect_prototxt, path_detect_caffemodel, path_sr_prototxt, path_sr_caffemodel; + if (!model_path.empty()) + { + path_detect_prototxt = findDataFile(model_path + "/detect.prototxt", false); + path_detect_caffemodel = findDataFile(model_path + "/detect.caffemodel", false); + path_sr_prototxt = findDataFile(model_path + "/sr.prototxt", false); + path_sr_caffemodel = findDataFile(model_path + "/sr.caffemodel", false); + } + return WeChatQRCode(path_detect_prototxt, path_detect_caffemodel, path_sr_prototxt, path_sr_caffemodel); +} + +typedef ::perf::TestBaseWithParam< tuple< std::string,std::string > > Perf_Objdetect_QRCode; + +PERF_TEST_P_(Perf_Objdetect_QRCode, detect_and_decode) +{ + std::string model_path = get<0>(GetParam()); + std::string name_current_image = get<1>(GetParam()); + const std::string root = "cv/qrcode/"; + + std::string image_path = findDataFile(root + name_current_image); + Mat src = imread(image_path, IMREAD_GRAYSCALE), straight_barcode; + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + + std::vector< Mat > corners; + std::vector< String > decoded_info; + auto detector = createQRDetectorWithDNN(model_path); + // warmup + if (!model_path.empty()) + { + decoded_info = detector.detectAndDecode(src, corners); + } + TEST_CYCLE() + { + decoded_info = detector.detectAndDecode(src, corners); + ASSERT_FALSE(decoded_info[0].empty()); + } + SANITY_CHECK_NOTHING(); +} + +typedef ::perf::TestBaseWithParam< tuple< std::string,std::string > > Perf_Objdetect_QRCode_Multi; + +PERF_TEST_P_(Perf_Objdetect_QRCode_Multi, detect_and_decode) +{ + std::string model_path = get<0>(GetParam()); + std::string name_current_image = get<1>(GetParam()); + const std::string root = "cv/qrcode/multiple/"; + + std::string image_path = findDataFile(root + name_current_image); + Mat src = imread(image_path, IMREAD_GRAYSCALE), straight_barcode; + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + + std::vector< Mat > corners; + std::vector< String > decoded_info; + auto detector = createQRDetectorWithDNN(model_path); + // warmup + if (!model_path.empty()) + { + decoded_info = detector.detectAndDecode(src, corners); + } + TEST_CYCLE() + { + decoded_info = detector.detectAndDecode(src, corners); + ASSERT_TRUE(decoded_info.size()); + } + for(size_t i = 0; i < decoded_info.size(); i++) + { + ASSERT_FALSE(decoded_info[i].empty()); + } + SANITY_CHECK_NOTHING(); +} + +typedef ::perf::TestBaseWithParam< tuple >Perf_Objdetect_Not_QRCode; + +PERF_TEST_P_(Perf_Objdetect_Not_QRCode, detect_and_decode) +{ + std::string model_path = get<0>(GetParam()); + std::string type_gen = get<1>(GetParam()); + Size resolution = get<2>(GetParam()); + Mat not_qr_code(resolution, CV_8UC1, Scalar(0)); + if (type_gen == "random") + { + RNG rng; + rng.fill(not_qr_code, RNG::UNIFORM, Scalar(0), Scalar(1)); + } + else if (type_gen == "chessboard") + { + uint8_t next_pixel = 255; + for (int j = 0; j < not_qr_code.cols; j++) + { + not_qr_code.ptr(0)[j] = next_pixel; + next_pixel = 255 - next_pixel; + } + for (int r = not_qr_code.cols; r < not_qr_code.rows * not_qr_code.cols; r++) + { + int i = r / not_qr_code.cols; + int j = r % not_qr_code.cols; + not_qr_code.ptr(i)[j] = 255 - not_qr_code.ptr(i-1)[j]; + } + } + std::vector< Mat > corners; + std::vector< String > decoded_info; + auto detector = createQRDetectorWithDNN(model_path); + // warmup + if (!model_path.empty()) + { + decoded_info = detector.detectAndDecode(not_qr_code, corners); + } + TEST_CYCLE() + { + decoded_info = detector.detectAndDecode(not_qr_code, corners); + ASSERT_FALSE(decoded_info.size()); + } + SANITY_CHECK_NOTHING(); +} + + +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_QRCode, + ::testing::Combine( + ::testing::ValuesIn(qrcode_model_path), + ::testing::ValuesIn(qrcode_images_name) + )); +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_QRCode_Multi, + ::testing::Combine( + ::testing::ValuesIn(qrcode_model_path), + ::testing::ValuesIn(qrcode_images_multiple) + )); +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_Not_QRCode, + ::testing::Combine( + ::testing::ValuesIn(qrcode_model_path), + ::testing::Values("zero", "random", "chessboard"), + ::testing::Values(Size(640, 480), Size(1280, 720)) + )); + +} // namespace +} // namespace diff --git a/modules/wechat_qrcode/src/zxing/qrcode/decoder/decoded_bit_stream_parser.cpp b/modules/wechat_qrcode/src/zxing/qrcode/decoder/decoded_bit_stream_parser.cpp index 05de793ced..f02435d568 100644 --- a/modules/wechat_qrcode/src/zxing/qrcode/decoder/decoded_bit_stream_parser.cpp +++ b/modules/wechat_qrcode/src/zxing/qrcode/decoder/decoded_bit_stream_parser.cpp @@ -65,7 +65,8 @@ void DecodedBitStreamParser::append(std::string& result, string const& in, void DecodedBitStreamParser::append(std::string& result, const char* bufIn, size_t nIn, ErrorHandler& err_handler) { - if (err_handler.ErrCode()) return; + // avoid null pointer exception + if (err_handler.ErrCode() || bufIn == nullptr) return; #ifndef NO_ICONV_INSIDE if (nIn == 0) { return; @@ -126,7 +127,10 @@ void DecodedBitStreamParser::decodeHanziSegment(Ref bits_, string& re while (count > 0) { // Each 13 bits encodes a 2-byte character int twoBytes = bits.readBits(13, err_handler); - if (err_handler.ErrCode()) return; + if (err_handler.ErrCode()) { + delete[] buffer; + return; + } int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); if (assembledTwoBytes < 0x003BF) { // In the 0xA1A1 to 0xAAFE range @@ -190,16 +194,20 @@ void DecodedBitStreamParser::decodeByteSegment(Ref bits_, string& res CharacterSetECI* currentCharacterSetECI, ArrayRef >& byteSegments, ErrorHandler& err_handler) { - int nBytes = count; BitSource& bits(*bits_); // Don't crash trying to read more bits than we have available. int available = bits.available(); // try to repair count data if count data is invalid if (count * 8 > available) { - count = (available + 7 / 8); + count = (available + 7) / 8; } + size_t nBytes = count; + + ArrayRef bytes_(nBytes); + // issue https://github.com/opencv/opencv_contrib/issues/3478 + if (bytes_->empty()) + return; - ArrayRef bytes_(count); char* readBytes = &(*bytes_)[0]; for (int i = 0; i < count; i++) { // readBytes[i] = (char) bits.readBits(8); diff --git a/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp b/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp index e22a852f9c..d9f3f99f3e 100644 --- a/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp +++ b/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp @@ -684,7 +684,7 @@ int Detector::fitLine(vector > &oldPoints, float &k, float &b, int num = fitPoints.size(); if (num < 2) return -1; - double x = 0, y = 0, xx = 0, xy = 0, yy = 0, tem = 0; + double x = 0, y = 0, xx = 0, xy = 0, tem = 0; for (int i = 0; i < num; i++) { int point_x = fitPoints[i]->getX(); int point_y = fitPoints[i]->getY(); @@ -692,7 +692,6 @@ int Detector::fitLine(vector > &oldPoints, float &k, float &b, y += point_y; xx += point_x * point_x; xy += point_x * point_y; - yy += point_y * point_y; } tem = xx * num - x * x; diff --git a/modules/wechat_qrcode/test/test_qrcode.cpp b/modules/wechat_qrcode/test/test_qrcode.cpp index d59932b812..ec2559b0e7 100644 --- a/modules/wechat_qrcode/test/test_qrcode.cpp +++ b/modules/wechat_qrcode/test/test_qrcode.cpp @@ -455,5 +455,16 @@ TEST_P(Objdetect_QRCode_Easy_Multi, regression) { std::string qrcode_model_path[] = {"", "dnn/wechat_2021-01"}; INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Easy_Multi, testing::ValuesIn(qrcode_model_path)); +TEST(Objdetect_QRCode_bug, issue_3478) { + auto detector = wechat_qrcode::WeChatQRCode(); + std::string image_path = findDataFile("qrcode/issue_3478.png"); + Mat src = imread(image_path, IMREAD_GRAYSCALE); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + std::vector outs = detector.detectAndDecode(src); + ASSERT_EQ(1, (int) outs.size()); + ASSERT_EQ(16, (int) outs[0].size()); + ASSERT_EQ("KFCVW50 ", outs[0]); +} + } // namespace } // namespace opencv_test diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp index cf0980ddf3..0df14995f3 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d.hpp @@ -299,7 +299,7 @@ hard negative mining, and anchor swap to improve the image matching results. It is able to describe keypoints from any detector just by changing the scale_factor parameter. TEBLID is as efficient as ORB, BEBLID or BRISK, but the triplet-based training objective selected more discriminative features that explain the accuracy gain. It is also more compact than BEBLID, -when running the [AKAZE example](https://github.com/opencv/opencv/blob/4.x/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp) +when running the [AKAZE example](https://github.com/opencv/opencv/blob/5.x/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp) with 10000 keypoints detected by ORB, BEBLID obtains 561 inliers (75%) with 512 bits, whereas TEBLID obtains 621 (75.2%) with 256 bits. ORB obtains only 493 inliers (63%). diff --git a/modules/ximgproc/src/brightedges.cpp b/modules/ximgproc/src/brightedges.cpp index 5daff1c27d..028bf32611 100644 --- a/modules/ximgproc/src/brightedges.cpp +++ b/modules/ximgproc/src/brightedges.cpp @@ -150,7 +150,7 @@ namespace cv iedge.ptr(row + 1)[col + 2] + iedge.ptr(row - 1)[col + 2]; if (line < weight) lines += 1; - if (line == 1) return 0; + if (lines == 1) return 0; // Compute surrounding pixels for dark zone int surround = iedge.ptr(row - 1)[col - 1] + iedge.ptr(row - 1)[col] + diff --git a/modules/ximgproc/src/edge_drawing.cpp b/modules/ximgproc/src/edge_drawing.cpp index 96f77357ec..4ff15324b7 100644 --- a/modules/ximgproc/src/edge_drawing.cpp +++ b/modules/ximgproc/src/edge_drawing.cpp @@ -3163,10 +3163,8 @@ void EdgeDrawingImpl::ValidateCircles(bool validate) int tr = -100; int tc = -100; - int tcount = 0; int noPeripheryPixels = 0; - int noEdgePixels = 0; int aligned = 0; for (int j = 0; j < noPoints; j++) { @@ -3191,7 +3189,6 @@ void EdgeDrawingImpl::ValidateCircles(bool validate) { tr = r; tc = c; - tcount++; } // @@ -3300,9 +3297,6 @@ void EdgeDrawingImpl::ValidateCircles(bool validate) // This produces less false positives, but occationally misses on some valid circles } out: - if (edgeImg[r * width + c] == 255) - noEdgePixels++; - // compute gx & gy int com1 = smoothImg[(r + 1) * width + c + 1] - smoothImg[(r - 1) * width + c - 1]; int com2 = smoothImg[(r - 1) * width + c + 1] - smoothImg[(r + 1) * width + c - 1]; diff --git a/modules/ximgproc/src/fast_hough_transform.cpp b/modules/ximgproc/src/fast_hough_transform.cpp index 391d3fa490..a16945c4ce 100644 --- a/modules/ximgproc/src/fast_hough_transform.cpp +++ b/modules/ximgproc/src/fast_hough_transform.cpp @@ -293,10 +293,6 @@ static void FHT(Mat &dst, else CV_Assert(src.cols == dst.rows && src.rows == dst.cols); - int level = 0; - for (int thres = 1; dst.rows > thres; thres <<= 1) - level++; - Mat tmp; src.convertTo(tmp, dst.type()); if (!isVertical) diff --git a/modules/ximgproc/src/find_ellipses.cpp b/modules/ximgproc/src/find_ellipses.cpp index 6372787148..6b52be0eb3 100644 --- a/modules/ximgproc/src/find_ellipses.cpp +++ b/modules/ximgproc/src/find_ellipses.cpp @@ -723,7 +723,6 @@ void EllipseDetectorImpl::labeling(Mat1b &image, VVP &segments, int minLength) { void EllipseDetectorImpl::detectEdges13(Mat1b &DP, VVP &points_1, VVP &points_3) { // vector of connected edge points VVP contours; - int countEdges = 0; // labeling 8-connected edge points, discarding edge too small labeling(DP, contours, _minEdgeLength); // label point on the same arc int contourSize = int(contours.size()); @@ -737,7 +736,6 @@ void EllipseDetectorImpl::detectEdges13(Mat1b &DP, VVP &points_1, VVP &points_3) float orMin = min(oriented.size.width, oriented.size.height); if (orMin < _minOrientedRectSide) { - countEdges++; continue; } @@ -773,7 +771,6 @@ void EllipseDetectorImpl::detectEdges13(Mat1b &DP, VVP &points_1, VVP &points_3) void EllipseDetectorImpl::detectEdges24(Mat1b &DN, VVP &points_2, VVP &points_4) { // vector of connected edge points VVP contours; - int countEdges = 0; // labeling 8-connected edge points, discarding edge too small labeling(DN, contours, _minEdgeLength); // label point on the same arc int contourSize = int(contours.size()); @@ -787,7 +784,6 @@ void EllipseDetectorImpl::detectEdges24(Mat1b &DN, VVP &points_2, VVP &points_4) float orMin = min(oriented.size.width, oriented.size.height); if (orMin < _minOrientedRectSide) { - countEdges++; continue; } diff --git a/modules/ximgproc/src/slic.cpp b/modules/ximgproc/src/slic.cpp index 7528f0ff21..7f666d7ba3 100644 --- a/modules/ximgproc/src/slic.cpp +++ b/modules/ximgproc/src/slic.cpp @@ -772,7 +772,7 @@ inline void SuperpixelSLICImpl::GetChSeedsK() { int xoff = m_region_size / 2; int yoff = m_region_size / 2; - int n = 0; int r = 0; + int r = 0; for( int y = 0; y < m_height; y++ ) { int Y = y*m_region_size + yoff; @@ -827,8 +827,6 @@ inline void SuperpixelSLICImpl::GetChSeedsK() m_kseedsx.push_back((float)X); m_kseedsy.push_back((float)Y); - - n++; } r++; } diff --git a/modules/ximgproc/src/sparse_match_interpolators.cpp b/modules/ximgproc/src/sparse_match_interpolators.cpp index b12d7767e3..517573946a 100644 --- a/modules/ximgproc/src/sparse_match_interpolators.cpp +++ b/modules/ximgproc/src/sparse_match_interpolators.cpp @@ -1765,7 +1765,6 @@ int RICInterpolatorImpl::PropagateModels(int spCnt, Mat & spNN, vector & su { parallel_for_(Range(0, spCnt), [&](const Range& range) { - int averInlier = 0; int minPtCnt = 30; for (int i = range.start; i < range.end; i++) { @@ -1795,7 +1794,6 @@ int RICInterpolatorImpl::PropagateModels(int spCnt, Mat & spNN, vector & su fitModel.reshape(1, 1).copyTo(outModels.row(i)); } - averInlier += inlierCnt; } } ); @@ -1814,7 +1812,6 @@ float RICInterpolatorImpl::HypothesisEvaluation(const Mat & inModel, const int * float errTh = 5.; // find inliers - int inLierCnt = 0; float cost = 0; for (int k = 0; k < matCnt; k++) { int matId = matNodes[k]; @@ -1838,7 +1835,6 @@ float RICInterpolatorImpl::HypothesisEvaluation(const Mat & inModel, const int * float dis = sqrt((tu - pu)*(tu - pu) + (tv - pv)*(tv - pv)); if (dis < errTh) { outInLier.at(k) = 1; - inLierCnt++; cost += wt * dis; } else { diff --git a/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp b/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp index f1e9d1bebf..dfcbd4438f 100644 --- a/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp +++ b/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp @@ -145,9 +145,9 @@ using namespace cv::ximgproc; public: AdaptiveManifoldFilterRefImpl(); - void filter(InputArray src, OutputArray dst, InputArray joint); + void filter(InputArray src, OutputArray dst, InputArray joint) CV_OVERRIDE; - void collectGarbage(); + void collectGarbage() CV_OVERRIDE; inline double getSigmaS() const CV_OVERRIDE { return sigma_s_; } inline void setSigmaS(double val) CV_OVERRIDE { sigma_s_ = val; } diff --git a/modules/xstereo/src/stereo_binary_bm.cpp b/modules/xstereo/src/stereo_binary_bm.cpp index a4c31d472e..38f58d685a 100644 --- a/modules/xstereo/src/stereo_binary_bm.cpp +++ b/modules/xstereo/src/stereo_binary_bm.cpp @@ -341,15 +341,6 @@ namespace cv } Mat left = preFilteredImg0, right = preFilteredImg1; - - int ndisp = params.numDisparities; - - int wsz = params.kernelSize; - int bufSize0 = (int)((ndisp + 2)*sizeof(int)); - bufSize0 += (int)((height + wsz + 2)*ndisp*sizeof(int)); - bufSize0 += (int)((height + wsz + 2)*sizeof(int)); - bufSize0 += (int)((height + wsz + 2)*ndisp*(wsz + 2)*sizeof(uchar) + 256); - int bufSize1 = (int)((width + params.preFilterSize + 2) * sizeof(int) + 256); if(params.usePrefilter == true) { diff --git a/modules/xstereo/test/test_qds_matching.cpp b/modules/xstereo/test/test_qds_matching.cpp index 9b550a80da..b944930044 100644 --- a/modules/xstereo/test/test_qds_matching.cpp +++ b/modules/xstereo/test/test_qds_matching.cpp @@ -12,14 +12,10 @@ static float disparity_MAE(const Mat &reference, const Mat &estimation) { int elems=0; float error=0; - float ref_invalid=0; for (int row=0; row< reference.rows; row++){ for (int col=0; col(row, col); float estimated_val = estimation.at(row, col); - if (ref_val == 0){ - ref_invalid++; - } // filter out pixels with unknown reference value and pixels whose disparity did not get estimated. if (estimated_val == 0 || ref_val == 0 || std::isnan(estimated_val)){ continue;