mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
Merge branch 4.x
This commit is contained in:
@@ -17,6 +17,7 @@ set(OPENCV_CPP_SAMPLES_REQUIRED_DEPS
|
||||
opencv_calib
|
||||
opencv_stitching
|
||||
opencv_dnn
|
||||
opencv_gapi
|
||||
${OPENCV_MODULES_PUBLIC}
|
||||
${OpenCV_LIB_COMPONENTS})
|
||||
ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS})
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+92
-11
@@ -6,6 +6,7 @@
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <opencv2/objdetect/charuco_detector.hpp>
|
||||
|
||||
#include <cctype>
|
||||
#include <stdio.h>
|
||||
@@ -49,15 +50,25 @@ static void help(char** argv)
|
||||
{
|
||||
printf( "This is a camera calibration sample.\n"
|
||||
"Usage: %s\n"
|
||||
" -w=<board_width> # the number of inner corners per one of board dimension\n"
|
||||
" -h=<board_height> # the number of inner corners per another board dimension\n"
|
||||
" [-pt=<pattern>] # the type of pattern: chessboard or circles' grid\n"
|
||||
" -w=<board_width> # the calibration board horizontal size in inner corners "
|
||||
"for chessboard and in squares or circles for others like ChArUco or circles grid\n"
|
||||
" -h=<board_height> # the calibration board verical size in inner corners "
|
||||
"for chessboard and in squares or circles for others like ChArUco or circles grid\n"
|
||||
" [-pt=<pattern>] # the type of pattern: chessboard, charuco, circles, acircles\n"
|
||||
" [-n=<number_of_frames>] # the number of frames to use for calibration\n"
|
||||
" # (if not specified, it will be set to the number\n"
|
||||
" # of board views actually available)\n"
|
||||
" [-d=<delay>] # a minimum delay in ms between subsequent attempts to capture a next view\n"
|
||||
" # (used only for video capturing)\n"
|
||||
" [-s=<squareSize>] # square size in some user-defined units (1 by default)\n"
|
||||
" [-ms=<markerSize>] # marker size in some user-defined units (0.5 by default)\n"
|
||||
" [-ad=<arucoDict>] # Aruco dictionary name for ChArUco board. "
|
||||
"Available ArUco dictionaries: 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\n"
|
||||
" [-adf=<dictFilename>] # Custom aruco dictionary file for ChArUco board\n"
|
||||
" [-o=<out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n"
|
||||
" [-op] # write detected feature points\n"
|
||||
" [-oe] # write extrinsic parameters\n"
|
||||
@@ -91,7 +102,7 @@ static void help(char** argv)
|
||||
}
|
||||
|
||||
enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
|
||||
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
|
||||
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID, CHARUCOBOARD};
|
||||
|
||||
static double computeReprojectionErrors(
|
||||
const vector<vector<Point3f> >& objectPoints,
|
||||
@@ -140,6 +151,12 @@ static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point
|
||||
float(i*squareSize), 0));
|
||||
break;
|
||||
|
||||
case CHARUCOBOARD:
|
||||
for( int i = 0; i < boardSize.height-1; i++ )
|
||||
for( int j = 0; j < boardSize.width-1; j++ )
|
||||
corners.push_back(Point3f(float(j*squareSize),
|
||||
float(i*squareSize), 0));
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "Unknown pattern type\n");
|
||||
}
|
||||
@@ -162,7 +179,8 @@ static bool runCalibration( vector<vector<Point2f> > imagePoints,
|
||||
|
||||
vector<vector<Point3f> > objectPoints(1);
|
||||
calcChessboardCorners(boardSize, squareSize, objectPoints[0], patternType);
|
||||
objectPoints[0][boardSize.width - 1].x = objectPoints[0][0].x + grid_width;
|
||||
int offset = patternType != CHARUCOBOARD ? boardSize.width - 1: boardSize.width - 2;
|
||||
objectPoints[0][offset].x = objectPoints[0][0].x + grid_width;
|
||||
newObjPoints = objectPoints[0];
|
||||
|
||||
objectPoints.resize(imagePoints.size(),objectPoints[0]);
|
||||
@@ -351,10 +369,12 @@ static bool runAndSave(const string& outputFilename,
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
Size boardSize, imageSize;
|
||||
float squareSize, aspectRatio = 1;
|
||||
float squareSize, markerSize, aspectRatio = 1;
|
||||
Mat cameraMatrix, distCoeffs;
|
||||
string outputFilename;
|
||||
string inputFilename = "";
|
||||
int arucoDict;
|
||||
string dictFilename;
|
||||
|
||||
int i, nframes;
|
||||
bool writeExtrinsics, writePoints;
|
||||
@@ -368,12 +388,12 @@ int main( int argc, char** argv )
|
||||
clock_t prevTimestamp = 0;
|
||||
int mode = DETECTION;
|
||||
int cameraId = 0;
|
||||
vector<vector<Point2f> > imagePoints;
|
||||
vector<vector<Point2f>> imagePoints;
|
||||
vector<string> imageList;
|
||||
Pattern pattern = CHESSBOARD;
|
||||
|
||||
cv::CommandLineParser parser(argc, argv,
|
||||
"{help ||}{w||}{h||}{pt|chessboard|}{n|10|}{d|1000|}{s|1|}{o|out_camera_data.yml|}"
|
||||
"{help ||}{w||}{h||}{pt|chessboard|}{n|10|}{d|1000|}{s|1|}{ms|0.5|}{ad|DICT_4X4_50|}{adf|None|}{o|out_camera_data.yml|}"
|
||||
"{op||}{oe||}{zt||}{a||}{p||}{v||}{V||}{su||}"
|
||||
"{oo||}{ws|11|}{dt||}"
|
||||
"{fx||}{fy||}{cx||}{cy||}"
|
||||
@@ -395,10 +415,43 @@ int main( int argc, char** argv )
|
||||
pattern = ASYMMETRIC_CIRCLES_GRID;
|
||||
else if( val == "chessboard" )
|
||||
pattern = CHESSBOARD;
|
||||
else if( val == "charuco" )
|
||||
pattern = CHARUCOBOARD;
|
||||
else
|
||||
return fprintf( stderr, "Invalid pattern type: must be chessboard or circles\n" ), -1;
|
||||
}
|
||||
|
||||
squareSize = parser.get<float>("s");
|
||||
markerSize = parser.get<float>("ms");
|
||||
|
||||
string arucoDictName = parser.get<string>("ad");
|
||||
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 Aruco dictionary name " << arucoDictName << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dictFilename = parser.get<std::string>("adf");
|
||||
nframes = parser.get<int>("n");
|
||||
delay = parser.get<int>("d");
|
||||
writePoints = parser.has("op");
|
||||
@@ -439,7 +492,8 @@ int main( int argc, char** argv )
|
||||
{
|
||||
flags |= CALIB_FIX_K3;
|
||||
}
|
||||
float grid_width = squareSize * (boardSize.width - 1);
|
||||
|
||||
float grid_width = squareSize *(pattern != CHARUCOBOARD ? (boardSize.width - 1): (boardSize.width - 2) );
|
||||
bool release_object = false;
|
||||
if (parser.has("dt")) {
|
||||
grid_width = parser.get<float>("dt");
|
||||
@@ -464,6 +518,22 @@ int main( int argc, char** argv )
|
||||
if ( boardSize.height <= 0 )
|
||||
return fprintf( stderr, "Invalid board height\n" ), -1;
|
||||
|
||||
cv::aruco::Dictionary dictionary;
|
||||
if (dictFilename == "None") {
|
||||
std::cout << "Using predefined dictionary with id: " << arucoDict << std::endl;
|
||||
dictionary = aruco::getPredefinedDictionary(arucoDict);
|
||||
}
|
||||
else {
|
||||
std::cout << "Using custom dictionary from file: " << dictFilename << std::endl;
|
||||
cv::FileStorage dict_file(dictFilename, cv::FileStorage::Mode::READ);
|
||||
cv::FileNode fn(dict_file.root());
|
||||
dictionary.readDictionary(fn);
|
||||
}
|
||||
|
||||
cv::aruco::CharucoBoard ch_board(boardSize, squareSize, markerSize, dictionary);
|
||||
std::vector<int> markerIds;
|
||||
cv::aruco::CharucoDetector ch_detector(ch_board);
|
||||
|
||||
if( !inputFilename.empty() )
|
||||
{
|
||||
if( !videofile && readStringList(samples::findFile(inputFilename), imageList) )
|
||||
@@ -475,7 +545,7 @@ int main( int argc, char** argv )
|
||||
capture.open(cameraId);
|
||||
|
||||
if( !capture.isOpened() && imageList.empty() )
|
||||
return fprintf( stderr, "Could not initialize video (%d) capture\n",cameraId ), -2;
|
||||
return fprintf( stderr, "Could not initialize video (%d) capture\n", cameraId ), -2;
|
||||
|
||||
if( !imageList.empty() )
|
||||
nframes = (int)imageList.size();
|
||||
@@ -530,6 +600,12 @@ int main( int argc, char** argv )
|
||||
case ASYMMETRIC_CIRCLES_GRID:
|
||||
found = findCirclesGrid( view, boardSize, pointbuf, CALIB_CB_ASYMMETRIC_GRID );
|
||||
break;
|
||||
case CHARUCOBOARD:
|
||||
{
|
||||
ch_detector.detectBoard(view, pointbuf, markerIds);
|
||||
found = pointbuf.size() == (size_t)(boardSize.width-1)*(boardSize.height-1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return fprintf( stderr, "Unknown pattern type\n" ), -1;
|
||||
}
|
||||
@@ -547,7 +623,12 @@ int main( int argc, char** argv )
|
||||
}
|
||||
|
||||
if(found)
|
||||
drawChessboardCorners( view, boardSize, Mat(pointbuf), found );
|
||||
{
|
||||
if(pattern != CHARUCOBOARD)
|
||||
drawChessboardCorners( view, boardSize, Mat(pointbuf), found );
|
||||
else
|
||||
drawChessboardCorners( view, Size(boardSize.width-1, boardSize.height-1), Mat(pointbuf), found );
|
||||
}
|
||||
|
||||
string msg = mode == CAPTURING ? "100/100" :
|
||||
mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
|
||||
|
||||
+17
-21
@@ -218,6 +218,11 @@ int main( int argc, char** argv )
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline static bool isGoodBox(const RotatedRect& box) {
|
||||
//size.height >= size.width awalys,only if the pts are on a line or at the same point,size.width=0
|
||||
return (box.size.height <= box.size.width * 30) && (box.size.width > 0);
|
||||
}
|
||||
|
||||
// Define trackbar callback function. This function finds contours,
|
||||
// draws them, and approximates by ellipses.
|
||||
void processImage(int /*h*/, void*)
|
||||
@@ -276,39 +281,30 @@ void processImage(int /*h*/, void*)
|
||||
{
|
||||
vector<Point2f> pts = points[i];
|
||||
|
||||
if (pts.size()<=5) {
|
||||
//At least 5 points can fit an ellipse
|
||||
if (pts.size()<5) {
|
||||
continue;
|
||||
}
|
||||
if (fitEllipseQ) {
|
||||
box = fitEllipse(pts);
|
||||
if( MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height)*30 ||
|
||||
MAX(box.size.width, box.size.height) <= 0 ||
|
||||
MIN(box.size.width, box.size.height) <= 0){continue;};
|
||||
if (isGoodBox(box)) {
|
||||
paper.drawEllipseWithBox(box, fitEllipseColor, 3);
|
||||
}
|
||||
}
|
||||
if (fitEllipseAMSQ) {
|
||||
boxAMS = fitEllipseAMS(pts);
|
||||
if( MAX(boxAMS.size.width, boxAMS.size.height) > MIN(boxAMS.size.width, boxAMS.size.height)*30 ||
|
||||
MAX(box.size.width, box.size.height) <= 0 ||
|
||||
MIN(box.size.width, box.size.height) <= 0){continue;};
|
||||
if (isGoodBox(boxAMS)) {
|
||||
paper.drawEllipseWithBox(boxAMS, fitEllipseAMSColor, 2);
|
||||
}
|
||||
}
|
||||
if (fitEllipseDirectQ) {
|
||||
boxDirect = fitEllipseDirect(pts);
|
||||
if( MAX(boxDirect.size.width, boxDirect.size.height) > MIN(boxDirect.size.width, boxDirect.size.height)*30 ||
|
||||
MAX(box.size.width, box.size.height) <= 0 ||
|
||||
MIN(box.size.width, box.size.height) <= 0 ){continue;};
|
||||
if (isGoodBox(boxDirect)){
|
||||
paper.drawEllipseWithBox(boxDirect, fitEllipseDirectColor, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fitEllipseQ) {
|
||||
paper.drawEllipseWithBox(box, fitEllipseColor, 3);
|
||||
}
|
||||
if (fitEllipseAMSQ) {
|
||||
paper.drawEllipseWithBox(boxAMS, fitEllipseAMSColor, 2);
|
||||
}
|
||||
if (fitEllipseDirectQ) {
|
||||
paper.drawEllipseWithBox(boxDirect, fitEllipseDirectColor, 1);
|
||||
}
|
||||
|
||||
paper.drawPoints(pts, cv::Scalar(255,255,255));
|
||||
paper.drawPoints(pts, fitEllipseTrueColor);
|
||||
}
|
||||
|
||||
imshow("result", paper.img);
|
||||
|
||||
+104
-17
@@ -26,6 +26,7 @@
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/objdetect/charuco_detector.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -42,21 +43,31 @@ using namespace std;
|
||||
static int print_help(char** argv)
|
||||
{
|
||||
cout <<
|
||||
" Given a list of chessboard images, the number of corners (nx, ny)\n"
|
||||
" on the chessboards, and a flag: useCalibrated for \n"
|
||||
" Given a list of chessboard or ChArUco images, the number of corners (nx, ny)\n"
|
||||
" on the chessboards and the number of squares (nx, ny) on ChArUco,\n"
|
||||
" and a flag: useCalibrated for \n"
|
||||
" calibrated (0) or\n"
|
||||
" uncalibrated \n"
|
||||
" (1: use stereoCalibrate(), 2: compute fundamental\n"
|
||||
" matrix separately) stereo. \n"
|
||||
" Calibrate the cameras and display the\n"
|
||||
" rectified results along with the computed disparity images. \n" << endl;
|
||||
cout << "Usage:\n " << argv[0] << " -w=<board_width default=9> -h=<board_height default=6> -s=<square_size default=1.0> <image list XML/YML file default=stereo_calib.xml>\n" << endl;
|
||||
cout << "Usage:\n " << argv[0] << " -w=<board_width default=9> -h=<board_height default=6>"
|
||||
<<" -t=<pattern type: chessboard or charucoboard default=chessboard> -s=<square_size default=1.0> -ms=<marker size default=0.5>"
|
||||
<<" -ad=<predefined aruco dictionary name default=DICT_4X4_50> -adf=<aruco dictionary file default=None>"
|
||||
<<" <image list XML/YML file default=stereo_calib.xml>\n" << endl;
|
||||
cout << "Available Aruco dictionaries: 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\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, bool displayCorners = false, bool useCalibrated=true, bool showRectified=true)
|
||||
StereoCalib(const vector<string>& imagelist, Size inputBoardSize, string type, float squareSize, float markerSize, cv::aruco::PredefinedDictionaryType arucoDict, string arucoDictFile, bool displayCorners = false, bool useCalibrated=true, bool showRectified=true)
|
||||
{
|
||||
if( imagelist.size() % 2 != 0 )
|
||||
{
|
||||
@@ -77,6 +88,37 @@ StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, b
|
||||
imagePoints[1].resize(nimages);
|
||||
vector<string> goodImageList;
|
||||
|
||||
Size boardSizeInnerCorners, boardSizeUnits;
|
||||
if (type == "chessboard") {
|
||||
//chess board pattern boardSize is given in inner corners
|
||||
boardSizeInnerCorners = inputBoardSize;
|
||||
boardSizeUnits.height = inputBoardSize.height+1;
|
||||
boardSizeUnits.width = inputBoardSize.width+1;
|
||||
}
|
||||
else if (type == "charucoboard") {
|
||||
//ChArUco board pattern boardSize is given in squares units
|
||||
boardSizeUnits = inputBoardSize;
|
||||
boardSizeInnerCorners.width = inputBoardSize.width - 1;
|
||||
boardSizeInnerCorners.height = inputBoardSize.height - 1;
|
||||
}
|
||||
else {
|
||||
std::cout << "unknown pattern type " << type << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
cv::aruco::Dictionary dictionary;
|
||||
if (arucoDictFile == "None") {
|
||||
dictionary = cv::aruco::getPredefinedDictionary(arucoDict);
|
||||
}
|
||||
else {
|
||||
cv::FileStorage dict_file(arucoDictFile, cv::FileStorage::Mode::READ);
|
||||
cv::FileNode fn(dict_file.root());
|
||||
dictionary.readDictionary(fn);
|
||||
}
|
||||
cv::aruco::CharucoBoard ch_board(boardSizeUnits, squareSize, markerSize, dictionary);
|
||||
cv::aruco::CharucoDetector ch_detector(ch_board);
|
||||
std::vector<int> markerIds;
|
||||
|
||||
for( i = j = 0; i < nimages; i++ )
|
||||
{
|
||||
for( k = 0; k < 2; k++ )
|
||||
@@ -101,8 +143,19 @@ StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, b
|
||||
timg = img;
|
||||
else
|
||||
resize(img, timg, Size(), scale, scale, INTER_LINEAR_EXACT);
|
||||
found = findChessboardCorners(timg, boardSize, corners,
|
||||
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
|
||||
|
||||
if (type == "chessboard") {
|
||||
found = findChessboardCorners(timg, boardSizeInnerCorners, corners,
|
||||
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
|
||||
}
|
||||
else if (type == "charucoboard") {
|
||||
ch_detector.detectBoard(timg, corners, markerIds);
|
||||
found = corners.size() == (size_t) (boardSizeInnerCorners.height*boardSizeInnerCorners.width);
|
||||
}
|
||||
else {
|
||||
cout << "Error: unknown pattern " << type << "\n";
|
||||
return;
|
||||
}
|
||||
if( found )
|
||||
{
|
||||
if( scale > 1 )
|
||||
@@ -118,7 +171,7 @@ StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, b
|
||||
cout << filename << endl;
|
||||
Mat cimg, cimg1;
|
||||
cvtColor(img, cimg, COLOR_GRAY2BGR);
|
||||
drawChessboardCorners(cimg, boardSize, corners, found);
|
||||
drawChessboardCorners(cimg, boardSizeInnerCorners, corners, found);
|
||||
double sf = 640./MAX(img.rows, img.cols);
|
||||
resize(cimg, cimg1, Size(), sf, sf, INTER_LINEAR_EXACT);
|
||||
imshow("corners", cimg1);
|
||||
@@ -130,9 +183,11 @@ StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, b
|
||||
putchar('.');
|
||||
if( !found )
|
||||
break;
|
||||
cornerSubPix(img, corners, Size(11,11), Size(-1,-1),
|
||||
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,
|
||||
30, 0.01));
|
||||
if (type == "chessboard") {
|
||||
cornerSubPix(img, corners, Size(11, 11), Size(-1, -1),
|
||||
TermCriteria(TermCriteria::COUNT + TermCriteria::EPS,
|
||||
30, 0.01));
|
||||
}
|
||||
}
|
||||
if( k == 2 )
|
||||
{
|
||||
@@ -155,8 +210,8 @@ StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, b
|
||||
|
||||
for( i = 0; i < nimages; i++ )
|
||||
{
|
||||
for( j = 0; j < boardSize.height; j++ )
|
||||
for( k = 0; k < boardSize.width; k++ )
|
||||
for( j = 0; j < boardSizeInnerCorners.height; j++ )
|
||||
for( k = 0; k < boardSizeInnerCorners.width; k++ )
|
||||
objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0));
|
||||
}
|
||||
|
||||
@@ -344,17 +399,49 @@ static bool readStringList( const string& filename, vector<string>& l )
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Size boardSize;
|
||||
Size inputBoardSize;
|
||||
string imagelistfn;
|
||||
bool showRectified;
|
||||
cv::CommandLineParser parser(argc, argv, "{w|9|}{h|6|}{s|1.0|}{nr||}{help||}{@input|stereo_calib.xml|}");
|
||||
cv::CommandLineParser parser(argc, argv, "{w|9|}{h|6|}{t|chessboard|}{s|1.0|}{ms|0.5|}{ad|DICT_4X4_50|}{adf|None|}{nr||}{help||}{@input|stereo_calib.xml|}");
|
||||
if (parser.has("help"))
|
||||
return print_help(argv);
|
||||
showRectified = !parser.has("nr");
|
||||
imagelistfn = samples::findFile(parser.get<string>("@input"));
|
||||
boardSize.width = parser.get<int>("w");
|
||||
boardSize.height = parser.get<int>("h");
|
||||
inputBoardSize.width = parser.get<int>("w");
|
||||
inputBoardSize.height = parser.get<int>("h");
|
||||
string type = parser.get<string>("t");
|
||||
float squareSize = parser.get<float>("s");
|
||||
float markerSize = parser.get<float>("ms");
|
||||
string arucoDictName = parser.get<string>("ad");
|
||||
string arucoDictFile = parser.get<string>("adf");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!parser.check())
|
||||
{
|
||||
parser.printErrors();
|
||||
@@ -368,6 +455,6 @@ int main(int argc, char** argv)
|
||||
return print_help(argv);
|
||||
}
|
||||
|
||||
StereoCalib(imagelist, boardSize, squareSize, false, true, showRectified);
|
||||
StereoCalib(imagelist, inputBoardSize, type, squareSize, markerSize, arucoDict, arucoDictFile, false, true, showRectified);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ struct Data
|
||||
bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift);
|
||||
|
||||
//function finds two points for drawing line (wx = 0)
|
||||
bool findPointsForLine(const Mat &weights, float shift, Point points[], int width, int height);
|
||||
bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height);
|
||||
|
||||
// function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) )
|
||||
bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint);
|
||||
|
||||
@@ -26,26 +26,28 @@ int max_Trackbar = 5;
|
||||
/// Function Headers
|
||||
void MatchingMethod( int, void* );
|
||||
|
||||
const char* keys =
|
||||
"{ help h| | Print help message. }"
|
||||
"{ @input1 | Template_Matching_Original_Image.jpg | image_name }"
|
||||
"{ @input2 | Template_Matching_Template_Image.jpg | template_name }"
|
||||
"{ @input3 | | mask_name }";
|
||||
|
||||
/**
|
||||
* @function main
|
||||
*/
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
cout << "Not enough parameters" << endl;
|
||||
cout << "Usage:\n" << argv[0] << " <image_name> <template_name> [<mask_name>]" << endl;
|
||||
return -1;
|
||||
}
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
samples::addSamplesDataSearchSubDirectory( "doc/tutorials/imgproc/histograms/template_matching/images" );
|
||||
|
||||
//! [load_image]
|
||||
/// Load image and template
|
||||
img = imread( argv[1], IMREAD_COLOR );
|
||||
templ = imread( argv[2], IMREAD_COLOR );
|
||||
img = imread( samples::findFile( parser.get<String>("@input1") ) );
|
||||
templ = imread( samples::findFile( parser.get<String>("@input2") ), IMREAD_COLOR );
|
||||
|
||||
if(argc > 3) {
|
||||
use_mask = true;
|
||||
mask = imread( argv[3], IMREAD_COLOR );
|
||||
mask = imread(samples::findFile( parser.get<String>("@input3") ), IMREAD_COLOR );
|
||||
}
|
||||
|
||||
if(img.empty() || templ.empty() || (use_mask && mask.empty()))
|
||||
|
||||
@@ -26,8 +26,9 @@ void Hist_and_Backproj(int, void* );
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
//! [Read the image]
|
||||
CommandLineParser parser( argc, argv, "{@input | | input image}" );
|
||||
Mat src = imread( parser.get<String>( "@input" ) );
|
||||
CommandLineParser parser( argc, argv, "{@input |Back_Projection_Theory0.jpg| input image}" );
|
||||
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/histograms/back_projection/images");
|
||||
Mat src = imread(samples::findFile(parser.get<String>( "@input" )) );
|
||||
if( src.empty() )
|
||||
{
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
|
||||
@@ -14,9 +14,9 @@ using namespace cv;
|
||||
|
||||
const char* keys =
|
||||
"{ help h| | Print help message. }"
|
||||
"{ @input1 | | Path to input image 1. }"
|
||||
"{ @input2 | | Path to input image 2. }"
|
||||
"{ @input3 | | Path to input image 3. }";
|
||||
"{ @input1 |Histogram_Comparison_Source_0.jpg | Path to input image 1. }"
|
||||
"{ @input2 |Histogram_Comparison_Source_1.jpg | Path to input image 2. }"
|
||||
"{ @input3 |Histogram_Comparison_Source_2.jpg | Path to input image 3. }";
|
||||
|
||||
/**
|
||||
* @function main
|
||||
@@ -25,9 +25,10 @@ int main( int argc, char** argv )
|
||||
{
|
||||
//! [Load three images with different environment settings]
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
Mat src_base = imread( parser.get<String>("input1") );
|
||||
Mat src_test1 = imread( parser.get<String>("input2") );
|
||||
Mat src_test2 = imread( parser.get<String>("input3") );
|
||||
samples::addSamplesDataSearchSubDirectory( "doc/tutorials/imgproc/histograms/histogram_comparison/images" );
|
||||
Mat src_base = imread(samples::findFile( parser.get<String>( "@input1" ) ) );
|
||||
Mat src_test1 = imread(samples::findFile( parser.get<String>( "@input2" ) ) );
|
||||
Mat src_test2 = imread(samples::findFile( parser.get<String>( "@input3" ) ) );
|
||||
if( src_base.empty() || src_test1.empty() || src_test2.empty() )
|
||||
{
|
||||
cout << "Could not open or find the images!\n" << endl;
|
||||
|
||||
+12
-5
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
/**
|
||||
* @brief You will learn how to segment an anisotropic image with a single local orientation by a gradient structure tensor (GST)
|
||||
* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
|
||||
@@ -21,7 +22,8 @@ int main()
|
||||
int LowThr = 35; // threshold1 for orientation, it ranges from 0 to 180
|
||||
int HighThr = 57; // threshold2 for orientation, it ranges from 0 to 180
|
||||
|
||||
Mat imgIn = imread("input.jpg", IMREAD_GRAYSCALE);
|
||||
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/anisotropic_image_segmentation/images");
|
||||
Mat imgIn = imread(samples::findFile("gst_input.jpg"), IMREAD_GRAYSCALE);
|
||||
if (imgIn.empty()) //check whether the image is loaded or not
|
||||
{
|
||||
cout << "ERROR : Image cannot be loaded..!!" << endl;
|
||||
@@ -46,13 +48,18 @@ int main()
|
||||
//! [combining]
|
||||
//! [main]
|
||||
|
||||
normalize(imgCoherency, imgCoherency, 0, 255, NORM_MINMAX);
|
||||
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX);
|
||||
normalize(imgCoherency, imgCoherency, 0, 255, NORM_MINMAX, CV_8U);
|
||||
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX, CV_8U);
|
||||
|
||||
imshow("Original", imgIn);
|
||||
imshow("Result", 0.5 * (imgIn + imgBin));
|
||||
imshow("Coherency", imgCoherency);
|
||||
imshow("Orientation", imgOrientation);
|
||||
imwrite("result.jpg", 0.5*(imgIn + imgBin));
|
||||
imwrite("Coherency.jpg", imgCoherency);
|
||||
imwrite("Orientation.jpg", imgOrientation);
|
||||
//! [main_extra]
|
||||
waitKey(0);
|
||||
//! [main_extra]
|
||||
return 0;
|
||||
}
|
||||
//! [calcGST]
|
||||
|
||||
+10
-5
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
/**
|
||||
* @brief You will learn how to recover an out-of-focus image by Wiener filter
|
||||
* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin
|
||||
*/
|
||||
#include <iostream>
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
|
||||
@@ -17,9 +18,9 @@ void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr);
|
||||
|
||||
const String keys =
|
||||
"{help h usage ? | | print this message }"
|
||||
"{image |original.JPG | input image name }"
|
||||
"{R |53 | radius }"
|
||||
"{SNR |5200 | signal to noise ratio}"
|
||||
"{image |original.jpg | input image name }"
|
||||
"{R |5 | radius }"
|
||||
"{SNR |100 | signal to noise ratio}"
|
||||
;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -35,6 +36,7 @@ int main(int argc, char *argv[])
|
||||
int R = parser.get<int>("R");
|
||||
int snr = parser.get<int>("SNR");
|
||||
string strInFileName = parser.get<String>("image");
|
||||
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/out_of_focus_deblur_filter/images");
|
||||
|
||||
if (!parser.check())
|
||||
{
|
||||
@@ -43,7 +45,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
Mat imgIn;
|
||||
imgIn = imread(strInFileName, IMREAD_GRAYSCALE);
|
||||
imgIn = imread(samples::findFile( strInFileName ), IMREAD_GRAYSCALE);
|
||||
if (imgIn.empty()) //check whether the image is loaded or not
|
||||
{
|
||||
cout << "ERROR : Image cannot be loaded..!!" << endl;
|
||||
@@ -69,7 +71,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
imgOut.convertTo(imgOut, CV_8U);
|
||||
normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);
|
||||
imshow("Original", imgIn);
|
||||
imshow("Debluring", imgOut);
|
||||
imwrite("result.jpg", imgOut);
|
||||
waitKey(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+16
-3
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
/**
|
||||
* @brief You will learn how to remove periodic noise in the Fourier domain
|
||||
* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin
|
||||
*/
|
||||
#include <iostream>
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
|
||||
@@ -14,15 +15,25 @@ void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H);
|
||||
void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius);
|
||||
void calcPSD(const Mat& inputImg, Mat& outputImg, int flag = 0);
|
||||
|
||||
int main()
|
||||
const String keys =
|
||||
"{help h usage ? | | print this message }"
|
||||
"{@image |period_input.jpg | input image name }"
|
||||
;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Mat imgIn = imread("input.jpg", IMREAD_GRAYSCALE);
|
||||
CommandLineParser parser(argc, argv, keys);
|
||||
string strInFileName = parser.get<String>("@image");
|
||||
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/periodic_noise_removing_filter/images");
|
||||
|
||||
Mat imgIn = imread(samples::findFile(strInFileName), IMREAD_GRAYSCALE);
|
||||
if (imgIn.empty()) //check whether the image is loaded or not
|
||||
{
|
||||
cout << "ERROR : Image cannot be loaded..!!" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
imshow("Image corrupted", imgIn);
|
||||
imgIn.convertTo(imgIn, CV_32F);
|
||||
|
||||
//! [main]
|
||||
@@ -57,7 +68,9 @@ int main()
|
||||
imwrite("PSD.jpg", imgPSD);
|
||||
fftshift(H, H);
|
||||
normalize(H, H, 0, 255, NORM_MINMAX);
|
||||
imshow("Debluring", imgOut);
|
||||
imwrite("filter.jpg", H);
|
||||
waitKey(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ using namespace std;
|
||||
int main() {
|
||||
//! [generalized-hough-transform-load-and-setup]
|
||||
// load source image and grayscale template
|
||||
Mat image = imread("images/generalized_hough_mini_image.jpg");
|
||||
Mat templ = imread("images/generalized_hough_mini_template.jpg", IMREAD_GRAYSCALE);
|
||||
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/generalized_hough_ballard_guil");
|
||||
Mat image = imread(samples::findFile("images/generalized_hough_mini_image.jpg"));
|
||||
Mat templ = imread(samples::findFile("images/generalized_hough_mini_template.jpg"), IMREAD_GRAYSCALE);
|
||||
|
||||
// create grayscale image
|
||||
Mat grayImage;
|
||||
@@ -105,4 +106,4 @@ int main() {
|
||||
//! [generalized-hough-transform-draw-results]
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/videoio.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include "opencv2/objdetect/charuco_detector.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
@@ -20,7 +21,7 @@ class Settings
|
||||
{
|
||||
public:
|
||||
Settings() : goodInput(false) {}
|
||||
enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
|
||||
enum Pattern { NOT_EXISTING, CHESSBOARD, CHARUCOBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
|
||||
enum InputType { INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST };
|
||||
|
||||
void write(FileStorage& fs) const //Write serialization for this class
|
||||
@@ -29,7 +30,10 @@ public:
|
||||
<< "BoardSize_Width" << boardSize.width
|
||||
<< "BoardSize_Height" << boardSize.height
|
||||
<< "Square_Size" << squareSize
|
||||
<< "Marker_Size" << markerSize
|
||||
<< "Calibrate_Pattern" << patternToUse
|
||||
<< "ArUco_Dict_Name" << arucoDictName
|
||||
<< "ArUco_Dict_File_Name" << arucoDictFileName
|
||||
<< "Calibrate_NrOfFrameToUse" << nrFrames
|
||||
<< "Calibrate_FixAspectRatio" << aspectRatio
|
||||
<< "Calibrate_AssumeZeroTangentialDistortion" << calibZeroTangentDist
|
||||
@@ -49,10 +53,13 @@ public:
|
||||
}
|
||||
void read(const FileNode& node) //Read serialization for this class
|
||||
{
|
||||
node["BoardSize_Width" ] >> boardSize.width;
|
||||
node["BoardSize_Width"] >> boardSize.width;
|
||||
node["BoardSize_Height"] >> boardSize.height;
|
||||
node["Calibrate_Pattern"] >> patternToUse;
|
||||
node["Square_Size"] >> squareSize;
|
||||
node["ArUco_Dict_Name"] >> arucoDictName;
|
||||
node["ArUco_Dict_File_Name"] >> arucoDictFileName;
|
||||
node["Square_Size"] >> squareSize;
|
||||
node["Marker_Size"] >> markerSize;
|
||||
node["Calibrate_NrOfFrameToUse"] >> nrFrames;
|
||||
node["Calibrate_FixAspectRatio"] >> aspectRatio;
|
||||
node["Write_DetectedFeaturePoints"] >> writePoints;
|
||||
@@ -148,6 +155,7 @@ public:
|
||||
|
||||
calibrationPattern = NOT_EXISTING;
|
||||
if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD;
|
||||
if (!patternToUse.compare("CHARUCOBOARD")) calibrationPattern = CHARUCOBOARD;
|
||||
if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID;
|
||||
if (!patternToUse.compare("ASYMMETRIC_CIRCLES_GRID")) calibrationPattern = ASYMMETRIC_CIRCLES_GRID;
|
||||
if (calibrationPattern == NOT_EXISTING)
|
||||
@@ -199,8 +207,11 @@ public:
|
||||
}
|
||||
public:
|
||||
Size boardSize; // The size of the board -> Number of items by width and height
|
||||
Pattern calibrationPattern; // One of the Chessboard, circles, or asymmetric circle pattern
|
||||
Pattern calibrationPattern; // One of the Chessboard, ChArUco board, circles, or asymmetric circle pattern
|
||||
float squareSize; // The size of a square in your defined unit (point, millimeter,etc).
|
||||
float markerSize; // The size of a marker in your defined unit (point, millimeter,etc).
|
||||
string arucoDictName; // The Name of ArUco dictionary which you use in ChArUco pattern
|
||||
string arucoDictFileName; // The Name of file which contains ArUco dictionary for ChArUco pattern
|
||||
int nrFrames; // The number of frames to use from the input for calibration
|
||||
float aspectRatio; // The aspect ratio
|
||||
int delay; // In case of a video input
|
||||
@@ -284,9 +295,6 @@ int main(int argc, char* argv[])
|
||||
fs.release(); // close Settings file
|
||||
//! [file_read]
|
||||
|
||||
//FileStorage fout("settings.yml", FileStorage::WRITE); // write config as YAML
|
||||
//fout << "Settings" << s;
|
||||
|
||||
if (!s.goodInput)
|
||||
{
|
||||
cout << "Invalid input detected. Application stopping. " << endl;
|
||||
@@ -296,12 +304,63 @@ int main(int argc, char* argv[])
|
||||
int winSize = parser.get<int>("winSize");
|
||||
|
||||
float grid_width = s.squareSize * (s.boardSize.width - 1);
|
||||
if (s.calibrationPattern == Settings::Pattern::CHARUCOBOARD) {
|
||||
grid_width = s.squareSize * (s.boardSize.width - 2);
|
||||
}
|
||||
|
||||
bool release_object = false;
|
||||
if (parser.has("d")) {
|
||||
grid_width = parser.get<float>("d");
|
||||
release_object = true;
|
||||
}
|
||||
|
||||
//create CharucoBoard
|
||||
cv::aruco::Dictionary dictionary;
|
||||
if (s.calibrationPattern == Settings::CHARUCOBOARD) {
|
||||
if (s.arucoDictFileName == "") {
|
||||
cv::aruco::PredefinedDictionaryType arucoDict;
|
||||
if (s.arucoDictName == "DICT_4X4_50") { arucoDict = cv::aruco::DICT_4X4_50; }
|
||||
else if (s.arucoDictName == "DICT_4X4_100") { arucoDict = cv::aruco::DICT_4X4_100; }
|
||||
else if (s.arucoDictName == "DICT_4X4_250") { arucoDict = cv::aruco::DICT_4X4_250; }
|
||||
else if (s.arucoDictName == "DICT_4X4_1000") { arucoDict = cv::aruco::DICT_4X4_1000; }
|
||||
else if (s.arucoDictName == "DICT_5X5_50") { arucoDict = cv::aruco::DICT_5X5_50; }
|
||||
else if (s.arucoDictName == "DICT_5X5_100") { arucoDict = cv::aruco::DICT_5X5_100; }
|
||||
else if (s.arucoDictName == "DICT_5X5_250") { arucoDict = cv::aruco::DICT_5X5_250; }
|
||||
else if (s.arucoDictName == "DICT_5X5_1000") { arucoDict = cv::aruco::DICT_5X5_1000; }
|
||||
else if (s.arucoDictName == "DICT_6X6_50") { arucoDict = cv::aruco::DICT_6X6_50; }
|
||||
else if (s.arucoDictName == "DICT_6X6_100") { arucoDict = cv::aruco::DICT_6X6_100; }
|
||||
else if (s.arucoDictName == "DICT_6X6_250") { arucoDict = cv::aruco::DICT_6X6_250; }
|
||||
else if (s.arucoDictName == "DICT_6X6_1000") { arucoDict = cv::aruco::DICT_6X6_1000; }
|
||||
else if (s.arucoDictName == "DICT_7X7_50") { arucoDict = cv::aruco::DICT_7X7_50; }
|
||||
else if (s.arucoDictName == "DICT_7X7_100") { arucoDict = cv::aruco::DICT_7X7_100; }
|
||||
else if (s.arucoDictName == "DICT_7X7_250") { arucoDict = cv::aruco::DICT_7X7_250; }
|
||||
else if (s.arucoDictName == "DICT_7X7_1000") { arucoDict = cv::aruco::DICT_7X7_1000; }
|
||||
else if (s.arucoDictName == "DICT_ARUCO_ORIGINAL") { arucoDict = cv::aruco::DICT_ARUCO_ORIGINAL; }
|
||||
else if (s.arucoDictName == "DICT_APRILTAG_16h5") { arucoDict = cv::aruco::DICT_APRILTAG_16h5; }
|
||||
else if (s.arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; }
|
||||
else if (s.arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; }
|
||||
else if (s.arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; }
|
||||
else {
|
||||
cout << "incorrect name of aruco dictionary \n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
dictionary = cv::aruco::getPredefinedDictionary(arucoDict);
|
||||
}
|
||||
else {
|
||||
cv::FileStorage dict_file(s.arucoDictFileName, cv::FileStorage::Mode::READ);
|
||||
cv::FileNode fn(dict_file.root());
|
||||
dictionary.readDictionary(fn);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// default dictionary
|
||||
dictionary = cv::aruco::getPredefinedDictionary(0);
|
||||
}
|
||||
cv::aruco::CharucoBoard ch_board({s.boardSize.width, s.boardSize.height}, s.squareSize, s.markerSize, dictionary);
|
||||
cv::aruco::CharucoDetector ch_detector(ch_board);
|
||||
std::vector<int> markerIds;
|
||||
|
||||
vector<vector<Point2f> > imagePoints;
|
||||
Mat cameraMatrix, distCoeffs;
|
||||
Size imageSize;
|
||||
@@ -309,8 +368,8 @@ int main(int argc, char* argv[])
|
||||
clock_t prevTimestamp = 0;
|
||||
const Scalar RED(0,0,255), GREEN(0,255,0);
|
||||
const char ESC_KEY = 27;
|
||||
|
||||
//! [get_input]
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Mat view;
|
||||
@@ -357,6 +416,10 @@ int main(int argc, char* argv[])
|
||||
case Settings::CHESSBOARD:
|
||||
found = findChessboardCorners( view, s.boardSize, pointBuf, chessBoardFlags);
|
||||
break;
|
||||
case Settings::CHARUCOBOARD:
|
||||
ch_detector.detectBoard( view, pointBuf, markerIds);
|
||||
found = pointBuf.size() == (size_t)((s.boardSize.height - 1)*(s.boardSize.width - 1));
|
||||
break;
|
||||
case Settings::CIRCLES_GRID:
|
||||
found = findCirclesGrid( view, s.boardSize, pointBuf );
|
||||
break;
|
||||
@@ -368,8 +431,9 @@ int main(int argc, char* argv[])
|
||||
break;
|
||||
}
|
||||
//! [find_pattern]
|
||||
|
||||
//! [pattern_found]
|
||||
if ( found) // If done with success,
|
||||
if (found) // If done with success,
|
||||
{
|
||||
// improve the found corners' coordinate accuracy for chessboard
|
||||
if( s.calibrationPattern == Settings::CHESSBOARD)
|
||||
@@ -389,7 +453,10 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
// Draw the corners.
|
||||
drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
|
||||
if(s.calibrationPattern == Settings::CHARUCOBOARD)
|
||||
drawChessboardCorners( view, cv::Size(s.boardSize.width-1, s.boardSize.height-1), Mat(pointBuf), found );
|
||||
else
|
||||
drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
|
||||
}
|
||||
//! [pattern_found]
|
||||
//----------------------------- Output Text ------------------------------------------------
|
||||
@@ -531,15 +598,25 @@ static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Po
|
||||
{
|
||||
case Settings::CHESSBOARD:
|
||||
case Settings::CIRCLES_GRID:
|
||||
for( int i = 0; i < boardSize.height; ++i )
|
||||
for( int j = 0; j < boardSize.width; ++j )
|
||||
for (int i = 0; i < boardSize.height; ++i) {
|
||||
for (int j = 0; j < boardSize.width; ++j) {
|
||||
corners.push_back(Point3f(j*squareSize, i*squareSize, 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Settings::CHARUCOBOARD:
|
||||
for (int i = 0; i < boardSize.height - 1; ++i) {
|
||||
for (int j = 0; j < boardSize.width - 1; ++j) {
|
||||
corners.push_back(Point3f(j*squareSize, i*squareSize, 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Settings::ASYMMETRIC_CIRCLES_GRID:
|
||||
for( int i = 0; i < boardSize.height; i++ )
|
||||
for( int j = 0; j < boardSize.width; j++ )
|
||||
corners.push_back(Point3f((2*j + i % 2)*squareSize, i*squareSize, 0));
|
||||
for (int i = 0; i < boardSize.height; i++) {
|
||||
for (int j = 0; j < boardSize.width; j++) {
|
||||
corners.push_back(Point3f((2 * j + i % 2)*squareSize, i*squareSize, 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -564,7 +641,12 @@ static bool runCalibration( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat
|
||||
|
||||
vector<vector<Point3f> > objectPoints(1);
|
||||
calcBoardCornerPositions(s.boardSize, s.squareSize, objectPoints[0], s.calibrationPattern);
|
||||
objectPoints[0][s.boardSize.width - 1].x = objectPoints[0][0].x + grid_width;
|
||||
if (s.calibrationPattern == Settings::Pattern::CHARUCOBOARD) {
|
||||
objectPoints[0][s.boardSize.width - 2].x = objectPoints[0][0].x + grid_width;
|
||||
}
|
||||
else {
|
||||
objectPoints[0][s.boardSize.width - 1].x = objectPoints[0][0].x + grid_width;
|
||||
}
|
||||
newObjPoints = objectPoints[0];
|
||||
|
||||
objectPoints.resize(imagePoints.size(),objectPoints[0]);
|
||||
@@ -635,6 +717,7 @@ static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, M
|
||||
fs << "board_width" << s.boardSize.width;
|
||||
fs << "board_height" << s.boardSize.height;
|
||||
fs << "square_size" << s.squareSize;
|
||||
fs << "marker_size" << s.markerSize;
|
||||
|
||||
if( !s.useFisheye && s.flag & CALIB_FIX_ASPECT_RATIO )
|
||||
fs << "fix_aspect_ratio" << s.aspectRatio;
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
<opencv_storage>
|
||||
<Settings>
|
||||
<!-- Number of inner corners per a item row and column. (square, circle) -->
|
||||
<BoardSize_Width> 9</BoardSize_Width>
|
||||
<BoardSize_Width>9</BoardSize_Width>
|
||||
<BoardSize_Height>6</BoardSize_Height>
|
||||
|
||||
<!-- The size of a square in some user defined metric system (pixel, millimeter)-->
|
||||
<Square_Size>50</Square_Size>
|
||||
|
||||
<!-- The type of input used for camera calibration. One of: CHESSBOARD CIRCLES_GRID ASYMMETRIC_CIRCLES_GRID -->
|
||||
<Marker_Size>25</Marker_Size>
|
||||
<!-- The type of input used for camera calibration. One of: CHESSBOARD CHARUCOBOARD CIRCLES_GRID ASYMMETRIC_CIRCLES_GRID -->
|
||||
<Calibrate_Pattern>"CHESSBOARD"</Calibrate_Pattern>
|
||||
|
||||
<ArUco_Dict_Name>DICT_4X4_50</ArUco_Dict_Name>
|
||||
<ArUco_Dict_File_Name></ArUco_Dict_File_Name>
|
||||
<!-- The input to use for calibration.
|
||||
To use an input camera -> give the ID of the camera, like "1"
|
||||
To use an input video -> give the path of the input video, like "/tmp/x.avi"
|
||||
|
||||
@@ -92,7 +92,7 @@ void Sharpen(const Mat& myImage,Mat& Result)
|
||||
|
||||
for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
|
||||
{
|
||||
*output++ = saturate_cast<uchar>(5*current[i]
|
||||
output[i] = saturate_cast<uchar>(5*current[i]
|
||||
-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ find_package(OpenCV REQUIRED COMPONENTS opencv_core)
|
||||
if(NOT OPENCV_EXAMPLES_SKIP_PARALLEL_BACKEND_OPENMP
|
||||
AND NOT OPENCV_EXAMPLES_SKIP_OPENMP
|
||||
)
|
||||
project(opencv_example_openmp_backend)
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_FOUND)
|
||||
project(opencv_example_openmp_backend)
|
||||
add_executable(opencv_example_openmp_backend example-openmp.cpp)
|
||||
target_link_libraries(opencv_example_openmp_backend PRIVATE
|
||||
opencv_core
|
||||
@@ -20,13 +20,13 @@ if(NOT OPENCV_EXAMPLES_SKIP_PARALLEL_BACKEND_TBB
|
||||
AND NOT OPENCV_EXAMPLES_SKIP_TBB
|
||||
AND NOT OPENCV_EXAMPLE_SKIP_TBB # deprecated (to be removed in OpenCV 5.0)
|
||||
)
|
||||
project(opencv_example_tbb_backend)
|
||||
find_package(TBB QUIET)
|
||||
if(NOT TBB_FOUND)
|
||||
find_path(TBB_INCLUDE_DIR NAMES "tbb/tbb.h")
|
||||
find_library(TBB_LIBRARY NAMES "tbb")
|
||||
endif()
|
||||
if(TBB_INCLUDE_DIR AND TBB_LIBRARY)
|
||||
project(opencv_example_tbb_backend)
|
||||
add_executable(opencv_example_tbb_backend example-tbb.cpp)
|
||||
target_include_directories(opencv_example_tbb_backend SYSTEM PRIVATE ${TBB_INCLUDE_DIR})
|
||||
target_link_libraries(opencv_example_tbb_backend PRIVATE
|
||||
|
||||
@@ -38,6 +38,8 @@ int main()
|
||||
waitKey(0);
|
||||
//! [Algorithm]
|
||||
|
||||
const char * vertex_names[4] {"0", "1", "2", "3"};
|
||||
|
||||
//! [RotatedRect_demo]
|
||||
Mat test_image(200, 200, CV_8UC3, Scalar(0));
|
||||
RotatedRect rRect = RotatedRect(Point2f(100,100), Size2f(100,50), 30);
|
||||
@@ -45,7 +47,10 @@ int main()
|
||||
Point2f vertices[4];
|
||||
rRect.points(vertices);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
line(test_image, vertices[i], vertices[(i+1)%4], Scalar(0,255,0), 2);
|
||||
putText(test_image, vertex_names[i], vertices[i], FONT_HERSHEY_SIMPLEX, 1, Scalar(255,255,255));
|
||||
}
|
||||
|
||||
Rect brect = rRect.boundingRect();
|
||||
rectangle(test_image, brect, Scalar(255,0,0), 2);
|
||||
|
||||
@@ -157,7 +157,7 @@ static void onMouse(int event, int x, int y, int, void*)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if ((event == EVENT_LBUTTONDOWN) & ((abs(roi_corners[i].x - x) < 10)) & (abs(roi_corners[i].y - y) < 10))
|
||||
if ((event == EVENT_LBUTTONDOWN) && ((abs(roi_corners[i].x - x) < 10)) && (abs(roi_corners[i].y - y) < 10))
|
||||
{
|
||||
selected_corner_index = i;
|
||||
dragging = true;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
@@ -0,0 +1,21 @@
|
||||
%YAML:1.0
|
||||
---
|
||||
calibration_time: "Wed 08 Dec 2021 05:13:09 PM MSK"
|
||||
image_width: 640
|
||||
image_height: 480
|
||||
flags: 0
|
||||
camera_matrix: !!opencv-matrix
|
||||
rows: 3
|
||||
cols: 3
|
||||
dt: d
|
||||
data: [ 4.5251072219637672e+02, 0., 3.1770297317353277e+02, 0.,
|
||||
4.5676707935146891e+02, 2.7775155919135995e+02, 0., 0., 1. ]
|
||||
distortion_coefficients: !!opencv-matrix
|
||||
rows: 1
|
||||
cols: 5
|
||||
dt: d
|
||||
data: [ 1.2136925618707872e-01, -1.0854664722560681e+00,
|
||||
1.1786843796668460e-04, -4.6240686046485508e-04,
|
||||
2.9542589406810080e+00 ]
|
||||
avg_reprojection_error: 1.8234905535936044e-01
|
||||
info: "The camera calibration parameters were obtained by img_00.jpg-img_03.jpg from aruco/tutorials/aruco_calibration/images"
|
||||
@@ -35,6 +35,20 @@ yolo:
|
||||
classes: "object_detection_classes_yolov4.txt"
|
||||
sample: "object_detection"
|
||||
|
||||
yolov4-tiny:
|
||||
load_info:
|
||||
url: "https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights"
|
||||
sha1: "451caaab22fb9831aa1a5ee9b5ba74a35ffa5dcb"
|
||||
model: "yolov4-tiny.weights"
|
||||
config: "yolov4-tiny.cfg"
|
||||
mean: [0, 0, 0]
|
||||
scale: 0.00392
|
||||
width: 416
|
||||
height: 416
|
||||
rgb: true
|
||||
classes: "object_detection_classes_yolov4.txt"
|
||||
sample: "object_detection"
|
||||
|
||||
tiny-yolo-voc:
|
||||
load_info:
|
||||
url: "https://pjreddie.com/media/files/yolov2-tiny-voc.weights"
|
||||
|
||||
@@ -103,6 +103,7 @@ int main(int argc, char** argv)
|
||||
// Inference
|
||||
std::vector< std::vector<Point> > detResults;
|
||||
detector.detect(frame, detResults);
|
||||
Mat frame2 = frame.clone();
|
||||
|
||||
if (detResults.size() > 0) {
|
||||
// Text Recognition
|
||||
@@ -131,13 +132,13 @@ int main(int argc, char** argv)
|
||||
std::string recognitionResult = recognizer.recognize(cropped);
|
||||
std::cout << i << ": '" << recognitionResult << "'" << std::endl;
|
||||
|
||||
putText(frame, recognitionResult, quadrangle[3], FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2);
|
||||
putText(frame2, recognitionResult, quadrangle[3], FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2);
|
||||
}
|
||||
polylines(frame, contours, true, Scalar(0, 255, 0), 2);
|
||||
polylines(frame2, contours, true, Scalar(0, 255, 0), 2);
|
||||
} else {
|
||||
std::cout << "No Text Detected." << std::endl;
|
||||
}
|
||||
imshow(winName, frame);
|
||||
imshow(winName, frame2);
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -126,7 +126,7 @@ int main(int argc, char** argv)
|
||||
// Detection
|
||||
std::vector< std::vector<Point> > detResults;
|
||||
detector.detect(frame, detResults);
|
||||
|
||||
Mat frame2 = frame.clone();
|
||||
if (detResults.size() > 0) {
|
||||
// Text Recognition
|
||||
Mat recInput;
|
||||
@@ -153,11 +153,11 @@ int main(int argc, char** argv)
|
||||
std::string recognitionResult = recognizer.recognize(cropped);
|
||||
std::cout << i << ": '" << recognitionResult << "'" << std::endl;
|
||||
|
||||
putText(frame, recognitionResult, quadrangle[3], FONT_HERSHEY_SIMPLEX, 1.5, Scalar(0, 0, 255), 2);
|
||||
putText(frame2, recognitionResult, quadrangle[3], FONT_HERSHEY_SIMPLEX, 1.5, Scalar(0, 0, 255), 2);
|
||||
}
|
||||
polylines(frame, contours, true, Scalar(0, 255, 0), 2);
|
||||
polylines(frame2, contours, true, Scalar(0, 255, 0), 2);
|
||||
}
|
||||
imshow(kWinName, frame);
|
||||
imshow(kWinName, frame2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ int main(int argc, char* argv[])
|
||||
if (argc < 2)
|
||||
{
|
||||
cout << "Usage: " << argv[0] << " image" << endl;
|
||||
filename = "../data/lena.jpg";
|
||||
filename = "lena.jpg";
|
||||
}
|
||||
else
|
||||
filename = argv[1];
|
||||
|
||||
Mat img = imread(filename);
|
||||
Mat img = imread(samples::findFile(filename));
|
||||
if (img.empty())
|
||||
{
|
||||
cerr << "Can't open image " << filename << endl;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""aruco_detect_board_charuco.py
|
||||
Usage example:
|
||||
python aruco_detect_board_charuco.py -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 -c=../data/aruco/tutorial_camera_charuco.yml
|
||||
-i=../data/aruco/choriginal.jpg
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import sys
|
||||
|
||||
|
||||
def read_camera_parameters(filename):
|
||||
fs = cv.FileStorage(cv.samples.findFile(filename, False), cv.FileStorage_READ)
|
||||
if fs.isOpened():
|
||||
cam_matrix = fs.getNode("camera_matrix").mat()
|
||||
dist_coefficients = fs.getNode("distortion_coefficients").mat()
|
||||
return True, cam_matrix, dist_coefficients
|
||||
return False, [], []
|
||||
|
||||
|
||||
def main():
|
||||
# parse command line options
|
||||
parser = argparse.ArgumentParser(description="detect markers and corners of charuco board, estimate pose of charuco"
|
||||
"board", add_help=False)
|
||||
parser.add_argument("-H", "--help", help="show help", action="store_true", dest="show_help")
|
||||
parser.add_argument("-v", "--video", help="Input from video or image file, if omitted, input comes from camera",
|
||||
default="", action="store", dest="v")
|
||||
parser.add_argument("-i", "--image", help="Input from image file", default="", action="store", dest="img_path")
|
||||
parser.add_argument("-w", help="Number of squares in X direction", default="3", action="store", dest="w", type=int)
|
||||
parser.add_argument("-h", help="Number of squares in Y direction", default="3", action="store", dest="h", type=int)
|
||||
parser.add_argument("-sl", help="Square side length", default="1.", action="store", dest="sl", type=float)
|
||||
parser.add_argument("-ml", help="Marker side length", default="0.5", action="store", dest="ml", type=float)
|
||||
parser.add_argument("-d", help="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}",
|
||||
default="0", action="store", dest="d", type=int)
|
||||
parser.add_argument("-ci", help="Camera id if input doesnt come from video (-v)", default="0", action="store",
|
||||
dest="ci", type=int)
|
||||
parser.add_argument("-c", help="Input file with calibrated camera parameters", default="", action="store",
|
||||
dest="cam_param")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
show_help = args.show_help
|
||||
if show_help:
|
||||
parser.print_help()
|
||||
sys.exit()
|
||||
width = args.w
|
||||
height = args.h
|
||||
square_len = args.sl
|
||||
marker_len = args.ml
|
||||
dict = args.d
|
||||
video = args.v
|
||||
camera_id = args.ci
|
||||
img_path = args.img_path
|
||||
|
||||
cam_param = args.cam_param
|
||||
cam_matrix = []
|
||||
dist_coefficients = []
|
||||
if cam_param != "":
|
||||
_, cam_matrix, dist_coefficients = read_camera_parameters(cam_param)
|
||||
|
||||
aruco_dict = cv.aruco.getPredefinedDictionary(dict)
|
||||
board_size = (width, height)
|
||||
board = cv.aruco.CharucoBoard(board_size, square_len, marker_len, aruco_dict)
|
||||
charuco_detector = cv.aruco.CharucoDetector(board)
|
||||
|
||||
image = None
|
||||
input_video = None
|
||||
wait_time = 10
|
||||
if video != "":
|
||||
input_video = cv.VideoCapture(cv.samples.findFileOrKeep(video, False))
|
||||
image = input_video.retrieve()[1] if input_video.grab() else None
|
||||
elif img_path == "":
|
||||
input_video = cv.VideoCapture(camera_id)
|
||||
image = input_video.retrieve()[1] if input_video.grab() else None
|
||||
elif img_path != "":
|
||||
wait_time = 0
|
||||
image = cv.imread(cv.samples.findFile(img_path, False))
|
||||
|
||||
if image is None:
|
||||
print("Error: unable to open video/image source")
|
||||
sys.exit(0)
|
||||
|
||||
while image is not None:
|
||||
image_copy = np.copy(image)
|
||||
charuco_corners, charuco_ids, marker_corners, marker_ids = charuco_detector.detectBoard(image)
|
||||
if not (marker_ids is None) and len(marker_ids) > 0:
|
||||
cv.aruco.drawDetectedMarkers(image_copy, marker_corners)
|
||||
if not (charuco_ids is None) and len(charuco_ids) > 0:
|
||||
cv.aruco.drawDetectedCornersCharuco(image_copy, charuco_corners, charuco_ids)
|
||||
if len(cam_matrix) > 0 and len(charuco_ids) >= 4:
|
||||
try:
|
||||
obj_points, img_points = board.matchImagePoints(charuco_corners, charuco_ids)
|
||||
flag, rvec, tvec = cv.solvePnP(obj_points, img_points, cam_matrix, dist_coefficients)
|
||||
if flag:
|
||||
cv.drawFrameAxes(image_copy, cam_matrix, dist_coefficients, rvec, tvec, .2)
|
||||
except cv.error as error_inst:
|
||||
print("SolvePnP recognize calibration pattern as non-planar pattern. To process this need to use "
|
||||
"minimum 6 points. The planar pattern may be mistaken for non-planar if the pattern is "
|
||||
"deformed or incorrect camera parameters are used.")
|
||||
print(error_inst.err)
|
||||
cv.imshow("out", image_copy)
|
||||
key = cv.waitKey(wait_time)
|
||||
if key == 27:
|
||||
break
|
||||
image = input_video.retrieve()[1] if input_video is not None and input_video.grab() else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+89
-19
@@ -5,11 +5,21 @@ camera calibration for distorted images with chess board samples
|
||||
reads distorted images, calculates the calibration and write undistorted images
|
||||
|
||||
usage:
|
||||
calibrate.py [--debug <output path>] [--square_size] [<image mask>]
|
||||
calibrate.py [--debug <output path>] [-w <width>] [-h <height>] [-t <pattern type>] [--square_size=<square size>]
|
||||
[--marker_size=<aruco marker size>] [--aruco_dict=<aruco dictionary name>] [<image mask>]
|
||||
|
||||
usage example:
|
||||
calibrate.py -w 4 -h 6 -t chessboard --square_size=50 ../data/left*.jpg
|
||||
|
||||
default values:
|
||||
--debug: ./output/
|
||||
--square_size: 1.0
|
||||
-w: 4
|
||||
-h: 6
|
||||
-t: chessboard
|
||||
--square_size: 50
|
||||
--marker_size: 25
|
||||
--aruco_dict: DICT_4X4_50
|
||||
--threads: 4
|
||||
<image mask> defaults to ../data/left*.jpg
|
||||
'''
|
||||
|
||||
@@ -30,31 +40,81 @@ def main():
|
||||
import getopt
|
||||
from glob import glob
|
||||
|
||||
args, img_mask = getopt.getopt(sys.argv[1:], '', ['debug=', 'square_size=', 'threads='])
|
||||
args, img_names = getopt.getopt(sys.argv[1:], 'w:h:t:', ['debug=','square_size=', 'marker_size=',
|
||||
'aruco_dict=', 'threads=', ])
|
||||
args = dict(args)
|
||||
args.setdefault('--debug', './output/')
|
||||
args.setdefault('--square_size', 1.0)
|
||||
args.setdefault('-w', 4)
|
||||
args.setdefault('-h', 6)
|
||||
args.setdefault('-t', 'chessboard')
|
||||
args.setdefault('--square_size', 10)
|
||||
args.setdefault('--marker_size', 5)
|
||||
args.setdefault('--aruco_dict', 'DICT_4X4_50')
|
||||
args.setdefault('--threads', 4)
|
||||
if not img_mask:
|
||||
img_mask = '../data/left??.jpg' # default
|
||||
else:
|
||||
img_mask = img_mask[0]
|
||||
|
||||
img_names = glob(img_mask)
|
||||
if not img_names:
|
||||
img_mask = '../data/left??.jpg' # default
|
||||
img_names = glob(img_mask)
|
||||
|
||||
debug_dir = args.get('--debug')
|
||||
if debug_dir and not os.path.isdir(debug_dir):
|
||||
os.mkdir(debug_dir)
|
||||
square_size = float(args.get('--square_size'))
|
||||
|
||||
pattern_size = (9, 6)
|
||||
pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)
|
||||
pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)
|
||||
pattern_points *= square_size
|
||||
height = int(args.get('-h'))
|
||||
width = int(args.get('-w'))
|
||||
pattern_type = str(args.get('-t'))
|
||||
square_size = float(args.get('--square_size'))
|
||||
marker_size = float(args.get('--marker_size'))
|
||||
aruco_dict_name = str(args.get('--aruco_dict'))
|
||||
|
||||
pattern_size = (height, width)
|
||||
if pattern_type == 'chessboard':
|
||||
pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)
|
||||
pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)
|
||||
pattern_points *= square_size
|
||||
elif pattern_type == 'charucoboard':
|
||||
pattern_points = np.zeros((np.prod((height-1, width-1)), 3), np.float32)
|
||||
pattern_points[:, :2] = np.indices((height-1, width-1)).T.reshape(-1, 2)
|
||||
pattern_points *= square_size
|
||||
else:
|
||||
print("unknown pattern")
|
||||
return None
|
||||
|
||||
obj_points = []
|
||||
img_points = []
|
||||
h, w = cv.imread(img_names[0], cv.IMREAD_GRAYSCALE).shape[:2] # TODO: use imquery call to retrieve results
|
||||
|
||||
aruco_dicts = {
|
||||
'DICT_4X4_50':cv.aruco.DICT_4X4_50,
|
||||
'DICT_4X4_100':cv.aruco.DICT_4X4_100,
|
||||
'DICT_4X4_250':cv.aruco.DICT_4X4_250,
|
||||
'DICT_4X4_1000':cv.aruco.DICT_4X4_1000,
|
||||
'DICT_5X5_50':cv.aruco.DICT_5X5_50,
|
||||
'DICT_5X5_100':cv.aruco.DICT_5X5_100,
|
||||
'DICT_5X5_250':cv.aruco.DICT_5X5_250,
|
||||
'DICT_5X5_1000':cv.aruco.DICT_5X5_1000,
|
||||
'DICT_6X6_50':cv.aruco.DICT_6X6_50,
|
||||
'DICT_6X6_100':cv.aruco.DICT_6X6_100,
|
||||
'DICT_6X6_250':cv.aruco.DICT_6X6_250,
|
||||
'DICT_6X6_1000':cv.aruco.DICT_6X6_1000,
|
||||
'DICT_7X7_50':cv.aruco.DICT_7X7_50,
|
||||
'DICT_7X7_100':cv.aruco.DICT_7X7_100,
|
||||
'DICT_7X7_250':cv.aruco.DICT_7X7_250,
|
||||
'DICT_7X7_1000':cv.aruco.DICT_7X7_1000,
|
||||
'DICT_ARUCO_ORIGINAL':cv.aruco.DICT_ARUCO_ORIGINAL,
|
||||
'DICT_APRILTAG_16h5':cv.aruco.DICT_APRILTAG_16h5,
|
||||
'DICT_APRILTAG_25h9':cv.aruco.DICT_APRILTAG_25h9,
|
||||
'DICT_APRILTAG_36h10':cv.aruco.DICT_APRILTAG_36h10,
|
||||
'DICT_APRILTAG_36h11':cv.aruco.DICT_APRILTAG_36h11
|
||||
}
|
||||
|
||||
if (aruco_dict_name not in set(aruco_dicts.keys())):
|
||||
print("unknown aruco dictionary name")
|
||||
return None
|
||||
aruco_dict = cv.aruco.getPredefinedDictionary(aruco_dicts[aruco_dict_name])
|
||||
board = cv.aruco.CharucoBoard(pattern_size, square_size, marker_size, aruco_dict)
|
||||
charuco_detector = cv.aruco.CharucoDetector(board)
|
||||
|
||||
def processImage(fn):
|
||||
print('processing %s... ' % fn)
|
||||
img = cv.imread(fn, cv.IMREAD_GRAYSCALE)
|
||||
@@ -63,10 +123,20 @@ def main():
|
||||
return None
|
||||
|
||||
assert w == img.shape[1] and h == img.shape[0], ("size: %d x %d ... " % (img.shape[1], img.shape[0]))
|
||||
found, corners = cv.findChessboardCorners(img, pattern_size)
|
||||
if found:
|
||||
term = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_COUNT, 30, 0.1)
|
||||
cv.cornerSubPix(img, corners, (5, 5), (-1, -1), term)
|
||||
found = False
|
||||
corners = 0
|
||||
if pattern_type == 'chessboard':
|
||||
found, corners = cv.findChessboardCorners(img, pattern_size)
|
||||
if found:
|
||||
term = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_COUNT, 30, 0.1)
|
||||
cv.cornerSubPix(img, corners, (5, 5), (-1, -1), term)
|
||||
elif pattern_type == 'charucoboard':
|
||||
corners, _charucoIds, _markerCorners_svg, _markerIds_svg = charuco_detector.detectBoard(img)
|
||||
if (len(corners) == (height-1)*(width-1)):
|
||||
found = True
|
||||
else:
|
||||
print("unknown pattern type", pattern_type)
|
||||
return None
|
||||
|
||||
if debug_dir:
|
||||
vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
|
||||
@@ -76,7 +146,7 @@ def main():
|
||||
cv.imwrite(outfile, vis)
|
||||
|
||||
if not found:
|
||||
print('chessboard not found')
|
||||
print('pattern not found')
|
||||
return None
|
||||
|
||||
print(' %s... OK' % fn)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import sys
|
||||
import cv2 as cv
|
||||
|
||||
|
||||
def main():
|
||||
# Open Orbbec depth sensor
|
||||
orbbec_cap = cv.VideoCapture(0, cv.CAP_OBSENSOR)
|
||||
if orbbec_cap.isOpened() == False:
|
||||
sys.exit("Fail to open camera.")
|
||||
|
||||
while True:
|
||||
# Grab data from the camera
|
||||
if orbbec_cap.grab():
|
||||
# RGB data
|
||||
ret_bgr, bgr_image = orbbec_cap.retrieve(None, cv.CAP_OBSENSOR_BGR_IMAGE)
|
||||
if ret_bgr:
|
||||
cv.imshow("BGR", bgr_image)
|
||||
|
||||
# depth data
|
||||
ret_depth, depth_map = orbbec_cap.retrieve(None, cv.CAP_OBSENSOR_DEPTH_MAP)
|
||||
if ret_depth:
|
||||
color_depth_map = cv.normalize(depth_map, None, 0, 255, cv.NORM_MINMAX, cv.CV_8UC1)
|
||||
color_depth_map = cv.applyColorMap(color_depth_map, cv.COLORMAP_JET)
|
||||
cv.imshow("DEPTH", color_depth_map)
|
||||
else:
|
||||
print("Fail to grab data from the camera.")
|
||||
|
||||
if cv.pollKey() >= 0:
|
||||
break
|
||||
|
||||
orbbec_cap.release()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user