天天看點

OpenCV4學習筆記(75)——ArUco子產品之實作AR(增強現實)效果

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

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

首先,我們需要建立并列印出四個aruco标記,這四個标記作為我們确定現實增強區域的基準,例如下面這幾張圖像:

OpenCV4學習筆記(75)——ArUco子產品之實作AR(增強現實)效果
OpenCV4學習筆記(75)——ArUco子產品之實作AR(增強現實)效果
OpenCV4學習筆記(75)——ArUco子產品之實作AR(增強現實)效果

可以看到這四個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);
           

得到的效果如下:

OpenCV4學習筆記(75)——ArUco子產品之實作AR(增強現實)效果

由于這裡的aruco标記是列印在一張紙上,是以看起來效果沒有特别的好,但是試想下如果将它們裁剪下來,并且貼在相框上或者是窗上,再對拍攝下的圖像進行增強現實操作,那是不是感覺就不一樣了(╹ڡ╹ )

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

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

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

繼續閱讀