如何在 opencv 中的 Aruco 标记上绘制一个矩形?
How to draw a rectangle on the Aruco marker in opencv?
我有一个程序来绘制和检测aruco标记,并在上面写上标记id。我需要一个矩形出现在每个标记上而不是标记 id,我可以绘制一个矩形但在固定位置不在标记上,这里是代码:
#include <opencv2\highgui.hpp>
#include <opencv2\aruco.hpp>
#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\imgproc.hpp>
#include <opencv2\calib3d.hpp>
#include <sstream>
#include <fstream>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char *argv[]) {
cv::VideoCapture inputVideo;
inputVideo.open(0);
Mat outputMarker;
auto markerDict = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
for (int i = 0; i < 50; i++) {
aruco::drawMarker(markerDict, i, 500, outputMarker, 1);
ostringstream convert;
String imageName = "4x4marker_";
convert << imageName << i << ".jpg";
imwrite(convert.str(), outputMarker);
while (inputVideo.grab()) {
cv::Mat image, imageCopy;
inputVideo.retrieve(image);
image.copyTo(imageCopy);
std::vector<int> ids;
std::vector<std::vector<cv::Point2f> > corners;
cv::aruco::detectMarkers(image, markerDict, corners, ids);
// if at least one marker detected
if (ids.size() > 0)
cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
int x = 0;
int y = 3;
rectangle(imageCopy, Point(imageCopy.cols/2, imageCopy.rows/2),
Point(x,y),Scalar::all(255), -1, 8, 0);
cv::imshow("out", imageCopy);
char key = (char)cv::waitKey(5);
if (key == 27)
break;
}
}
}
简化代码测试的示例标记。
当你使用detectMarkers
函数时,它returns检测每个角点。在你的例子中,你将它放入 std::vector<std::vector<cv::Point2f> > corners
。要绘制您要求的矩形,您可以执行类似的操作(以下代码是一个示例,尚未经过测试):
for (size_t i = 0; i< corners.size(); +i)
{
cv::Point2f p0(image.cols,image.rows);
cv::Ponit2f p1(0,0);
for (auto p: corners[i])
{
if (p.x < p0.x)
p0.x = p.x;
if (p.y < p0.y)
p0.y = p.y;
if (p.x > p1.x)
p1.x = p.x;
if (p.y > p1.y)
p1.y = p.y;
}
rectangle(imageCopy, p0, p1,Scalar::all(255), -1, 8, 0);
}
但是,您可能想要绘制一个更适合标记的多边形,因为如果标记不完全垂直于相机光轴并且没有失真,图像上的标记投影将不是矩形。为此,您可以使用 fillPoly
, or if you don't want it filled line
.
Here 是在 Ubuntu 中使用 OpenCV 4.3.0-pre 和 3.2.0 以及 Windows:
中的 3.4.9 测试的全功能示例
#include <iostream>
#include <opencv2/aruco.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main(int argc, char** argv)
{
// Check cv versionmake
std::cout << "Using OpenCV version: " << CV_VERSION << std::endl;
// Create video input
cv::VideoCapture inputVideo;
int input_source(0);
if (argc > 1)
input_source = std::atoi(argv[1]);
if (!inputVideo.open(input_source))
{
std::cerr << "Error opening input video soruce: " << input_source << std::endl;
return EXIT_FAILURE;
}
// Create marker dictionary
auto marker_dict = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
// Get imshow ready
cv::namedWindow("Display window", cv::WINDOW_KEEPRATIO | cv::WINDOW_NORMAL);
cv::resizeWindow("Display window", 800, 600);
// Grab images until escape is pressed
int key = 0;
while (key != 27 && inputVideo.grab())
{
// Retrieve image
cv::Mat image;
inputVideo.retrieve(image);
// Get image output ready
cv::Size image_size = image.size();
cv::Mat out_image(image_size.height, 3 * image_size.width, CV_8UC3);
cv::Mat left(out_image, cv::Rect(0, 0, image_size.width, image_size.height));
image.copyTo(left);
cv::Mat mid(out_image, cv::Rect(image_size.width, 0, image_size.width, image_size.height));
image.copyTo(mid);
cv::Mat right(out_image, cv::Rect(2 * image_size.width, 0, image_size.width, image_size.height));
image.copyTo(right);
// Add names to images
int corner_offset = 50;
cv::putText(left, "Original image", cv::Point(corner_offset, corner_offset), cv::FONT_HERSHEY_DUPLEX, 1.0,
CV_RGB(0, 0, 0), 2);
cv::putText(mid, "Image with OpenCV drawing", cv::Point(corner_offset, corner_offset), cv::FONT_HERSHEY_DUPLEX, 1.0,
CV_RGB(0, 0, 0), 2);
cv::putText(right, "Image with custom drawing", cv::Point(corner_offset, corner_offset), cv::FONT_HERSHEY_DUPLEX,
1.0, CV_RGB(0, 0, 0), 2);
// Detect markers
std::vector<int> ids;
std::vector<std::vector<cv::Point2f> > corners;
cv::aruco::detectMarkers(image, marker_dict, corners, ids);
// Draw markers using opencv tool
cv::aruco::drawDetectedMarkers(mid, corners, ids);
// Draw markers custom
for (size_t i = 0; i < corners.size(); ++i)
{
// Convert to integer ponits
int num = static_cast<int>(corners[i].size());
std::vector<cv::Point> points;
for (size_t j = 0; j < corners[i].size(); ++j)
points.push_back(cv::Point(static_cast<int>(corners[i][j].x), static_cast<int>(corners[i][j].y)));
const cv::Point* pts = &(points[0]);
// Draw
cv::fillPoly(right, &pts, &num, 1, cv::Scalar(255, 0, 0));
// Draw contour
for (size_t j = 0; j < corners[i].size(); ++j)
{
size_t next = (j + 1) % corners[i].size();
cv::line(right, corners[i][j], corners[i][next], cv::Scalar(0, 255, 0), 5);
}
}
// Display
cv::imshow("Display window", out_image);
key = cv::waitKey(5);
}
return EXIT_SUCCESS;
}
这是您将使用此代码获得的输出:
w=12=sh@apalomersh=10=shsh=11=sh
我有一个程序来绘制和检测aruco标记,并在上面写上标记id。我需要一个矩形出现在每个标记上而不是标记 id,我可以绘制一个矩形但在固定位置不在标记上,这里是代码:
#include <opencv2\highgui.hpp>
#include <opencv2\aruco.hpp>
#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\imgproc.hpp>
#include <opencv2\calib3d.hpp>
#include <sstream>
#include <fstream>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char *argv[]) {
cv::VideoCapture inputVideo;
inputVideo.open(0);
Mat outputMarker;
auto markerDict = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
for (int i = 0; i < 50; i++) {
aruco::drawMarker(markerDict, i, 500, outputMarker, 1);
ostringstream convert;
String imageName = "4x4marker_";
convert << imageName << i << ".jpg";
imwrite(convert.str(), outputMarker);
while (inputVideo.grab()) {
cv::Mat image, imageCopy;
inputVideo.retrieve(image);
image.copyTo(imageCopy);
std::vector<int> ids;
std::vector<std::vector<cv::Point2f> > corners;
cv::aruco::detectMarkers(image, markerDict, corners, ids);
// if at least one marker detected
if (ids.size() > 0)
cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
int x = 0;
int y = 3;
rectangle(imageCopy, Point(imageCopy.cols/2, imageCopy.rows/2),
Point(x,y),Scalar::all(255), -1, 8, 0);
cv::imshow("out", imageCopy);
char key = (char)cv::waitKey(5);
if (key == 27)
break;
}
}
}
简化代码测试的示例标记。
当你使用detectMarkers
函数时,它returns检测每个角点。在你的例子中,你将它放入 std::vector<std::vector<cv::Point2f> > corners
。要绘制您要求的矩形,您可以执行类似的操作(以下代码是一个示例,尚未经过测试):
for (size_t i = 0; i< corners.size(); +i)
{
cv::Point2f p0(image.cols,image.rows);
cv::Ponit2f p1(0,0);
for (auto p: corners[i])
{
if (p.x < p0.x)
p0.x = p.x;
if (p.y < p0.y)
p0.y = p.y;
if (p.x > p1.x)
p1.x = p.x;
if (p.y > p1.y)
p1.y = p.y;
}
rectangle(imageCopy, p0, p1,Scalar::all(255), -1, 8, 0);
}
但是,您可能想要绘制一个更适合标记的多边形,因为如果标记不完全垂直于相机光轴并且没有失真,图像上的标记投影将不是矩形。为此,您可以使用 fillPoly
, or if you don't want it filled line
.
Here 是在 Ubuntu 中使用 OpenCV 4.3.0-pre 和 3.2.0 以及 Windows:
中的 3.4.9 测试的全功能示例#include <iostream>
#include <opencv2/aruco.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main(int argc, char** argv)
{
// Check cv versionmake
std::cout << "Using OpenCV version: " << CV_VERSION << std::endl;
// Create video input
cv::VideoCapture inputVideo;
int input_source(0);
if (argc > 1)
input_source = std::atoi(argv[1]);
if (!inputVideo.open(input_source))
{
std::cerr << "Error opening input video soruce: " << input_source << std::endl;
return EXIT_FAILURE;
}
// Create marker dictionary
auto marker_dict = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
// Get imshow ready
cv::namedWindow("Display window", cv::WINDOW_KEEPRATIO | cv::WINDOW_NORMAL);
cv::resizeWindow("Display window", 800, 600);
// Grab images until escape is pressed
int key = 0;
while (key != 27 && inputVideo.grab())
{
// Retrieve image
cv::Mat image;
inputVideo.retrieve(image);
// Get image output ready
cv::Size image_size = image.size();
cv::Mat out_image(image_size.height, 3 * image_size.width, CV_8UC3);
cv::Mat left(out_image, cv::Rect(0, 0, image_size.width, image_size.height));
image.copyTo(left);
cv::Mat mid(out_image, cv::Rect(image_size.width, 0, image_size.width, image_size.height));
image.copyTo(mid);
cv::Mat right(out_image, cv::Rect(2 * image_size.width, 0, image_size.width, image_size.height));
image.copyTo(right);
// Add names to images
int corner_offset = 50;
cv::putText(left, "Original image", cv::Point(corner_offset, corner_offset), cv::FONT_HERSHEY_DUPLEX, 1.0,
CV_RGB(0, 0, 0), 2);
cv::putText(mid, "Image with OpenCV drawing", cv::Point(corner_offset, corner_offset), cv::FONT_HERSHEY_DUPLEX, 1.0,
CV_RGB(0, 0, 0), 2);
cv::putText(right, "Image with custom drawing", cv::Point(corner_offset, corner_offset), cv::FONT_HERSHEY_DUPLEX,
1.0, CV_RGB(0, 0, 0), 2);
// Detect markers
std::vector<int> ids;
std::vector<std::vector<cv::Point2f> > corners;
cv::aruco::detectMarkers(image, marker_dict, corners, ids);
// Draw markers using opencv tool
cv::aruco::drawDetectedMarkers(mid, corners, ids);
// Draw markers custom
for (size_t i = 0; i < corners.size(); ++i)
{
// Convert to integer ponits
int num = static_cast<int>(corners[i].size());
std::vector<cv::Point> points;
for (size_t j = 0; j < corners[i].size(); ++j)
points.push_back(cv::Point(static_cast<int>(corners[i][j].x), static_cast<int>(corners[i][j].y)));
const cv::Point* pts = &(points[0]);
// Draw
cv::fillPoly(right, &pts, &num, 1, cv::Scalar(255, 0, 0));
// Draw contour
for (size_t j = 0; j < corners[i].size(); ++j)
{
size_t next = (j + 1) % corners[i].size();
cv::line(right, corners[i][j], corners[i][next], cv::Scalar(0, 255, 0), 5);
}
}
// Display
cv::imshow("Display window", out_image);
key = cv::waitKey(5);
}
return EXIT_SUCCESS;
}
这是您将使用此代码获得的输出: