【OpenCV/aruco】第二个AR Demo-画Cube

  • 说在前面

  • 操作系统:win10
  • vs 版本:2017
  • opencv版本:4.0.1
  • opencv-contrb版本:4.0.1
  • 接上篇:【OpenCV/aruco】第一个AR Demo-二维图片
  • 补充:使用OpenGL
  • 运行结果

  • 原理

    • 原理和上一篇一样,首先定义cube的八个顶点
      std::vector<cv::Point3f> axisPoints;
      axisPoints.push_back(cv::Point3f(half_l, half_l, l));
      axisPoints.push_back(cv::Point3f(half_l, -half_l, l));
      axisPoints.push_back(cv::Point3f(-half_l, -half_l, l));
      axisPoints.push_back(cv::Point3f(-half_l, half_l, l));
      axisPoints.push_back(cv::Point3f(half_l, half_l, 0));
      axisPoints.push_back(cv::Point3f(half_l, -half_l, 0));
      axisPoints.push_back(cv::Point3f(-half_l, -half_l, 0));
      axisPoints.push_back(cv::Point3f(-half_l, half_l, 0));
      
    • 然后将三维坐标转换到图像坐标中
      std::vector<cv::Point2f> imagePoints;
      projectPoints(
      	axisPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints
      );//opencv提供的函数,,将三维坐标转换为图像中的坐标
      
    • 最后将这些顶点用线条连接起来
      // draw cube edges lines
      cv::line(image, imagePoints[0], imagePoints[1], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[0], imagePoints[3], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[0], imagePoints[4], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[1], imagePoints[2], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[1], imagePoints[5], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[2], imagePoints[3], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[2], imagePoints[6], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[3], imagePoints[7], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[4], imagePoints[5], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[4], imagePoints[7], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[5], imagePoints[6], cv::Scalar(255, 0, 0), 3);
      cv::line(image, imagePoints[6], imagePoints[7], cv::Scalar(255, 0, 0), 3);
      
  • 代码

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

void drawCubeWireframe(
	cv::InputOutputArray image, cv::InputArray cameraMatrix,
	cv::InputArray distCoeffs, cv::InputArray rvec, cv::InputArray tvec,
	float l
);


int main(int argc, char **argv)
{
	int wait_time = 10;
	float actual_marker_l = 0.101; // this should be in meters

	VideoWriter writer("VideoTest.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), 20.0, Size(640, 480));

	cv::Mat image, image_copy;
	cv::Mat camera_matrix, dist_coeffs;
	std::ostringstream vector_to_marker;

	cv::VideoCapture in_video;
	in_video.open(0);
	cv::Ptr<cv::aruco::Dictionary> dictionary =
		cv::aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(0));

	cv::FileStorage fs("camera.yml", cv::FileStorage::READ);

	fs["camera_matrix"] >> camera_matrix;
	fs["distortion_coefficients"] >> dist_coeffs;

	std::cout << "camera_matrix\n"
		<< camera_matrix << std::endl;
	std::cout << "\ndist coeffs\n"
		<< dist_coeffs << std::endl;

	int frame_width = 480;
	int frame_height = 640;

	while (in_video.grab())
	{

		in_video.retrieve(image);
		image.copyTo(image_copy);
		std::vector<int> ids;
		std::vector<std::vector<cv::Point2f>> corners;
		cv::aruco::detectMarkers(image, dictionary, corners, ids);

		// if at least one marker detected
		if (ids.size() > 0)
		{
			cv::aruco::drawDetectedMarkers(image_copy, corners, ids);
			std::vector<cv::Vec3d> rvecs, tvecs;
			cv::aruco::estimatePoseSingleMarkers(
				corners, actual_marker_l, camera_matrix, dist_coeffs,
				rvecs, tvecs
			);

			// draw axis for each marker
			for (int i = 0; i < ids.size(); i++)
			{
				drawCubeWireframe(
					image_copy, camera_matrix, dist_coeffs, rvecs[i], tvecs[i],
					actual_marker_l
				);

				vector_to_marker.str(std::string());
				vector_to_marker << std::setprecision(4)
					<< "x: " << std::setw(8) << tvecs[0](0);
				cv::putText(image_copy, vector_to_marker.str(),
					Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 0.6,
					Scalar(0, 252, 124), 1);

				vector_to_marker.str(std::string());
				vector_to_marker << std::setprecision(4)
					<< "y: " << std::setw(8) << tvecs[0](1);
				cv::putText(image_copy, vector_to_marker.str(),
					Point(10, 50), cv::FONT_HERSHEY_SIMPLEX, 0.6,
					Scalar(0, 252, 124), 1);

				vector_to_marker.str(std::string());
				vector_to_marker << std::setprecision(4)
					<< "z: " << std::setw(8) << tvecs[0](2);
				cv::putText(image_copy, vector_to_marker.str(),
					Point(10, 70), cv::FONT_HERSHEY_SIMPLEX, 0.6,
					Scalar(0, 252, 124), 1);
			}
		}

		cv::imshow("Pose estimation", image_copy);

		writer << image_copy;

		char key = (char)cv::waitKey(wait_time);
		if (key == 'b')
			break;
	}

}

void drawCubeWireframe(
	cv::InputOutputArray image, cv::InputArray cameraMatrix,
	cv::InputArray distCoeffs, cv::InputArray rvec, cv::InputArray tvec,
	float l
)
{

	CV_Assert(
		image.getMat().total() != 0 &&
		(image.getMat().channels() == 1 || image.getMat().channels() == 3)
	);
	CV_Assert(l > 0);
	float half_l = l / 2.0;

	// project cube points
	std::vector<cv::Point3f> axisPoints;
	axisPoints.push_back(cv::Point3f(half_l, half_l, l));
	axisPoints.push_back(cv::Point3f(half_l, -half_l, l));
	axisPoints.push_back(cv::Point3f(-half_l, -half_l, l));
	axisPoints.push_back(cv::Point3f(-half_l, half_l, l));
	axisPoints.push_back(cv::Point3f(half_l, half_l, 0));
	axisPoints.push_back(cv::Point3f(half_l, -half_l, 0));
	axisPoints.push_back(cv::Point3f(-half_l, -half_l, 0));
	axisPoints.push_back(cv::Point3f(-half_l, half_l, 0));

	std::vector<cv::Point2f> imagePoints;
	projectPoints(
		axisPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints
	);

	// draw cube edges lines
	cv::line(image, imagePoints[0], imagePoints[1], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[0], imagePoints[3], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[0], imagePoints[4], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[1], imagePoints[2], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[1], imagePoints[5], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[2], imagePoints[3], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[2], imagePoints[6], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[3], imagePoints[7], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[4], imagePoints[5], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[4], imagePoints[7], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[5], imagePoints[6], cv::Scalar(255, 0, 0), 3);
	cv::line(image, imagePoints[6], imagePoints[7], cv::Scalar(255, 0, 0), 3);
}


接下来想办法使用opengl了≡(▔﹏▔)≡

你可能感兴趣的:(AR,opencv,aruco,cube)