ARToolKitみたいなもんだと思ってもらって大丈夫。
個人的にはプログラムがすっきりしているのでこっちのほうが好き。
Aruco付きOpenCVのインストールについては
opencvとarucoのインストール
作ったプログラム(サンプル撮影画像もあります)
https://bitbucket.org/asama-yaya/opencv_arucomarke...
マーカとカメラ間の位置関係を求める
ボードとカメラ間の位置関係を求める
単一マーカより精度は良い
チェッカの交点を求める
カメラキャリブレーションにも使える
上のボードとしても使える
ダイアモンドとカメラ間の位置関係を求める
ダイアモンドについては参考ページの画像見ればわかると思う
全部単位は[m]です。
DICT_6X6_250は6x6の格子でマーカを作って、IDは合計250個ということ。
おまじないだと思ってもらってかまわない。
cv::aruco::drawMarker(辞典, マーカID, marker_size[pix], OutputImage, ややこしいので1);
cv::aruco::GridBoard::create(X軸のマーカ数, Y軸のマーカ数, マーカの長さ[m], マーカ間の長さ[m], 辞典);
board->draw(画像サイズ, OutputImage, マーカ間の最小の長さ[pix], ややこしいので1);
マーカの長さ→四角形の長さ
マーカ間の長さ→マーカの長さ
に置き換えてください
ほぼマーカ作成のときにやったことと同じ。
使用する辞典が何かとか、マーカの大きさとかは事前に登録してる。
個人的にはプログラムがすっきりしているのでこっちのほうが好き。
Aruco付きOpenCVのインストールについては
opencvとarucoのインストール
作ったプログラム(サンプル撮影画像もあります)
https://bitbucket.org/asama-yaya/opencv_arucomarke...
arucoマーカの認識
http://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco...
arucoボードの認識
http://docs.opencv.org/3.2.0/db/da9/tutorial_aruco...
arucoチェスボードの認識
http://docs.opencv.org/3.2.0/df/d4a/tutorial_charu...
arucoダイアモンドマーカの認識
http://docs.opencv.org/3.2.0/d5/d07/tutorial_charu...
http://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco...
arucoボードの認識
http://docs.opencv.org/3.2.0/db/da9/tutorial_aruco...
arucoチェスボードの認識
http://docs.opencv.org/3.2.0/df/d4a/tutorial_charu...
arucoダイアモンドマーカの認識
http://docs.opencv.org/3.2.0/d5/d07/tutorial_charu...
#include <opencv2/aruco.hpp> // aruco marker #include <opencv2/aruco/charuco.hpp> // for aruco chess board
namespace{
const int ARUCO_SingleMarker = 0;
const int ARUCO_Board = 1;
const int ARUCO_ChessBoard = 2;
const int ARUCO_Diamond = 3;
}
class TMyAruco{
// marker type
int markerType = ARUCO_SingleMarker;
// single marker
cv::Ptr<cv::aruco::Dictionary> markerDictionary;
double markerSingleSize = 0.132; // marker size [m]
vector<cv::Vec3d> rvecsSingle, tvecsSingle;
// board
cv::Ptr<cv::aruco::GridBoard> markerBoard;
cv::Point2d markerBoardSize = cv::Point2d(0.025, 0.007);
cv::Vec3d rvecBoard, tvecBoard;
// chess
cv::Ptr<cv::aruco::CharucoBoard> markerChess;
cv::Point2d markerChessSize = cv::Point2d(0.031, 0.0155);
vector<cv::Point2f> cornersChess;
vector<int> idsChess;
// diamond
cv::Point2d markerDiamondSize = cv::Point2d(0.053, 0.0315);
vector<cv::Vec3d> rvecsDiamond, tvecsDiamond;
};
最初にあげたもの4つをmarkerTypeを変更することでそれぞれ認識できるようになっている。- Single
マーカとカメラ間の位置関係を求める
- Board
ボードとカメラ間の位置関係を求める
単一マーカより精度は良い
- Chess
チェッカの交点を求める
カメラキャリブレーションにも使える
上のボードとしても使える
- Diamond
ダイアモンドとカメラ間の位置関係を求める
ダイアモンドについては参考ページの画像見ればわかると思う
全部単位は[m]です。
cv::Mat markerImage;
// single marker
if (markerType == ARUCO_SingleMarker){
cv::Ptr<cv::aruco::Dictionary> dictionary =
cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::aruco::drawMarker(dictionary, 23, 200, markerImage, 1);
cv::imwrite("data\\marker.png", markerImage);
}
// board
else if (markerType == ARUCO_Board){
cv::Ptr<cv::aruco::Dictionary> dictionary =
cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr<cv::aruco::GridBoard> board =
cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
board->draw(cv::Size(600, 500), markerImage, 10, 1);
cv::imwrite("data\\board.png", markerImage);
}
// chessboard
else if (markerType == ARUCO_ChessBoard){
cv::Ptr<cv::aruco::Dictionary> dictionary =
cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr<cv::aruco::CharucoBoard> board =
cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
board->draw(cv::Size(600, 500), markerImage, 10, 1);
cv::imwrite("data\\chess.png", markerImage);
}
// diamond
else if (markerType == ARUCO_Diamond){
cv::Ptr<cv::aruco::Dictionary> dictionary =
cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::aruco::drawCharucoDiamond(dictionary, cv::Vec4i(45, 68, 28, 74), 200, 120, markerImage);
cv::imwrite("data\\diamond.png", markerImage);
cv::aruco::drawCharucoDiamond(dictionary, cv::Vec4i(15, 28, 26, 34), 200, 120, markerImage);
cv::imwrite("data\\diamond(2).png", markerImage);
}
cv::aruco::Dictionary(以下、辞典)はマーカの種類を指定している。DICT_6X6_250は6x6の格子でマーカを作って、IDは合計250個ということ。
おまじないだと思ってもらってかまわない。
- Single
cv::aruco::drawMarker(辞典, マーカID, marker_size[pix], OutputImage, ややこしいので1);
- Board
cv::aruco::GridBoard::create(X軸のマーカ数, Y軸のマーカ数, マーカの長さ[m], マーカ間の長さ[m], 辞典);
board->draw(画像サイズ, OutputImage, マーカ間の最小の長さ[pix], ややこしいので1);
- ChessBoard
マーカの長さ→四角形の長さ
マーカ間の長さ→マーカの長さ
に置き換えてください
- Diamond
if (markerType == ARUCO_SingleMarker){
markerDictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
}
else if (markerType == ARUCO_Board){
markerDictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
markerBoard =cv::aruco::GridBoard::create(5, 7,
markerBoardSize.x, markerBoardSize.y, markerDictionary);
}
else if (markerType == ARUCO_ChessBoard){
markerDictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
markerChess = cv::aruco::CharucoBoard::create(5, 7,
markerChessSize.x, markerChessSize.y, markerDictionary);
}
else if (markerType == ARUCO_Diamond){
markerDictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
}
ほぼマーカ作成のときにやったことと同じ。
使用する辞典が何かとか、マーカの大きさとかは事前に登録してる。
undistImage: 歪補正後の画像
intrinsic: カメラの内部パラメータ
distortion: カメラの歪パラメータ(今回は歪補正後なので値は全部0)
detect markerのところで、まずマーカを認識する。
その後、それぞれのタイプに応じて推定を行う。
マーカの端っこの点の情報からマーカの位置推定を行う。
rvecs, tvecsにそれぞれのマーカとの位置関係が入っている。
rが回転成分、tが直進成分
回転成分に関してはrodriguesなので注意
http://opencv.jp/opencv-2svn/cpp/camera_calibratio...
見つけたマーカ全部の情報を使ってボードの位置推定を行う
マーカがある程度隠れていてもOKで精度も良い。
チェッカーの交点を求める。
交点にもIDが割り振られているみたいでidsChessに入ってる。
普通にチェッカー求めるより精度がいいのかな?
スピードはかなりはやくなってると思う。
cv::aruco::estimatePoseSingleMarkers
まずDiamondを見つけて、それを一つのマーカとして位置推定を行うといった流れ。
intrinsic: カメラの内部パラメータ
distortion: カメラの歪パラメータ(今回は歪補正後なので値は全部0)
detect markerのところで、まずマーカを認識する。
その後、それぞれのタイプに応じて推定を行う。
// detect marker
vector<int> ids;
vector<vector<cv::Point2f>> corners;
cv::aruco::detectMarkers(undistImage, markerDictionary, corners, ids);
// if at least one marker is detected
if (ids.size() > 0){
// single marker
if (markerType == ARUCO_SingleMarker){
// draw id
cv::aruco::drawDetectedMarkers(undistImage, corners, ids);
// pose estimation
rvecsSingle.clear(); tvecsSingle.clear();
cv::aruco::estimatePoseSingleMarkers(corners, markerSingleSize,
intrinsic, distortion, rvecsSingle, tvecsSinge);
// draw axis
for (int ii = 0; ii < ids.size(); ii++)
cv::aruco::drawAxis(undistImage, intrinsic, distortion,
rvecsSingle[ii], tvecsSingle[ii], 0.1);
}
// board
else if (markerType == ARUCO_Board){
cv::aruco::drawDetectedMarkers(undistImage, corners, ids);
int valid = cv::aruco::estimatePoseBoard(corners, ids,
markerBoard, intrinsic, distortion, rvecBoard, tvecBoad);
// if at least one board marker detected
if (valid > 0)
cv::aruco::drawAxis(undistImage, intrinsic, distortion,
rvecBoard, tvecBoard, 0.1);
}
// chessboard
else if (markerType == ARUCO_ChessBoard){
cornersChess.clear();
idsChess.clear();
cv::aruco::interpolateCornersCharuco(corners, ids, undistImage,
markerChess, cornersChess, idsChess);
cv::aruco::drawDetectedMarkers(undistImage, corners, ids);
// if at least one charuco corner detected
if (idsChess.size() > 0)
cv::aruco::drawDetectedCornersCharuco(undistImage,
cornersChess, idsChess, cv::Scalar(0, 0, 255));
}
// diamond
else if (markerType == ARUCO_Diamond){
// detect diamon diamonds
vector<cv::Vec4i> idsDiamond;
vector<vector<cv::Point2f>> cornersDiamond;
cv::aruco::detectCharucoDiamond(undistImage, corners, ids,
(markerDiamondSize.x / markerDiamondSize.y), cornersDiamond, idsDiamond);
cv::aruco::drawDetectedMarkers(undistImage, corners, ids);
// estimate poses
rvecsDiamond.clear();
tvecsDiamond.clear();
cv::aruco::estimatePoseSingleMarkers(cornersDiamond, markerDiamondSize.x,
intrinsic, distortion, rvecsDiamond, tvecsDiamond);
// draw axis
for (unsigned int i = 0; i<rvecsDiamond.size(); i++)
cv::aruco::drawAxis(undistImage, intrinsic, distortion,
rvecsDiamond[i], tvecsDiamond[i], 0.1);
}
}
- Single
マーカの端っこの点の情報からマーカの位置推定を行う。
rvecs, tvecsにそれぞれのマーカとの位置関係が入っている。
rが回転成分、tが直進成分
回転成分に関してはrodriguesなので注意
http://opencv.jp/opencv-2svn/cpp/camera_calibratio...
- Board
見つけたマーカ全部の情報を使ってボードの位置推定を行う
マーカがある程度隠れていてもOKで精度も良い。
- ChessBoard
チェッカーの交点を求める。
交点にもIDが割り振られているみたいでidsChessに入ってる。
普通にチェッカー求めるより精度がいいのかな?
スピードはかなりはやくなってると思う。
- Diamond
cv::aruco::estimatePoseSingleMarkers
まずDiamondを見つけて、それを一つのマーカとして位置推定を行うといった流れ。

コメントをかく