前回は「OpenCV」+「Python」でArUcoマーカを生成・認識する手順について解説しましたので、今回は「OpenCV」+「C++」での手順を解説します。

1. 使用した環境

・Ubuntu 18.04 LTS
・OpenCV 4.5.5
・cmake 3.10.2

2. 必要なパッケージのインストール

以下のコマンドを実行し、必要なパッケージのインストールを行います。

sudo apt install build-essential cmake libgtk2.0-dev pkg-config

3. OpenCVと拡張モジュール群のダウンロード

3.1. OpenCVのダウンロード
以下のサイトにアクセスするとバージョンごとのOpenCVライブラリが表示されるので、最新版のOpenCVの「Sources」をクリックしダウンロードします。
OpenCV:https://opencv.org/releases/

 
3.2. 拡張モジュール群のダウンロード
OpenCVの拡張モジュール群をダウンロードします。以下のサイトの「Switch branches/tags」からOpenCVと同様のバージョンを選択します。「Code」→「Download ZIP」からダウンロードします。
opencv_contrib:https://github.com/opencv/opencv_contrib

 

 
3.3. ダウンロードファイルの解凍
ダウンロードした「opencv-x.x.x.zip」、「opencv_contrib-x.x.x.zip」を解凍します。
※ x.x.xは、ダウンロードするバージョンにより異なります。

cd ~/ダウンロード
unzip opencv-x.x.x.zip -d ~/
unzip opencv_contrib-x.x.x.zip -d ~/opencv-x.x.x/

4. OpenCVと拡張モジュール群のインストール

以下のコマンドを実行しOpenCVと拡張モジュールのインストールを行います。

cd ~/opencv-x.x.x
mkdir build
cd build
cmake -DOPENCV_EXTRA_MODULES_PATH=~/opencv-x.x.x/opencv_contrib-x.x.x/modules ..
make
sudo make install

※  x.x.xには、ダウンロードしたOpenCVのバージョンを指定してください。

5. ArUcoマーカの生成

5.1. ArUcoマーカ生成プログラムの作成
以下のArUcoマーカ自動生成プログラムをコピーし、「arMarkerGenerator.cpp」を保存します。
本プログラムで生成できるArUcoマーカの種類は、20行目の「cv::aruco::DICT_4X4_50」で指定しています。
これは、「DICT_ビット数_ID数」となっており、ビット数は縦横のビット数を指し、ID数は生成できるマーカの数を指しています。
今回は、「aruco.DICT_4X4_50」なので、縦横が4ビットで、生成できるマーカの数が0~49の計50個となります。

cd ~/
mkdir -p ArMarker/src
cd ~/ArMarker/src
gedit arMarkerGenerator.cpp
// OpenCV
#include <opencv4/opencv2/opencv.hpp>
// ArUco
#include <opencv4/opencv2/aruco.hpp>

class arMarkerGenerator{
public:
	int pixel = 150;
	int offset = 10;
	static const int CNT = 9;

	void generateArMarker()
	{
		cv::Mat img = cv::Mat::zeros(pixel + offset, pixel + offset, CV_8UC1);
		cv::Mat hconcat_img, vconcat_img;
		img = cv::Scalar(255, 255, 255);
		int x_offset, y_offset;
		x_offset = y_offset = (int)(offset / 2);

		cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50);

		for(int i = 0; i < CNT; i++){
			cv::Mat ar_img;
			cv::aruco::drawMarker(dictionary, i, pixel, ar_img, 1);
			// ファイル名の設定
			std::string file_nm = "ar" + std::to_string(i) + ".png";
			// アフィン行列
			cv::Mat mat = (cv::Mat_<double>(2,3)<<1.0, 0.0, x_offset, 0.0, 1.0, y_offset);
			
			// アフィン変換
			cv::warpAffine(ar_img, img, mat, img.size(), cv::INTER_LINEAR, cv::BORDER_TRANSPARENT);
			// グレースケールからRGBへ変換
			cv::Mat rgb_img;
			cv::cvtColor(img, rgb_img, cv::COLOR_GRAY2RGB);

			if(i % 3 == 0){
				hconcat_img = rgb_img;
			} else if(i % 3 <=2){
				cv::hconcat(hconcat_img, rgb_img, hconcat_img);				
				if(i % 3 == 2 && i / 3 == 0){
					vconcat_img = hconcat_img;
				} else if(i % 3 == 2 && i / 3 > 0){
					cv::vconcat(vconcat_img, hconcat_img, vconcat_img);
				}
			}
			// Output RGB image.
			cv::imwrite(file_nm, rgb_img);
		}
		cv::imwrite("ar" + std::to_string(CNT) + ".png", vconcat_img);
	}
};

int main(int argc, char* argv[]){
	arMarkerGenerator ar;
	ar.generateArMarker();

	return 0;
}

 
5.2. CMakeLists.txtの作成
以下のCMakeListsの内容をコピーし、「CMakeLists.txt」を保存します。

gedit CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
# OpenCVのバージョンを指定
set(OCV_VERSION "4.5")
project(src)
# OpenCVパッケージの設定を検索し読み込む
find_package(OpenCV ${OCV_VERSION} REQUIRED)
# ArUco marker
add_executable(arMarkerGenerator arMarkerGenerator.cpp)

if(OpenCV_FOUND)
    target_include_directories(arMarkerGenerator PRIVATE ${OpenCV_INCLUDE_DIRS})
    target_link_libraries(arMarkerGenerator ${OpenCV_LIBS})
endif()

 
5.3. ArUcoマーカ生成プログラムのビルド・実行
以下のコマンドを実行し、ビルド・実行を行います。プログラムを実行すると「build」ディレクトリにArUcoマーカが生成されます。

mkdir build
cd build
cmake ..
make
./arMarkerGenerator

 


図 1. 自動生成したArUcoマーカ

6. ArUcoマーカの検出

6.1. ArUcoマーカ検出プログラムの作成
以下のArUcoマーカ検出プログラムをコピーし、「arMarkerRecognizer.cpp」を保存します。

cd ~/ArMarker/src
gedit arMarkerRecognizer.cpp
// OpenCV
#include <opencv4/opencv2/opencv.hpp>
// ARマーカ関連
#include <opencv4/opencv2/aruco.hpp>

class arMarkerRecognizer{
public:
	static const int cnt = 9;
	void recognizeArMarker()
	{
		cv::Ptr<cv::aruco::DetectorParameters> parameters = cv::aruco::DetectorParameters::create();
			cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_100);

		for(int i = 0; i < cnt + 1; i++){
			// 入力ファイル名
			std::string input_file_nm = "ar" + std::to_string(i) + ".png";
			// 出力ファイル名
			std::string output_file_nm = "ar_detection" + std::to_string(i) + ".png";
			// 入力ファイルの読み込み
			cv::Mat input_img = cv::imread(input_file_nm, cv::IMREAD_COLOR);

			std::vector<std::vector<cv::Point2f>> corners, rejectedCandidates;
			std::vector<int> ids;

			// ArUcoマーカの検出
			cv::aruco::detectMarkers(input_img, dictionary, corners, ids, parameters, rejectedCandidates);
	
			if(ids.size() > 0){
				cv::Mat output_img = input_img.clone();
				// ArUcoマーカの検出結果の描画
				cv:: aruco::drawDetectedMarkers(output_img, corners, ids);
				// ArUcoマーカの検出結果をファイル出力
				cv::imwrite(output_file_nm, output_img);
			}
		}
	}
};

int main(int argc, char* argv[]){
	arMarkerRecognizer ar;
	ar.recognizeArMarker();

	return 0;
}

 
6.2. CMakeLists.txtの追加
項番5.2で作成した「CMakeLists.txt」に以下の10、15~16行目を追加します。

cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
# OpenCVのバージョンを指定
set(OCV_VERSION "4.5")
project(src)
# OpenCVパッケージの設定を検索し読み込む
find_package(OpenCV ${OCV_VERSION} REQUIRED)
# ArUco marker
add_executable(arMarkerGenerator arMarkerGenerator.cpp)
add_executable(arMarkerRecognizer arMarkerRecognizer.cpp)

if(OpenCV_FOUND)
    target_include_directories(arMarkerGenerator PRIVATE ${OpenCV_INCLUDE_DIRS})
    target_link_libraries(arMarkerGenerator ${OpenCV_LIBS})
    target_include_directories(arMarkerRecognizer PRIVATE ${OpenCV_INCLUDE_DIRS})
    target_link_libraries(arMarkerRecognizer ${OpenCV_LIBS})
endif()

 
6.3. ArUcoマーカ検出プログラムのビルド・実行
以下のコマンドを実行し、ビルド・実行を行います。プログラムを実行すると「build」ディレクトリにArUcoマーカ検出結果の画像が生成されます。

cd build
cmake ..
make
./arMarkerRecognizer

 


図 2. 検出したArUcoマーカ

 
いかがだったでしょうか。C++でARマーカの生成・検出を行いたい方などのお役に立てれば幸いです。