cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

三次元画像計測システムofxActiveScanをopenFrameworks0.8.4(Windows MSVC2012)で動かしてみる(その3)

前回、カメラを変更することで形状が正しくとれるようになりましたが出力結果が点だけなので、PLY形式に吐き出しても他のアプリケーションでちょっと使いにくい状況でした。なので、メッシュを張っておきましょう。変更するのは、ofxActiveScan.cpp内のtriangulate関数です。

ofMesh triangulate(Options& options, Map2f& hmap, Map2f& vmap, Map2f& mmap,
				   slib::CMatrix<3,3,double>& matKcam, double camDist,
				   slib::CMatrix<3,3,double>& matKpro, double proDist,
				   slib::CMatrix<3,4,double>& proRt, ofImage& cp, Map2i& indices)
{
	ofMesh mesh;
	indices.Initialize(hmap.size());
	indices.Clear(-1);
	
	slib::CVector<2,double>
		cod1=make_vector<double>((options.projector_width+1)/2.0,options.projector_height*options.projector_horizontal_center),
		cod2=(make_vector(1.0,1.0)+mmap.size())/2;
	
	// extrinsic matrices of projector and camera
	slib::CMatrix<3,4,double> camRt;
	camRt = make_diagonal_matrix(1,1,1).AppendCols(make_vector(0,0,0));//CMatrix<3,4,double>::GetIdentity(); // reconstruction is in camera coordinate frame
	
	// compute projection matrices of projector and camera
	std::vector<slib::CMatrix<3,4,double> > matrices(2);
	matrices[0] = matKcam * camRt; // camera
	matrices[1] = matKpro * proRt; // projector
	
	// fundamental matrix
	CMatrix<3,3,double> matR;
	CVector<3,double> vecT;
	matR.Initialize(proRt.ptr());
	vecT.Initialize(proRt.ptr()+9);
	CMatrix<3,3,double> matF = transpose_of(inverse_of(matKpro)) * GetSkewSymmetric(vecT) * matR * inverse_of(matKcam);
	
	// triangulate 3d points
	std::vector<CVector<3,double> > result;
	for (int y=0; y<hmap.size(1); y++)
	{
		if (y % (hmap.size(1)/10) == 0)
			TRACE("triangulation: %d%% done\n", 100*y/hmap.size(1));
		
		int nbehind=0;
		for (int x=0; x<hmap.size(0); x++)
		{
			if (mmap.cell(x,y))
			{
				// 2D correspondence
				std::vector<CVector<2,double> > p2d(2);
				
				// camra coordinate
				slib::fmatrix::CancelRadialDistortion(camDist,cod2,make_vector<double>(x,y),p2d[0]);
				
				// projector coordinate
				double proj_y;
				
				proj_y = vmap.cell(x,y);
				
				//CVector<3,double> epiline = matF * GetHomogeneousVector(p2d[0]);
				//proj_y = -(epiline[0] * hmap.cell(x,y) + epiline[2]) / epiline[1];
				
				slib::fmatrix::CancelRadialDistortion(proDist,cod1,make_vector<double>(hmap.cell(x,y),proj_y),p2d[1]);
				
				// triangulate
				CVector<3,double> p3d;
				SolveStereo(p2d, matrices, p3d);
				
				// save
				//result.push_back(p3d);
				if (p3d[2]<0) {
					nbehind++;
				} else {
					indices.cell(x, y) = mesh.getNumVertices();
					mesh.addVertex(ofVec3f(p3d[0], p3d[1], p3d[2]));
					if( cp.bAllocated() ) {
						mesh.addColor(cp.getColor(x, y));
					}
				}
			}
		}
		if (nbehind)
			TRACE("found %d points behind viewpoint.\n", nbehind);
	}

	// mesh
	float scale_factor = 1.0;
	float dist_thresh = 0.02 * scale_factor;
	for (int y=0; y<hmap.size(1)-1; y++) {
		for (int x=0; x<hmap.size(0); x++) {
			if(indices.cell(x,y)>=0){
				ofVec3f p0 = mesh.getVertex(indices.cell(x,y));
				if(x!=hmap.size(0)){
					if((indices.cell(x+1,y)>=0) && (indices.cell(x,y+1)>=0)){
						ofVec3f p1 = mesh.getVertex(indices.cell(x+1,y));
						ofVec3f p2 = mesh.getVertex(indices.cell(x,y+1));
						float dist_threshold = 0.02;
						if((p0.distance(p1) < dist_threshold) && (p1.distance(p2) < dist_threshold) && (p2.distance(p0) < dist_threshold)) {
							mesh.addIndex(indices.cell(x,y));
							mesh.addIndex(indices.cell(x+1,y));
							mesh.addIndex(indices.cell(x,y+1));
						}
					}
				}
				if(x!=0){
					if((indices.cell(x,y+1)>=0) && (indices.cell(x-1,y+1)>=0)){
						ofVec3f p1 = mesh.getVertex(indices.cell(x,y+1));
						ofVec3f p2 = mesh.getVertex(indices.cell(x-1,y+1));
						float dist_threshold = 0.02;
						if((p0.distance(p1) < dist_threshold) && (p1.distance(p2) < dist_threshold) && (p2.distance(p0) < dist_threshold)) {
							mesh.addIndex(indices.cell(x,y));
							mesh.addIndex(indices.cell(x,y+1));
							mesh.addIndex(indices.cell(x-1,y+1));
						}
					}
				}
			}
		}
	}

	return mesh;
}

f:id:cvl-robot:20150306221459p:plain

白い部分が飛んでしまって計測に失敗していますが、メッシュはちゃんと張れていますね。
スケールをちゃんと合わせたいのですが、この計測法だとスケール合わせのためには一工夫必要なのが厄介ですね。メッシュのエッジの最大長とスケールをソースコード中に適当に書いてしまっているので、適宜工夫して調整してください。