bbenligiray / stag

STag: A Stable Fiducial Marker System
MIT License
187 stars 52 forks source link

How to Draw a Axes on the image from Stag? #11

Open DavidLeeDoosan opened 4 years ago

DavidLeeDoosan commented 4 years ago

How to Draw a Axes on the image from Stag?

After running your program, I had some result such as 1 edges.png ~ 8 ellipses.png, but there is no Homography Refinement image. You mentioned (j) Homography Refinement in Figure 7 on the paper. How can I make Homography Refinement Image such as Drawing a Axes.

image

image

bbenligiray commented 4 years ago

You need to calibrate your camera, calculate the pose of the marker, project the axis points to the image using these and draw lines between the projected points. I'm copy pasting an example below.

Note that the axis may end up looking wrong due to this https://stackoverflow.com/questions/32447357/solvepnp-pose-estimation-for-planar-object-ambiguous-case I went through all the existing solutions and none of them produce satisfactory results. So if your axis looks wrong, your best bet would be to use useExtrinsicGuess and randomize the rvec/tvec starting point until you end up with a good looking result (or just use a different image).

cv::Mat image = cv::imread("0.png", CV_LOAD_IMAGE_GRAYSCALE);

edm.detectMarkers(image, false);
//edm.dumpLog(outPath, "teaser");
Mat colorImage;
cv::cvtColor(image, colorImage, CV_GRAY2BGR);

Marker marker = edm.getMarkers()[0];

vector<cv::Point3f> objectPoints;
objectPoints.push_back(cv::Point3f(0, 0, 0));
objectPoints.push_back(cv::Point3f(1, 0, 0));
objectPoints.push_back(cv::Point3f(1, 1, 0));
objectPoints.push_back(cv::Point3f(0, 1, 0));

Mat cameraMatrix = (cv::Mat)(cv::Matx33d(1408.654794182396, 0, 981.1555853221231, 0, 1404.977436090862, 561.9808485811495, 0, 0, 1));
vector<double> distCoeff = { 0.126706318892812, -0.206388301229407, 0, 0 };

Mat rvec, tvec;

cv::solvePnP(objectPoints, marker.corners, cameraMatrix, distCoeff, rvec, tvec);

objectPoints.clear();
float axisLength = 0.5;
objectPoints.push_back(cv::Point3f(0, 0, 0));
objectPoints.push_back(cv::Point3f(axisLength, 0, 0));
objectPoints.push_back(cv::Point3f(0, axisLength, 0));
objectPoints.push_back(cv::Point3f(0, 0, -axisLength));

vector<cv::Point2f> imagePoints;
cv::projectPoints(objectPoints, rvec, tvec, cameraMatrix, distCoeff, imagePoints);

cv::line(colorImage, cv::Point(imagePoints[0].x, imagePoints[0].y), cv::Point(imagePoints[1].x, imagePoints[1].y), cv::Scalar(255, 255, 255), 5, CV_AA);
cv::line(colorImage, cv::Point(imagePoints[0].x, imagePoints[0].y), cv::Point(imagePoints[2].x, imagePoints[2].y), cv::Scalar(255, 255, 255), 5, CV_AA);
cv::line(colorImage, cv::Point(imagePoints[0].x, imagePoints[0].y), cv::Point(imagePoints[3].x, imagePoints[3].y), cv::Scalar(255, 255, 25), 5, CV_AA);

cv::line(colorImage, cv::Point(imagePoints[0].x, imagePoints[0].y), cv::Point(imagePoints[1].x, imagePoints[1].y), cv::Scalar(0, 0, 255), 2, CV_AA);
cv::line(colorImage, cv::Point(imagePoints[0].x, imagePoints[0].y), cv::Point(imagePoints[2].x, imagePoints[2].y), cv::Scalar(0, 255, 0), 2, CV_AA);
cv::line(colorImage, cv::Point(imagePoints[0].x, imagePoints[0].y), cv::Point(imagePoints[3].x, imagePoints[3].y), cv::Scalar(255, 0, 0), 2, CV_AA);

vector<int> compressionParams = { CV_IMWRITE_PNG_COMPRESSION, 0 };
cv::imwrite("teaser.png", colorImage, compressionParams);