mirror of https://github.com/opencv/opencv.git
Merge pull request #23363 from vovka643:4.x_generate_charuco
Added charuco board generation to gen_pattern.py #23363 added charuco board generation in gen_pattern.py moved aruco_dict_utils.cpp to samples from opencv_contrib (https://github.com/opencv/opencv_contrib/pull/3464) ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMakepull/23652/head
parent
f2311d1bfd
commit
9931da772d
29 changed files with 629 additions and 14 deletions
@ -0,0 +1,56 @@ |
||||
#!/usr/bin/env python |
||||
|
||||
from __future__ import print_function |
||||
|
||||
import sys |
||||
sys.dont_write_bytecode = True # Don't generate .pyc files / __pycache__ directories |
||||
|
||||
import os |
||||
import sys |
||||
import unittest |
||||
|
||||
# Python 3 moved urlopen to urllib.requests |
||||
try: |
||||
from urllib.request import urlopen |
||||
except ImportError: |
||||
from urllib import urlopen |
||||
|
||||
basedir = os.path.abspath(os.path.dirname(__file__)) |
||||
|
||||
sys.path.append(os.path.join(os.path.split(basedir)[0], "modules", "python", "test")) |
||||
from tests_common import NewOpenCVTests |
||||
|
||||
def load_tests(loader, tests, pattern): |
||||
cwd = os.getcwd() |
||||
config_file = 'opencv_apps_python_tests.cfg' |
||||
locations = [cwd, basedir] |
||||
if os.path.exists(config_file): |
||||
with open(config_file, 'r') as f: |
||||
locations += [str(s).strip() for s in f.readlines()] |
||||
else: |
||||
print('WARNING: OpenCV tests config file ({}) is missing, running subset of tests'.format(config_file)) |
||||
|
||||
tests_pattern = os.environ.get('OPENCV_APPS_TEST_FILTER', 'test_*') + '.py' |
||||
if tests_pattern != 'test_*.py': |
||||
print('Tests filter: {}'.format(tests_pattern)) |
||||
|
||||
processed = set() |
||||
for l in locations: |
||||
if not os.path.isabs(l): |
||||
l = os.path.normpath(os.path.join(cwd, l)) |
||||
if l in processed: |
||||
continue |
||||
processed.add(l) |
||||
print('Discovering python tests from: {}'.format(l)) |
||||
sys_path_modify = l not in sys.path |
||||
if sys_path_modify: |
||||
sys.path.append(l) # Hack python loader |
||||
discovered_tests = loader.discover(l, pattern=tests_pattern, top_level_dir=l) |
||||
print(' found {} tests'.format(discovered_tests.countTestCases())) |
||||
tests.addTests(loader.discover(l, pattern=tests_pattern)) |
||||
if sys_path_modify: |
||||
sys.path.remove(l) |
||||
return tests |
||||
|
||||
if __name__ == '__main__': |
||||
NewOpenCVTests.bootstrap() |
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,118 @@ |
||||
from __future__ import print_function |
||||
|
||||
import os, tempfile, numpy as np |
||||
|
||||
import sys |
||||
import cv2 as cv |
||||
from tests_common import NewOpenCVTests |
||||
import gen_pattern |
||||
|
||||
class aruco_objdetect_test(NewOpenCVTests): |
||||
|
||||
def test_aruco_dicts(self): |
||||
try: |
||||
from svglib.svglib import svg2rlg |
||||
from reportlab.graphics import renderPM |
||||
except: |
||||
raise self.skipTest("libraies svglib and reportlab not found") |
||||
else: |
||||
cols = 3 |
||||
rows = 5 |
||||
square_size = 100 |
||||
aruco_type = [cv.aruco.DICT_4X4_1000, cv.aruco.DICT_5X5_1000, cv.aruco.DICT_6X6_1000, |
||||
cv.aruco.DICT_7X7_1000, cv.aruco.DICT_ARUCO_ORIGINAL, cv.aruco.DICT_APRILTAG_16h5, |
||||
cv.aruco.DICT_APRILTAG_25h9, cv.aruco.DICT_APRILTAG_36h10, cv.aruco.DICT_APRILTAG_36h11] |
||||
aruco_type_str = ['DICT_4X4_1000','DICT_5X5_1000', 'DICT_6X6_1000', |
||||
'DICT_7X7_1000', 'DICT_ARUCO_ORIGINAL', 'DICT_APRILTAG_16h5', |
||||
'DICT_APRILTAG_25h9', 'DICT_APRILTAG_36h10', 'DICT_APRILTAG_36h11'] |
||||
marker_size = 0.8*square_size |
||||
board_width = cols*square_size |
||||
board_height = rows*square_size |
||||
|
||||
for aruco_type_i in range(len(aruco_type)): |
||||
#draw desk using opencv |
||||
aruco_dict = cv.aruco.getPredefinedDictionary(aruco_type[aruco_type_i]) |
||||
board = cv.aruco.CharucoBoard((cols, rows), square_size, marker_size, aruco_dict) |
||||
charuco_detector = cv.aruco.CharucoDetector(board) |
||||
from_cv_img = board.generateImage((cols*square_size*10, rows*square_size*10)) |
||||
|
||||
#draw desk using svg |
||||
fd1, filesvg = tempfile.mkstemp(prefix="out", suffix=".svg") |
||||
os.close(fd1) |
||||
fd2, filepng = tempfile.mkstemp(prefix="svg_marker", suffix=".png") |
||||
os.close(fd2) |
||||
|
||||
try: |
||||
basedir = os.path.abspath(os.path.dirname(__file__)) |
||||
pm = gen_pattern.PatternMaker(cols, rows, filesvg, "px", square_size, 0, board_width, |
||||
board_height, "charuco_checkboard", marker_size, |
||||
os.path.join(basedir, aruco_type_str[aruco_type_i]+'.json.gz')) |
||||
pm.make_charuco_board() |
||||
pm.save() |
||||
drawing = svg2rlg(filesvg) |
||||
renderPM.drawToFile(drawing, filepng, fmt='PNG', dpi=720) |
||||
from_svg_img = cv.imread(filepng) |
||||
|
||||
#test |
||||
_charucoCorners, _charucoIds, markerCorners_svg, markerIds_svg = charuco_detector.detectBoard(from_svg_img) |
||||
_charucoCorners, _charucoIds, markerCorners_cv, markerIds_cv = charuco_detector.detectBoard(from_cv_img) |
||||
|
||||
np.testing.assert_allclose(markerCorners_svg, markerCorners_cv, 0.1, 0.1) |
||||
np.testing.assert_allclose(markerIds_svg, markerIds_cv, 0.1, 0.1) |
||||
finally: |
||||
if os.path.exists(filesvg): |
||||
os.remove(filesvg) |
||||
if os.path.exists(filepng): |
||||
os.remove(filepng) |
||||
|
||||
def test_aruco_marker_sizes(self): |
||||
try: |
||||
from svglib.svglib import svg2rlg |
||||
from reportlab.graphics import renderPM |
||||
except: |
||||
raise self.skipTest("libraies svglib and reportlab not found") |
||||
else: |
||||
cols = 3 |
||||
rows = 5 |
||||
square_size = 100 |
||||
aruco_type = cv.aruco.DICT_5X5_1000 |
||||
aruco_type_str = 'DICT_5X5_1000' |
||||
marker_sizes_rate = [0.25, 0.5, 0.75, 0.9] |
||||
board_width = cols*square_size |
||||
board_height = rows*square_size |
||||
|
||||
for marker_s_rate in marker_sizes_rate: |
||||
marker_size = marker_s_rate*square_size |
||||
#draw desk using opencv |
||||
aruco_dict = cv.aruco.getPredefinedDictionary(aruco_type) |
||||
board = cv.aruco.CharucoBoard((cols, rows), square_size, marker_size, aruco_dict) |
||||
charuco_detector = cv.aruco.CharucoDetector(board) |
||||
from_cv_img = board.generateImage((cols*square_size*10, rows*square_size*10)) |
||||
|
||||
#draw desk using svg |
||||
fd1, filesvg = tempfile.mkstemp(prefix="out", suffix=".svg") |
||||
os.close(fd1) |
||||
fd2, filepng = tempfile.mkstemp(prefix="svg_marker", suffix=".png") |
||||
os.close(fd2) |
||||
|
||||
try: |
||||
basedir = os.path.abspath(os.path.dirname(__file__)) |
||||
pm = gen_pattern.PatternMaker(cols, rows, filesvg, "px", square_size, 0, board_width, |
||||
board_height, "charuco_checkboard", marker_size, os.path.join(basedir, aruco_type_str+'.json.gz')) |
||||
pm.make_charuco_board() |
||||
pm.save() |
||||
drawing = svg2rlg(filesvg) |
||||
renderPM.drawToFile(drawing, filepng, fmt='PNG', dpi=720) |
||||
from_svg_img = cv.imread(filepng) |
||||
|
||||
#test |
||||
_charucoCorners, _charucoIds, markerCorners_svg, markerIds_svg = charuco_detector.detectBoard(from_svg_img) |
||||
_charucoCorners, _charucoIds, markerCorners_cv, markerIds_cv = charuco_detector.detectBoard(from_cv_img) |
||||
|
||||
np.testing.assert_allclose(markerCorners_svg, markerCorners_cv, 0.1, 0.1) |
||||
np.testing.assert_allclose(markerIds_svg, markerIds_cv, 0.1, 0.1) |
||||
finally: |
||||
if os.path.exists(filesvg): |
||||
os.remove(filesvg) |
||||
if os.path.exists(filepng): |
||||
os.remove(filepng) |
@ -0,0 +1,2 @@ |
||||
svglib>=1.5.1 |
||||
reportlab>=4.0.0 |
@ -0,0 +1,348 @@ |
||||
#include <opencv2/objdetect/aruco_detector.hpp> |
||||
#include <iostream> |
||||
|
||||
using namespace cv; |
||||
using namespace std; |
||||
|
||||
static int _getSelfDistance(const Mat &marker) { |
||||
|
||||
Mat bytes = aruco::Dictionary::getByteListFromBits(marker); |
||||
|
||||
double minHamming = (double)marker.total() + 1; |
||||
for(int r = 1; r < 4; r++) { |
||||
cv::Mat tmp1(1, bytes.cols, CV_8UC1, Scalar::all(0)); |
||||
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0)); |
||||
uchar* rot0 = tmp1.ptr(); |
||||
uchar* rot1 = tmp2.ptr(); |
||||
|
||||
for (int i = 0; i < bytes.cols; ++i) { |
||||
rot0[i] = bytes.ptr()[i]; |
||||
rot1[i] = bytes.ptr()[bytes.cols*r + i]; |
||||
} |
||||
|
||||
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING); |
||||
if (currentHamming < minHamming) minHamming = currentHamming; |
||||
} |
||||
Mat b; |
||||
flip(marker, b, 0); |
||||
Mat flipBytes = aruco::Dictionary::getByteListFromBits(b); |
||||
for(int r = 0; r < 4; r++) { |
||||
cv::Mat tmp1(1, flipBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0)); |
||||
uchar* rot0 = tmp1.ptr(); |
||||
uchar* rot1 = tmp2.ptr(); |
||||
|
||||
for (int i = 0; i < bytes.cols; ++i) { |
||||
rot0[i] = flipBytes.ptr()[i]; |
||||
rot1[i] = bytes.ptr()[bytes.cols*r + i]; |
||||
} |
||||
|
||||
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING); |
||||
if(currentHamming < minHamming) minHamming = currentHamming; |
||||
} |
||||
flip(marker, b, 1); |
||||
flipBytes = aruco::Dictionary::getByteListFromBits(b); |
||||
for(int r = 0; r < 4; r++) { |
||||
cv::Mat tmp1(1, flipBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0)); |
||||
uchar* rot0 = tmp1.ptr(); |
||||
uchar* rot1 = tmp2.ptr(); |
||||
|
||||
for (int i = 0; i < bytes.cols; ++i) { |
||||
rot0[i] = flipBytes.ptr()[i]; |
||||
rot1[i] = bytes.ptr()[bytes.cols*r + i]; |
||||
} |
||||
|
||||
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING); |
||||
if(currentHamming < minHamming) minHamming = currentHamming; |
||||
} |
||||
return cvRound(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()); |
||||
double currentMinDistance = int(bits.total() * bits.total()); |
||||
for(unsigned int r = 0; r < nRotations; r++) { |
||||
|
||||
cv::Mat tmp1(1, candidateBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
cv::Mat tmp2(1, candidateBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
uchar* rot0 = tmp1.ptr(); |
||||
uchar* rot1 = tmp2.ptr(); |
||||
|
||||
for (int i = 0; i < candidateBytes.cols; ++i) { |
||||
rot0[i] = bytesList.ptr(id)[r*candidateBytes.cols + i]; |
||||
rot1[i] = candidateBytes.ptr()[i]; |
||||
} |
||||
|
||||
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING); |
||||
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++) { |
||||
cv::Mat tmp1(1, candidateBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
cv::Mat tmp2(1, candidateBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
uchar* rot0 = tmp1.ptr(); |
||||
uchar* rot1 = tmp2.ptr(); |
||||
|
||||
for (int i = 0; i < candidateBytes.cols; ++i) { |
||||
rot0[i] = bytesList.ptr(id)[r*candidateBytes.cols + i]; |
||||
rot1[i] = candidateBytes.ptr()[i]; |
||||
} |
||||
|
||||
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING); |
||||
if (currentHamming < currentMinDistance) { |
||||
currentMinDistance = currentHamming; |
||||
} |
||||
} |
||||
|
||||
flip(bits.getMat(), b, 1); |
||||
candidateBytes = aruco::Dictionary::getByteListFromBits(b); |
||||
for(unsigned int r = 0; r < nRotations; r++) { |
||||
cv::Mat tmp1(1, candidateBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
cv::Mat tmp2(1, candidateBytes.cols, CV_8UC1, Scalar::all(0)); |
||||
uchar* rot0 = tmp1.ptr(); |
||||
uchar* rot1 = tmp2.ptr(); |
||||
|
||||
for (int i = 0; i < candidateBytes.cols; ++i) { |
||||
rot0[i] = bytesList.ptr(id)[r*candidateBytes.cols + i]; |
||||
rot1[i] = candidateBytes.ptr()[i]; |
||||
} |
||||
|
||||
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING); |
||||
if (currentHamming < currentMinDistance) { |
||||
currentMinDistance = currentHamming; |
||||
} |
||||
} |
||||
return cvRound(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 |<none> | Output file with custom dict }" |
||||
"{r | false | Calculate the metric considering flipped markers }" |
||||
"{d | | Dictionary Name: DICT_4X4_50, DICT_4X4_100, DICT_4X4_250," |
||||
"DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, " |
||||
"DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50," |
||||
"DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL," |
||||
"DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10," |
||||
"DICT_APRILTAG_36h11}" |
||||
"{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<String>(0); |
||||
int nMarkers = parser.get<int>("nMarkers"); |
||||
int markerSize = parser.get<int>("markerSize"); |
||||
bool checkFlippedMarkers = parser.get<bool>("r"); |
||||
|
||||
aruco::Dictionary dictionary = aruco::getPredefinedDictionary(0); |
||||
|
||||
if (parser.has("d")) { |
||||
string arucoDictName = parser.get<string>("d"); |
||||
cv::aruco::PredefinedDictionaryType arucoDict; |
||||
if (arucoDictName == "DICT_4X4_50") { arucoDict = cv::aruco::DICT_4X4_50; } |
||||
else if (arucoDictName == "DICT_4X4_100") { arucoDict = cv::aruco::DICT_4X4_100; } |
||||
else if (arucoDictName == "DICT_4X4_250") { arucoDict = cv::aruco::DICT_4X4_250; } |
||||
else if (arucoDictName == "DICT_4X4_1000") { arucoDict = cv::aruco::DICT_4X4_1000; } |
||||
else if (arucoDictName == "DICT_5X5_50") { arucoDict = cv::aruco::DICT_5X5_50; } |
||||
else if (arucoDictName == "DICT_5X5_100") { arucoDict = cv::aruco::DICT_5X5_100; } |
||||
else if (arucoDictName == "DICT_5X5_250") { arucoDict = cv::aruco::DICT_5X5_250; } |
||||
else if (arucoDictName == "DICT_5X5_1000") { arucoDict = cv::aruco::DICT_5X5_1000; } |
||||
else if (arucoDictName == "DICT_6X6_50") { arucoDict = cv::aruco::DICT_6X6_50; } |
||||
else if (arucoDictName == "DICT_6X6_100") { arucoDict = cv::aruco::DICT_6X6_100; } |
||||
else if (arucoDictName == "DICT_6X6_250") { arucoDict = cv::aruco::DICT_6X6_250; } |
||||
else if (arucoDictName == "DICT_6X6_1000") { arucoDict = cv::aruco::DICT_6X6_1000; } |
||||
else if (arucoDictName == "DICT_7X7_50") { arucoDict = cv::aruco::DICT_7X7_50; } |
||||
else if (arucoDictName == "DICT_7X7_100") { arucoDict = cv::aruco::DICT_7X7_100; } |
||||
else if (arucoDictName == "DICT_7X7_250") { arucoDict = cv::aruco::DICT_7X7_250; } |
||||
else if (arucoDictName == "DICT_7X7_1000") { arucoDict = cv::aruco::DICT_7X7_1000; } |
||||
else if (arucoDictName == "DICT_ARUCO_ORIGINAL") { arucoDict = cv::aruco::DICT_ARUCO_ORIGINAL; } |
||||
else if (arucoDictName == "DICT_APRILTAG_16h5") { arucoDict = cv::aruco::DICT_APRILTAG_16h5; } |
||||
else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; } |
||||
else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; } |
||||
else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; } |
||||
else { |
||||
cout << "incorrect name of aruco dictionary \n"; |
||||
return 1; |
||||
} |
||||
|
||||
dictionary = aruco::getPredefinedDictionary(arucoDict); |
||||
} |
||||
else if (parser.has("cd")) { |
||||
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ); |
||||
bool readOk = 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 << "Hamming distance: " << getMinAsymDistForDict(dictionary) << endl; |
||||
} |
||||
else { |
||||
cout << "Hamming distance: " << getMinDistForDict(dictionary) << endl; |
||||
} |
||||
return 0; |
||||
} |
Loading…
Reference in new issue