OpenCV4學習筆記(75)——ArUco模塊之實現AR(增強現實)效果

今天要整理記錄的是利用OpenCV中ArUco模塊的aruco標記實現一個增強現實的小應用,當然了本次筆記的內容也是需要建立在之前的《OpenCV4學習筆記(72)》基礎上的。

所謂增強現實(Augmented Reality),其實是一種將虛擬信息與真實世界巧妙融合的技術,通過技術手段將計算機生成的文字、圖像、三維模型、音樂、視頻等虛擬信息模擬仿真後,應用到真實世界中,兩種信息互爲補充,從而實現對真實世界的“增強”。在這裏,我們主要利用aruco標記實現將圖像、視頻這些虛擬信息應用到拍攝下來的真實世界中。

首先,我們需要創建並打印出四個aruco標記,這四個標記作爲我們確定現實增強區域的基準,例如下面這幾張圖像:在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
可以看到這四個aruco標記包圍形成了一個大的四邊形區域,這個區域就是我們要進行操作的ROI區域了,當然了還可以把這四個aruco標記裁剪下來,然後貼在門上、窗上、相框中等等場景,這樣更有利於增強現實的體現。這裏我們就不做裁剪了,就在這張紙上進行實驗。下面將這張包含aruco標記的紙圖像表述爲場景圖像。

首先,我們需要對場景圖像進行aruco標記的檢測,那麼就需要先加載拍攝時所用相機的內參矩陣和畸變係數,這裏默認已經對相機標定好了,以後有機會再整理一下相機標定的內容。

	//加載圖像
	Mat inputImage = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\FourMarkerVideo.jpg");
	resize(inputImage, inputImage, Size(600, 800));
	Mat test_image = inputImage.clone();
	//加載相機內參和畸變係數
	cv::Mat cameraMatrix, distCoeffs;
	vector<double> camera = { 657.1548323619423, 0, 291.8582472145741,0, 647.384819351103, 391.254810476919,0, 0, 1 };
	cameraMatrix = Mat(camera);
	cameraMatrix = cameraMatrix.reshape(1, 3);
	vector<double> dist = { 0.1961793476399528, -1.38146317350581, -0.002301820186177369, -0.001054637905895881, 2.458286937422959 };
	distCoeffs = Mat(dist);
	distCoeffs = distCoeffs.reshape(1, 1);

然後對場景圖像中的aruco標記進行檢測

	//進行標記檢測
	auto dictionary = aruco::getPredefinedDictionary(DICT_6X6_250);
	vector<vector<Point2f>>corners, rejectedImaPoints;
	vector<int>ids;
	auto parameters = aruco::DetectorParameters::create();
	aruco::detectMarkers(test_image, dictionary, corners, ids, parameters, rejectedImaPoints, cameraMatrix, distCoeffs);
	//aruco::drawDetectedMarkers(test_image, corners, ids, Scalar(0, 255, 0));

接着我們要尋找所需的ROI區域,也就是四個aruco標記包圍而成的一個四邊形區域,那麼我們需要確定這個四邊形的四個頂點。我暫時考慮了兩個方法,一是對四個標記的所有角點中的x、y座標進行排序,找到正數和倒數的前兩個值,再進行配對,從而找到四個頂點,這個方法在對於場景圖像發生變化時、例如是場景視頻的情況下有比較好的效果。二是直接從檢測到的四個標記的ID值來索引標記,並獲取四邊形ROI區域中的對於角點,這個方法相對來說更簡單粗暴,但是適用性會比較差,尤其是場景圖像發生旋轉的情況下比較難達到好的效果。

這裏我使用的場景圖像是一張固定的圖像,也就是上面拍攝的場景圖像,所以這裏我使用第二個方法

	//提取四個標記形成的ROI區域
	vector<Point2f> roi_box_pt(4);
	//尋找方框的四個頂點,從檢測到標記的順序決定
	roi_box_pt[0] = corners[3][0];
	roi_box_pt[1] = corners[2][1];
	roi_box_pt[2] = corners[0][2];
	roi_box_pt[3] = corners[1][3];

接着我們需要讀取要替換ROI區域的目標圖像,並提取四個頂點

	//讀取替換圖像
	Mat new_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\pig.jpg");
	int width = new_image.cols;
	int height = new_image.rows;
	//提取替換圖像的四個頂點
	vector<Point2f> new_image_box(4);
	new_image_box[0] = Point(0, 0);
	new_image_box[1] = Point(width, 0);
	new_image_box[2] = Point(width, height);
	new_image_box[3] = Point(0, height);

然後將目標圖像從原視平面到場景圖像的視平面做透視變換

	//計算從替換圖像到目標ROI圖像的3x3單應性矩陣
	Mat H = findHomography(new_image_box, roi_box_pt);
	Mat roi_new_image;
	//進行透視變換
	warpPerspective(new_image, roi_new_image, H, test_image.size(), INTER_CUBIC);

然後爲了將場景圖像中的ROI區域挖空,我們需要設置一個掩膜,然後和場景圖像進行按位與操作,最後將場景圖像和目標圖像通過加權相加融合,實現對場景圖像的增強操作

	//製作掩膜
	Mat mask = Mat(test_image.size(), CV_8UC3,Scalar(255,255,255));
	for (int i = 0; i < roi_new_image.rows; i++)
	{
		for (int j = 0; j < roi_new_image.cols; j++)
		{
			if (roi_new_image.at<Vec3b>(i, j) != Vec3b(0,0,0))
			{
				mask.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
			}
		}
	}
	Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));
	dilate(mask, mask, kernel);
	//用透視變換後的替換圖像,替換原圖像中的ROI區域
	Mat result;
	bitwise_and(test_image, mask, test_image);
	addWeighted(test_image, 1, roi_new_image, 0.7, 1.0, result);
	namedWindow("result", WINDOW_FREERATIO);
	imshow("result", result);

得到的效果如下:
在這裏插入圖片描述
由於這裏的aruco標記是打印在一張紙上,所以看起來效果沒有特別的好,但是試想下如果將它們裁剪下來,並且貼在相框上或者是窗上,再對拍攝下的圖像進行增強現實操作,那是不是感覺就不一樣了(╹ڡ╹ )

而且,假如我們使用的場景圖像是實時視頻流中的每一幀圖像,那麼還可以實現實時拍攝的增強現實效果,這樣的話能得到更好的AR體驗,當然了這樣的話對電腦的要求就會比較高了。。。我也嘗試過一下在實時視頻流中進行處理,但是卡幀勸退了我。。。

今天嘗試着將虛擬圖像信息應用到了真實的場景圖像中,實現一個比較有趣的AR效果,下次筆記再來嘗試一下將視頻信息應用到真實場景當中去,那本次筆記到此結束啦。

PS:本人的註釋比較雜,既有自己的心得體會也有網上查閱資料時摘抄下的知識內容,所以如有雷同,純屬我向前輩學習的致敬,如果有前輩覺得我的筆記內容侵犯了您的知識產權,請和我聯繫,我會將涉及到的博文內容刪除,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章