1 /****************************************************************************
2 * MeshLab                                                           o o     *
3 * A versatile mesh processing toolbox                             o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2005                                                \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 
24 #include <cfloat>
25 #include <iostream>
26 #include <QtGui>
27 #include <QImage>
28 #include <QMap>
29 #include <QColor>
30 
31 #include <QtXml/QDomDocument>
32 #include <QtXml/QDomElement>
33 #include <QtXml/QDomNode>
34 
35 #include <src/PhotoTexturer.h>
36 #include <src/UVFaceTexture.h>
37 #include <src/CameraCalibration.h>
38 #include <src/TextureFilter.h>
39 #include <src/TextureMerger.h>
40 #include <src/Tsai/TsaiCameraCalibration.h>
41 
42 #include<vcg/complex/allocate.h>
43 #include <vcg/math/matrix44.h>
44 #include <src/QuadTree/QuadTreeNode.h>
45 
46 #include "photo_texture_tools.h"
47 
48 #include <src/WinnerTakesAllTextureMerger.h>
49 #include <src/SmartBlendTextureMerger.h>
50 
51 
52 #include <vcg/complex/algorithms/update/position.h>
53 #include <vcg/complex/algorithms/update/bounding.h>
54 
55 
56 
57 const QString PhotoTexturer::XML_PHOTOTEXTURING = "photoTexturing";
58 
59 //const std::string PhotoTexturer::ORIGINALUVTEXTURECOORDS = "OriginalUVTextureCoords";
60 const std::string PhotoTexturer::UVTEXTURECOORDS = "UVTextureCoords";
61 
62 const QString PhotoTexturer::TEXTURE_SIZE_WIDTH = "pt_texture_width";
63 const QString PhotoTexturer::TEXTURE_SIZE_HEIGHT = "pt_texture_height";
64 
65 const QString PhotoTexturer::UNPROJECT_ENABLE_ANGLE = "pt_enable_angle";
66 const QString PhotoTexturer::UNPROJECT_ANGLE = "pt_angle";
67 const QString PhotoTexturer::UNPROJECT_ANGLE_WEIGHT = "pt_angle_weight";
68 const QString PhotoTexturer::UNPROJECT_ANGLE_SHARPNESS = "pt_angle_sharpness";
69 
70 const QString PhotoTexturer::UNPROJECT_ENABLE_DISTANCE = "pt_enable_distance";
71 const QString PhotoTexturer::UNPROJECT_DISTANCE_WEIGHT = "pt_distance_weight";
72 const QString PhotoTexturer::UNPROJECT_DISTANCE_SHARPNESS = "pt_distance_shjarpness";
73 
74 const QString PhotoTexturer::UNPROJECT_ENABLE_EDGE_STRETCHING = "pt_enable_edge_stretching";
75 const QString PhotoTexturer::UNPROJECT_EDGE_STRETCHING_PASS = "pt_edge_stretching_pass";
76 
77 const QString PhotoTexturer::UNPROJECT_TEXTURE_FILENAME = "pt_unproject_texture_name";
78 
79 
80 const QString PhotoTexturer::BAKE_SAVE_UNPROJECT = "pt_save_unproject";
81 
82 const QString PhotoTexturer::BAKE_MERGE_TEXTURES = "pt_merge_textures";
83 const QString PhotoTexturer::BAKE_MERGE_TYPE = "pt_merge_type";
84 const QString PhotoTexturer::BAKE_MERGED_TEXTURE = "pt_merged_texture_file";
85 const QString PhotoTexturer::BAKE_SMARTBLEND = "pt_smartblend_command";
86 
87 #define ZB_EPSILON 1e-2
88 
89 
PhotoTexturer()90 PhotoTexturer::PhotoTexturer(){
91 	origTextureID = -1;
92 	nextTextId = 0;
93 	bakeCounter = 0;
94 	combineCounter = 0;
95 }
~PhotoTexturer()96 PhotoTexturer::~PhotoTexturer(){
97 
98 }
99 
loadConfigurationFile(QString cfgFile)100 void PhotoTexturer::loadConfigurationFile(QString cfgFile){
101 
102 	QDomDocument doc;
103 	cameras.clear();
104 	QFile file(cfgFile);
105 	QString errorMessage;
106 	if (file.open(QIODevice::ReadOnly) && doc.setContent(&file, &errorMessage)){
107 		file.close();
108 		QDomElement root = doc.documentElement();
109 		if (root.nodeName() == XML_PHOTOTEXTURING){
110 			for(QDomElement element = root.firstChildElement(Camera::XML_CAMERA); !element.isNull(); element = element.nextSiblingElement(Camera::XML_CAMERA)){
111 				Camera* cam = new Camera();
112 				cam->loadFromXml(&element);
113 				cameras.push_back(cam);
114 			}
115 		}
116 	}
117 }
118 
generateTextureId()119 int PhotoTexturer::generateTextureId(){
120 	return ++nextTextId;
121 }
122 
saveConfigurationFile(QString cfgFile)123 void PhotoTexturer::saveConfigurationFile(QString cfgFile){
124 	QDomDocument doc(XML_PHOTOTEXTURING);
125 	QDomElement root = doc.createElement(XML_PHOTOTEXTURING);
126 	doc.appendChild(root);
127 
128 	int i;
129 	for (i=0;i<cameras.size();i++){
130 
131 		Camera *cam = cameras.at(i);
132 		cam->saveAsXml(&doc,&root);
133 	}
134 
135 
136 	QFile file(cfgFile);
137 	file.open(QIODevice::WriteOnly);
138 	QTextStream qstream(&file);
139 	doc.save(qstream,1);
140 	file.close();
141 }
142 
addCamera(QString camFile)143 void PhotoTexturer::addCamera(QString camFile){
144 	QDomDocument doc;
145 	QFile file(camFile);
146 	QString errorMessage;
147 
148 	if (file.open(QIODevice::ReadOnly) && doc.setContent(&file, &errorMessage)){
149 		file.close();
150 		QDomElement root = doc.documentElement();
151 		qDebug() << root.nodeName() ;
152 		if (root.nodeName() == Camera::XML_CAMERADOCUMENT){
153 
154 			QDomElement xml_cam = root.firstChildElement(Camera::XML_CAMERA);
155 			if (!xml_cam.isNull()){
156 						Camera* cam = new Camera();
157 						cam->loadFromXml(&xml_cam);
158 						cameras.push_back(cam);
159 			}
160 		}else{
161 			qDebug("root is not camera \n");
162 		}
163 	}else{
164 		qDebug()<< "errorMessage: " << errorMessage;
165 	}
166 }
167 
removeCamera(int i)168 void PhotoTexturer::removeCamera(int i){
169 	//checks if i is a valid index of the cameras list
170 	//and deletes the camera on position i
171 	if (i>=0 && i < cameras.size()){
172 		cameras.removeAt(i);
173 	}
174 }
175 
storeOriginalTextureCoordinates(MeshModel * m)176 void PhotoTexturer::storeOriginalTextureCoordinates(MeshModel *m){
177 	qDebug()<<"storeOriginalTextureCoordinates";
178 	// see http://vcg.sourceforge.net/index.php/Tutorial#User-defined_attributes
179 	//if (m->cm.HasPerWedgeTexCoord()){	//Problem HasPerWedgeTexCoord() returns true even if MeshModel
180 	//has no texture information
181 
182 	//checks if the MeshModel has texture coordinates
183 	if(m->hasDataMask(MeshModel::MM_WEDGTEXCOORD) ){
184 		//qDebug()<<"HasPerWedgeTexCoord";
185 		CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> >ih;
186 		if (!vcg::tri::HasPerFaceAttribute(m->cm,UVTEXTURECOORDS)){
187 			//qDebug()<<"has no PhotoTexturingUVCoords";
188 			ih = vcg::tri::Allocator<CMeshO>::AddPerFaceAttribute<QMap<int,UVFaceTexture*> >(m->cm,UVTEXTURECOORDS);
189 		}else{
190 			ih = vcg::tri::Allocator<CMeshO>::AddPerFaceAttribute<QMap<int,UVFaceTexture*> >(m->cm,UVTEXTURECOORDS);
191 		}
192 		//checks if the original texture coordinates has been saved before
193 
194 		if (origTextureID == -1){
195 			//qDebug()<<"has no OriginalTextureCoords";
196 			origTextureID = generateTextureId();
197 			//CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> >ih = vcg::tri::Allocator<CMeshO>::AddPerFaceAttribute<QMap<int,UVFaceTexture*> >(m->cm,UVTEXTURECOORDS);
198 
199 			//saves the texture information for each face as perFaceAttribute
200 			CMeshO::FaceIterator fi; int i = 0;
201 			for(fi   = m->cm.face.begin(); fi != m->cm.face.end(); ++fi,i++){
202 				UVFaceTexture* uvft = new UVFaceTexture();
203 				uvft->u[0] = (*fi).WT(0).u();
204 				uvft->v[0] = (*fi).WT(0).v();
205 
206 				uvft->u[1] = (*fi).WT(1).u();
207 				uvft->v[1] = (*fi).WT(1).v();
208 
209 				uvft->u[2] = (*fi).WT(2).u();
210 				uvft->v[2] = (*fi).WT(2).v();
211 
212 				uvft->textureindex = (*fi).WT(0).n();
213 				uvft->faceIndex = i;
214 
215 				ih[i][origTextureID]  = uvft;   // [] operator takes a iterator
216 			}
217 			textureList[origTextureID]="original";
218 		}else{
219 			//qDebug()<<"has OriginalTextureCoords";
220 		}
221 	}else{
222 		//qDebug()<<"!HasPerWedgeTexCoord";
223 	}
224 
225 }
226 
restoreOriginalTextureCoordinates(MeshModel * m)227 void PhotoTexturer::restoreOriginalTextureCoordinates(MeshModel *m){
228 	//qDebug() << "restoreOriginalTextureCoordinates";
229 	// see http://vcg.sourceforge.net/index.php/Tutorial#User-defined_attributes
230 
231 	//checks if the original texture informationof the MeshModel were stored
232 	if (origTextureID!= -1 && vcg::tri::HasPerFaceAttribute(m->cm,UVTEXTURECOORDS)){
233 		applyTextureToMesh(m,origTextureID);
234 
235 	}else{
236 		//qDebug()<<"has no OriginalTextureCoords";
237 	}
238 }
239 
240 
241 
calculateMeshTextureForAllCameras(MeshModel * m,bool calcZBuffer)242 void PhotoTexturer::calculateMeshTextureForAllCameras(MeshModel *m, bool calcZBuffer){
243 	//checks if the MeshModel already has the perfaceAttribute PhotoTexturer::CAMERAUVTEXTURECOORDS
244 	//if not it creates one
245 
246 
247 	//enables texture information for the MeshModel
248 	//m->updateDataMask(MeshModel::MM_WEDGTEXCOORD);
249 	//makes sure that the mesh model mask enabels texture coordinates (needed to save the uv coorinates later)
250 	//m->ioMask |= MeshModel::IOM_WEDGTEXCOORD;
251 
252 
253 	//checks if special transformation data is stored asMeshData
254 
255 
256 
257 	//calculates the texture information (uv coordinates and texture index) for each camera
258 	int i;
259 	for (i=0;i<cameras.size();i++){
260 		Camera *cam = cameras.at(i);
261 		calculateMeshTextureForCamera(m,cam, calcZBuffer);
262 	}
263 }
264 
calculateMeshTextureForCamera(MeshModel * m,Camera * cam,bool calcZBuffer)265 void PhotoTexturer::calculateMeshTextureForCamera(MeshModel *m, Camera* cam,bool calcZBuffer){
266 	bool found = false;
267 	unsigned int size = static_cast<unsigned int>(m->cm.textures.size());
268 	unsigned j = 0;
269 	int tindx;
270 
271 	//gets the perFaceAttributeHandler for the perFaceAttribute PhotoTexturer::CAMERAUVTEXTURECOORDS
272 	CMeshO::PerFaceAttributeHandle<QMap<int ,UVFaceTexture*> > ih;
273 
274 	if (!vcg::tri::HasPerFaceAttribute(m->cm,UVTEXTURECOORDS)){
275 		//qDebug()<<"has no PhotoTexturingUVCoords";
276 		ih = vcg::tri::Allocator<CMeshO>::AddPerFaceAttribute<QMap<int,UVFaceTexture*> > (m->cm,UVTEXTURECOORDS);
277 	}else{
278 		ih = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> > (m->cm,UVTEXTURECOORDS);
279 	}
280 
281 	vcg::Matrix44f matrixTr = m->cm.Tr;
282 	vcg::Matrix44f matrix;
283 	vcg::Matrix44f matrixInv;
284 	if(vcg::tri::HasPerMeshAttribute(m->cm, PhotoTextureTools::TransformForPhoto)){
285 		CMeshO::PerMeshAttributeHandle<vcg::Matrix44f> transformHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<vcg::Matrix44f> (m->cm, PhotoTextureTools::TransformForPhoto);
286 		matrix = transformHandle();
287 		matrixInv =vcg::Inverse(matrix);
288 		m->cm.Tr = matrix;
289 		vcg::tri::UpdatePosition<CMeshO>::Matrix(m->cm, m->cm.Tr,true);
290 		//vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m->cm);
291 		vcg::tri::UpdateBounding<CMeshO>::Box(m->cm);
292 
293 		qDebug()<< "transformHandle";
294 	}/*else{
295 		qDebug()<<"Identity";
296 		matrix = vcg::Matrix44f();
297 		matrix.SetIdentity();
298 	}
299 
300 
301 	m->cm.Tr = matrix;
302 	*/
303 	//stdout << "matrix" << matrix;
304 	qDebug() << "matrix2: " << matrix[0][0]<< matrix[0][1]<< matrix[0][2]<< matrix[0][3]<< matrix[1][0]<< matrix[1][1]<< matrix[1][2]<< matrix[1][3]<< matrix[2][0]<< matrix[2][1]<< matrix[2][2]<< matrix[2][3]<< matrix[3][0]<< matrix[3][1]<< matrix[3][2]<< matrix[3][3];
305 
306 	//loads the texture image and gets its dimensions
307 	QImage *img = new QImage(cam->textureImage);
308 	int imgw = img->width();
309 	int imgh = img->height();
310 
311 	//looks if the texture image is allready loaded and stores the index of the texture
312 	//under tindx
313 	while (!found && (j < size))
314 	{
315 		if (cam->textureImage.toStdString().compare(m->cm.textures[j])==0)
316 		{
317 			tindx = (int)j;
318 			found = true;
319 		}
320 		++j;
321 	}
322 
323 	if (!found)
324 	{
325 		m->cm.textures.push_back(cam->textureImage.toStdString());
326 		tindx = (int)size;
327 	}
328 
329 
330 	//cam->calibration->calibrateToTsai(m);
331 	int textureId = generateTextureId();
332 	cam->textureId = textureId;
333 	QList<QuadTreeLeaf*> buildQuadTree;
334 	//calculates the uv coordinates for each face and saves them as UVFaceTexture as
335 	//perFaceAttribute of the MeshModel
336 	CMeshO::FaceIterator fi;
337 	int count = 0;
338 	for(fi=m->cm.face.begin(); fi!=m->cm.face.end(); ++fi, count++) {
339 		int i;
340 		UVFaceTexture *ft = new UVFaceTexture();
341 		ft->type = 0;
342 		//calculating angle between the camera direction and the face normal
343 		vcg::Matrix33f rMatrix = vcg::Matrix33f(matrix,3);
344 		//vcg::Point3f tmpN = rMatrix*(*fi).N();
345 		vcg::Point3f tmpN = (*fi).N();
346 		tmpN.Normalize();
347 		double angle = ((-1*cam->calibration->cameraDirection[0])*tmpN[0])
348 						+((-1*cam->calibration->cameraDirection[1])*tmpN[1])
349 						+((-1*cam->calibration->cameraDirection[2])*tmpN[2]);
350 		angle = acos(angle);
351 		angle = (angle/M_PI)*180.0;
352 
353 		//qDebug()<< "angle: " << angle;
354 		ft->faceAngleToCamera = angle;
355 
356 		for (i=0;i<3;i++){
357 
358 			double u,v;
359 			//vcg::Point3f tmpVector = matrix*(*fi).V(i)->cP();
360 			vcg::Point3f tmpVector = (*fi).V(i)->cP();
361 			cam->calibration->getUVforPoint(tmpVector[0],tmpVector[1],tmpVector[2],&u,&v);
362 
363 			ft->u[i] = u/cam->resolution[0];
364 			ft->v[i] = 1.0-v/cam->resolution[1];
365 
366 		}
367 		ft->textureindex =tindx;
368 		ft->faceIndex = count;
369 
370 		ih[ft->faceIndex][textureId] = ft;
371 		buildQuadTree.push_back(ft);
372 
373 	}
374 
375 	if (cam->zBuffer!= NULL){
376 		delete cam->zBuffer;
377 		cam->zBuffer = NULL;
378 	}
379 	if(calcZBuffer){
380 		QuadTreeNode zBufferTree = QuadTreeNode(0.0,0.0,1.0,1.0);
381 		zBufferTree.buildQuadTree(&buildQuadTree,1.0/imgw,1.0/imgh);
382 		cam->zBuffer = new TextureFilterZB(imgw,imgh,1);
383 		calculateZBuffer(m,cam,&zBufferTree,cam->zBuffer);
384 		cam->zBuffer->normalize();
385 	}
386 	//save Z-Buffer as image
387 	//cam->zBuffer->SaveAsImage("zbuffer_",cam->name);
388 	cam->calculatedTextures = true;
389 	textureList[textureId]= cam->name;
390 
391 
392 	if(vcg::tri::HasPerMeshAttribute(m->cm, PhotoTextureTools::TransformForPhoto)){
393 			m->cm.Tr = matrixInv;
394 			vcg::tri::UpdatePosition<CMeshO>::Matrix(m->cm, m->cm.Tr);
395 			//vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m->cm);
396 			vcg::tri::UpdateBounding<CMeshO>::Box(m->cm);
397 			m->cm.Tr = matrixTr;
398 			qDebug()<< "transformHandle";
399 	}
400 }
401 
applyTextureToMesh(MeshModel * m,int textureIdx,bool use_different_tidx,int tidx)402 void PhotoTexturer::applyTextureToMesh(MeshModel *m,int textureIdx, bool use_different_tidx, int tidx){
403 
404 	if(!m->hasDataMask(MeshModel::MM_WEDGTEXCOORD)){
405 		m->updateDataMask(MeshModel::MM_WEDGTEXCOORD);
406 	}
407 	QMap<int, QString>::const_iterator i = textureList.find(textureIdx);
408 	 if (i != textureList.end()){
409 
410 		if (vcg::tri::HasPerFaceAttribute(m->cm,UVTEXTURECOORDS)){
411 
412 			CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> > ih = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> > (m->cm,UVTEXTURECOORDS);
413 			CMeshO::FaceIterator fi;
414 			int k =0;
415 			for(fi=m->cm.face.begin(); fi!=m->cm.face.end(); ++fi) {
416 				int i;
417 				UVFaceTexture* ft = ih[fi][textureIdx];
418 				if(ft!=NULL){
419 					for (i=0;i<3;i++){
420 						(*fi).WT(i).u() = ft->u[i];
421 						(*fi).WT(i).v() = ft->v[i];
422 						if (use_different_tidx && tidx >-1){
423 							(*fi).WT(i).n() = tidx;
424 						}else{
425 							(*fi).WT(i).n() = ft->textureindex;
426 						}
427 					}
428 				}
429 				k++;
430 			}
431 			//m->cm
432 		}
433 	}
434 }
435 
436 
unprojectToOriginalTextureMap(MeshModel * m,Camera * camera,QuadTreeNode & qtree,ImageFilterContainer * container,bool use_distance_filter,int distance_weight,bool use_angle_filter,int angle_weight,int angle_map_sharpness,double min_angle,int imgResX,int imgResY)437 void PhotoTexturer::unprojectToOriginalTextureMap(MeshModel *m, Camera* camera, QuadTreeNode &qtree, ImageFilterContainer *container ,bool use_distance_filter, int distance_weight, bool use_angle_filter, int angle_weight , int angle_map_sharpness, double min_angle, int imgResX, int imgResY){
438 	qDebug() <<"unprojectToOriginalTextureMap"<< min_angle;
439 
440 	//checks if the MeshModel has original uv coordinates and camera projected uv coordinates.
441 	if (origTextureID != -1 && vcg::tri::HasPerFaceAttribute(m->cm,UVTEXTURECOORDS)){
442 
443 		//CMeshO::PerFaceAttributeHandle<UVFaceTexture*> oth = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<UVFaceTexture*>(m->cm,ORIGINALUVTEXTURECOORDS);
444 		CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> > cth = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> > (m->cm,UVTEXTURECOORDS);
445 
446 
447 
448 		vcg::Matrix44f matrixTr = m->cm.Tr;
449 		vcg::Matrix44f matrix;
450 		vcg::Matrix44f matrixInv;
451 		if(vcg::tri::HasPerMeshAttribute(m->cm, PhotoTextureTools::TransformForPhoto)){
452 			CMeshO::PerMeshAttributeHandle<vcg::Matrix44f> transformHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<vcg::Matrix44f> (m->cm, PhotoTextureTools::TransformForPhoto);
453 			matrix = transformHandle();
454 			matrixInv =vcg::Inverse(matrix);
455 			m->cm.Tr = matrix;
456 			vcg::tri::UpdatePosition<CMeshO>::Matrix(m->cm, m->cm.Tr,true);
457 			//vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m->cm);
458 			vcg::tri::UpdateBounding<CMeshO>::Box(m->cm);
459 
460 			qDebug()<< "transformHandle";
461 		}
462 
463 		QString camname = camera->name;
464 
465 		//creates a new RGBA image for saving the new texture
466 		//QImage image(res_x, res_y, QImage::Format_ARGB32);
467 
468 		container->image = new QImage(imgResX,imgResY,QImage::Format_ARGB32);
469 		TextureFilterSTD *distance_filter = NULL;
470 		TextureFilterSTD *angle_filter = NULL;
471 
472 		if(use_angle_filter){
473 			angle_filter = new TextureFilterSTD(imgResX,imgResY,angle_weight);
474 		}
475 		if (use_distance_filter){
476 			distance_filter = new TextureFilterSTD(imgResX,imgResY,distance_weight);
477 		}
478 
479 		//loading the texture corresponding to the camera
480 		QImage tmp_texture(camera->textureImage);
481 		QRgb* utimg = (QRgb*)tmp_texture.bits();
482 		int twidth = tmp_texture.width();
483 		int theight = tmp_texture.height();
484 
485 		QColor cpixel;
486 
487 		int x;
488 		int y;
489 		//CMeshO::FaceIterator fi;
490 		bool found = false;
491 
492 
493 		//goes pixelwise over the whole new texture image and looks if it lies inside
494 		//a texture face of the original texture coordinates. If the pixel lies inside
495 		//a textured face it looks in the corresponding camera texture for the color value
496 		//of this pixel and stores it at the current pixel position in the new texture image.
497 
498 		QRgb* ucimg = (QRgb*)container->image->bits();
499 
500 		for (y=0;y<imgResY;y++){
501 			for (x=0;x<imgResX;x++){
502 
503 				//sets the current pixel to black with an alpha value of 0
504 				cpixel = QColor(0, 0, 0, 0);
505 				//container->image->setPixel(x,imgResY-(y+1), cpixel.rgba());
506 				ucimg[(imgResY-(y+1))*imgResX+x] =  cpixel.rgba();
507 				found = false;
508 				//searches the QuadTree for matching faces
509 				QList<QuadTreeLeaf*> list;
510 				qtree.getLeafs(((double)x/(double)(imgResX-1)),((double)y/(double)(imgResY-1)),list);
511 				int ns = list.size();
512 
513 				if (ns>0){
514 					int idx = 0;
515 					while(!found && idx <ns){
516 						UVFaceTexture* tmp;
517 						tmp = dynamic_cast<UVFaceTexture*>(list.at(idx));
518 
519 						double u,v;
520 						double a,b,c,d;
521 
522 						UVFaceTexture* ct = cth[tmp->faceIndex][camera->textureId];
523 						tmp->getBarycentricCoordsForUV(((double)x/(double)(imgResX-1)),((double)y/(double)(imgResY-1)),a,b,c,d);
524 
525 						ct->getUVatBarycentricCoords(u,v,a,b,c);
526 						int ix = (int)(((double)twidth-1)*u);
527 						int iy = theight-(int)((((double)theight-1)*v)+1);
528 
529 						if(ix>=0 && ix<twidth && iy>=0 && iy<theight){
530 
531 
532 							//calculating alpha value of the pixel by using the angle
533 
534 							CFaceO f;
535 							f = m->cm.face.at(tmp->faceIndex);
536 
537 							vcg::Point3f p;
538 							p =  f.V(0)->cP()*a+ f.V(1)->cP()*b+f.V(2)->cP()*c;
539 							double distance = sqrt(pow(p[0]-camera->calibration->cameraPosition[0],2)+pow(p[1]-camera->calibration->cameraPosition[1],2)+pow(p[2]-camera->calibration->cameraPosition[2],2));
540 
541 							if((camera->zBuffer!= 0 && (camera->zBuffer->normalizeValue(distance)-ZB_EPSILON)<=camera->zBuffer->getValue(ix,tmp_texture.height()-(iy+1)))|| (camera->zBuffer== 0 )){
542 
543 								found = true;
544 
545 								//cpixel = QColor(tmp_texture.pixel(ix,iy));
546 								cpixel = QColor(utimg[iy*twidth+ix]);
547 								cpixel.setAlpha(255);
548 								//container->image->setPixel(x,imgResY-(y+1), cpixel.rgba());
549 								ucimg[(imgResY-(y+1))*imgResX+x] = cpixel.rgba();
550 
551 								double angle = 0.0;
552 								if(use_angle_filter){
553 									//calculate normal vector for pixel
554 									double n1, n2,n3;
555 									n1 = a*f.V(0)->N()[0]+ b*f.V(1)->N()[0]+c*f.V(2)->N()[0];
556 									n2 = a*f.V(0)->N()[1]+ b*f.V(1)->N()[1]+c*f.V(2)->N()[1];
557 									n3 = a*f.V(0)->N()[2]+ b*f.V(1)->N()[2]+c*f.V(2)->N()[2];
558 
559 									angle = ((-1*camera->calibration->cameraDirection[0])*n1)
560 													+((-1*camera->calibration->cameraDirection[1])*n2)
561 													+((-1*camera->calibration->cameraDirection[2])*n3);
562 
563 									//qDebug() << "angle["<<ix<<"]["<<iy<<"]: " <<angle;
564 
565 
566 									angle = acos(angle);
567 									angle = (angle/M_PI)*180.0;
568 
569 									if(angle<= min_angle){
570 										double wangle = (angle/180.0)*M_PI;
571 										wangle = sin(wangle);
572 										wangle = pow(wangle,angle_map_sharpness);
573 
574 										angle_filter->setValue(x,imgResY-(y+1),wangle);
575 									}
576 								}
577 
578 								if(use_distance_filter){
579 									//calculate distance for pixel
580 									distance_filter->setValue(x,imgResY-(y+1),distance);
581 								}
582 
583 
584 								if (angle<= min_angle){
585 									//cpixel = QColor(tmp_texture.pixel(ix,iy));
586 									cpixel = QColor(utimg[iy*twidth+ix]);
587 									//int rgb = (int)((angle/90.0*255.0));
588 									//cpixel = QColor(rgb,rgb,rgb);
589 									cpixel.setAlpha((int)((angle/90.0*255.0)));
590 									//cpixel.setAlpha(255);
591 
592 								}else{
593 									cpixel = QColor(0,0,0,0);
594 
595 								}
596 								//container->image->setPixel(x,imgResY-(y+1), cpixel.rgba());
597 								ucimg[(imgResY-(y+1))*imgResX+x] = cpixel.rgba();
598 							}
599 						}else{
600 
601 
602 						}
603 						//}
604 						idx++;
605 					}if(!found){
606 						//qDebug() << "not found ";
607 					}
608 
609 				}
610 			}
611 		}
612 		if(use_angle_filter){
613 			container->addFilter(angle_filter);
614 		}
615 		if(use_distance_filter){
616 			container->addFilter(distance_filter);
617 		}
618 
619 
620 		if(vcg::tri::HasPerMeshAttribute(m->cm, PhotoTextureTools::TransformForPhoto)){
621 				m->cm.Tr = matrixInv;
622 				vcg::tri::UpdatePosition<CMeshO>::Matrix(m->cm, m->cm.Tr);
623 				//vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m->cm);
624 				vcg::tri::UpdateBounding<CMeshO>::Box(m->cm);
625 				m->cm.Tr = matrixTr;
626 				qDebug()<< "transformHandle";
627 		}
628 	}
629 }
getSurrundingMeanColor(QRgb * uimg,int iwidth,int iheight,int x,int y,QColor & surcolor)630 void PhotoTexturer::getSurrundingMeanColor(QRgb* uimg, int iwidth, int iheight, int x, int y, QColor &surcolor){
631 	//qDebug()<<"getSurrundingMeanColor: "<<x<<y;
632 
633 	if((x>=0) && (x< iwidth) && (y>=0) && (y< iheight)){
634 		QColor c[8];
635 		c[0] = QColor(0,0,0,0);
636 		c[1] = QColor(0,0,0,0);
637 		c[2] = QColor(0,0,0,0);
638 		c[3] = QColor(0,0,0,0);
639 		c[4] = QColor(0,0,0,0);
640 		c[5] = QColor(0,0,0,0);
641 		c[6] = QColor(0,0,0,0);
642 		c[7] = QColor(0,0,0,0);
643 		if((x-1>=0) && (x-1< iwidth) && (y-1>=0) && (y-1< iheight)){
644 			//c[0]=QColor::fromRgba(image.pixel(x-1,y-1));
645 			c[0]=QColor::fromRgba(uimg[(y-1)*iwidth+(x-1)]);
646 		}
647 
648 		if((x>=0) && (x< iwidth) && (y-1>=0) && (y-1< iheight)){
649 			//c[1]=QColor::fromRgba(image.pixel(x,y-1));
650 			c[1]=QColor::fromRgba(uimg[(y-1)*iwidth+(x)]);
651 		}
652 		if((x+1>=0) && (x+1< iwidth) && (y-1>=0) && (y-1< iheight)){
653 			//c[2]=QColor::fromRgba(image.pixel(x+1,y-1));
654 			c[2]=QColor::fromRgba(uimg[(y-1)*iwidth+(x+1)]);
655 		}
656 		if((x+1>=0) && (x+1< iwidth) && (y>=0) && (y< iheight)){
657 			//c[3]=QColor::fromRgba(image.pixel(x+1,y));
658 			c[3]=QColor::fromRgba(uimg[(y)*iwidth+(x+1)]);
659 		}
660 		if((x+1>=0) && (x+1< iwidth) && (y+1>=0) && (y+1< iheight)){
661 			//c[4]=QColor::fromRgba(image.pixel(x+1,y+1));
662 			c[4]=QColor::fromRgba(uimg[(y+1)*iwidth+(x+1)]);
663 		}
664 		if((x>=0) && (x< iwidth) && (y+1>=0) && (y+1< iheight)){
665 			//c[5]=QColor::fromRgba(image.pixel(x,y+1));
666 			c[5]=QColor::fromRgba(uimg[(y+1)*iwidth+(x)]);
667 		}
668 		if((x-1>=0) && (x-1< iwidth) && (y+1>=0) && (y+1< iheight)){
669 			//c[6]=QColor::fromRgba(image.pixel(x-1,y+1));
670 			c[6]=QColor::fromRgba(uimg[(y+1)*iwidth+(x-1)]);
671 		}
672 		if((x-1>=0) && (x-1< iwidth) && (y>=0) && (y< iheight)){
673 			//c[7]=QColor::fromRgba(image.pixel(x-1,y));
674 			c[7]=QColor::fromRgba(uimg[(y)*iwidth+(x-1)]);
675 		}
676 		int i;
677 		int r=0;
678 		int g=0;
679 		int b=0;
680 		int a=0;
681 		int count=0;
682 		for(i=0;i<8;i++){
683 			if(c[i].alpha()>0){
684 				r+=c[i].red();
685 				g+=c[i].green();
686 				b+=c[i].blue();
687 				a+= c[i].alpha();
688 				count++;
689 			}
690 		}
691 		if(count>0){
692 			surcolor.setRed(r/count);
693 			surcolor.setGreen(g/count);
694 			surcolor.setBlue(b/count);
695 			surcolor.setAlpha(a/count);
696 			surcolor.setAlpha(255);
697 		}else{
698 			surcolor.setRed(0);
699 			surcolor.setGreen(0);
700 			surcolor.setBlue(0);
701 			surcolor.setAlpha(0);
702 		}
703 
704 	}
705 
706 
707 }
708 
709 
edgeTextureStretching(QImage * image,int pass)710 void PhotoTexturer::edgeTextureStretching(QImage *image, int pass){
711 	QRgb* uimg = (QRgb*) image->bits();
712 	int width = image->width();
713 	int height = image->height();
714 	if(pass>0){
715 		int count = 0;
716 		while(pass>0){
717 			//qDebug()<< "edgeTextureStretching pass:" <<++count;
718 			QImage tmp_image = image->copy(0,0,width,height);
719 			QRgb* utimg = (QRgb*) tmp_image.bits();
720 			int x;
721 			int y;
722 			for(y=0;y<height;y++){
723 				for(x=0;x<width;x++){
724 					//QColor test = QColor::fromRgba(image->pixel(x,y));
725 					QColor test = QColor::fromRgba(uimg[y*width+x]);
726 					if(test.alpha()==0){
727 						//qDebug()<< "alpha == 0";
728 						QColor surcolor;
729 						getSurrundingMeanColor(utimg,width,height,x,y,surcolor);
730 						//image->setPixel(x,y,surcolor.rgba());
731 						uimg[y*width+x] = surcolor.rgba();
732 					}
733 				}
734 			}
735 
736 
737 			pass--;
738 		}
739 	}
740 }
741 
742 
unprojectTextures(MeshModel * m,int textureID,FilterParameterSet * paraSet)743 int PhotoTexturer::unprojectTextures(MeshModel *m, int textureID, FilterParameterSet *paraSet){
744 	int width = paraSet->getInt(TEXTURE_SIZE_WIDTH);
745 	int height = paraSet->getInt(TEXTURE_SIZE_HEIGHT);
746 	int ets = paraSet->getInt(UNPROJECT_EDGE_STRETCHING_PASS);
747 	//bool enable_angle_map = paraSet->getBool(UNPROJECT_ENABLE_ANGLE);
748 	//int angle_weight = paraSet->getInt(UNPROJECT_ANGLE_WEIGHT);
749 	//int angle_map_sharpness = paraSet->getInt(UNPROJECT_ANGLE_SHARPNESS);
750 	//double min_angle = paraSet->getFloat(UNPROJECT_ANGLE);
751 	//bool enable_distance_map = paraSet->getBool(UNPROJECT_ENABLE_DISTANCE);
752 	//int distance_weight = paraSet->getInt(UNPROJECT_DISTANCE_WEIGHT);
753 	QString smartblend = paraSet->getString(BAKE_SMARTBLEND);
754 
755 	QList<QuadTreeLeaf*> *list = new QList<QuadTreeLeaf*>();
756 	CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> >oth = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> >(m->cm,UVTEXTURECOORDS);
757 	CMeshO::FaceIterator fi;
758 	for(fi = m->cm.face.begin();fi!=m->cm.face.end();fi++) {
759 		list->push_back(oth[fi][origTextureID]);
760 	}
761 
762 	QuadTreeNode qtree = QuadTreeNode(0.0,0.0,1.0,1.0);
763 	//qDebug() << "list->size(): "<<list->size();
764 	//qDebug()<< "buildQuadTree";
765 	qtree.buildQuadTree(list, 0.50/(double)width,0.50/(double)height);
766 /*
767 	ImageFilterContainer *ifc = new ImageFilterContainer();
768 	unprojectToOriginalTextureMap(m,camera,qtree,ifc, enable_distance_map, distance_weight, enable_angle_map,angle_weight,angle_map_sharpness,min_angle,width,height);
769 
770 	ifc->image->save(unprojectTextureName,"PNG");
771 */
772 	return 0;
773 	//delete image;
774 }
775 
bakeTextures(MeshModel * m,FilterParameterSet * paraSet)776 int PhotoTexturer::bakeTextures(MeshModel *m, FilterParameterSet *paraSet){
777 	int width = paraSet->getInt(TEXTURE_SIZE_WIDTH);
778 	int height = paraSet->getInt(TEXTURE_SIZE_HEIGHT);
779 	bool enable_ets = paraSet->getBool(UNPROJECT_ENABLE_EDGE_STRETCHING);
780 	int ets = paraSet->getInt(UNPROJECT_EDGE_STRETCHING_PASS);
781 	bool enable_angle_map = paraSet->getBool(UNPROJECT_ENABLE_ANGLE);
782 	int angle_weight = paraSet->getInt(UNPROJECT_ANGLE_WEIGHT);
783 	int angle_map_sharpness = paraSet->getInt(UNPROJECT_ANGLE_SHARPNESS);
784 	double min_angle = paraSet->getFloat(UNPROJECT_ANGLE);
785 	bool enable_distance_map = paraSet->getBool(UNPROJECT_ENABLE_DISTANCE);
786 	int distance_weight = paraSet->getInt(UNPROJECT_DISTANCE_WEIGHT);
787 	QString smartblend = paraSet->getString(BAKE_SMARTBLEND);
788 	int merger_type = paraSet->getEnum(BAKE_MERGE_TYPE);
789 	bool saveUnprojected = paraSet->getBool(BAKE_SAVE_UNPROJECT);
790 	//creating a list of all UVFaceTexture
791 	QList<QuadTreeLeaf*> list;
792 	CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> >oth = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> >(m->cm,UVTEXTURECOORDS);
793 	CMeshO::FaceIterator fi;
794 	for(fi = m->cm.face.begin();fi!=m->cm.face.end();fi++) {
795 		list.push_back(oth[fi][origTextureID]);
796 	}
797 
798 	//creating a quadtree from list UVFaceTexture
799 	QuadTreeNode qtree = QuadTreeNode(0.0,0.0,1.0,1.0);
800 	qtree.buildQuadTree(&list, 0.50/(double)width,0.50/(double)height);
801 	TextureMerger *texMerger = NULL;
802 	//deciedes which TextureMerger to use
803 	if (merger_type == 0){
804 		texMerger = new WinnerTakesAllTextureMerger();
805 	}else if(merger_type == 1){
806 		texMerger = new SmartBlendTextureMerger(smartblend);
807 	}
808 	if (texMerger != NULL){
809 		for (int i=0;i<cameras.size();i++){
810 			Camera *camera = cameras.at(i);
811 			if(camera->textureId >-1){
812 				ImageFilterContainer *ifc = new ImageFilterContainer();
813 				ifc->tag = camera->name;
814 				unprojectToOriginalTextureMap(m,camera,qtree,ifc, enable_distance_map, distance_weight, enable_angle_map,angle_weight,angle_map_sharpness,min_angle,width,height);
815 				texMerger->ifcList.push_back(ifc);
816 			}
817 		}
818 		texMerger->normalizeFilterContainerList();
819 
820 		if (saveUnprojected){
821 			ImageFilterContainer *ifc;
822 			QFileInfo fi = QFileInfo(m->fileName.c_str());
823 			for (int i=0;i<texMerger->ifcList.size();i++){
824 				ifc = texMerger->ifcList.at(i);
825 				QString upTextureName = fi.baseName()+"_unproject_"+ifc->tag+".png";
826 				ifc->image->save(upTextureName,"PNG");
827 			}
828 		}
829 
830 		QImage *image = texMerger->merge(width,height);
831 		if(image !=NULL){
832 			bakeCounter++;
833 
834 			if(enable_ets){
835 				edgeTextureStretching(image,ets);
836 			}
837 			QString filename = paraSet->getString(BAKE_MERGED_TEXTURE);
838 
839 			QImage final_image = image->convertToFormat(QImage::Format_RGB32);
840 
841 			final_image.save(filename,"PNG");
842 
843 			//create new UVTexture set
844 			qDebug()<<"filename:"<<filename;
845 			int textureId = generateTextureId();
846 			bool found = false;
847 			unsigned int size = static_cast<unsigned int>(m->cm.textures.size());
848 			unsigned j = 0;
849 			int tindx;
850 			while (!found && (j < size)){
851 
852 				if (filename.toStdString().compare(m->cm.textures[j])==0)
853 				{
854 					tindx = (int)j;
855 					found = true;
856 				}
857 				++j;
858 			}
859 
860 			if (!found)
861 			{
862 				m->cm.textures.push_back(filename.toStdString());
863 				tindx = (int)size;
864 			}
865 
866 			qDebug()<<"tindx:"<<tindx;
867 
868 			if (origTextureID>-1){
869 					qDebug()<<"has OriginalTextureCoords";
870 					//CMeshO::PerFaceAttributeHandle<UVFaceTexture*> ihot = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<UVFaceTexture*> (m->cm,ORIGINALUVTEXTURECOORDS);
871 					CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> > cth = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> > (m->cm,UVTEXTURECOORDS);
872 
873 					//overwrites the current texture information with the original texture information
874 					// from the perFaceAttribute "ORIGINALUVTEXTURECOORDS"
875 					CMeshO::FaceIterator fi; int i = 0;
876 					for(fi   = m->cm.face.begin(); fi != m->cm.face.end(); ++fi,++i){
877 
878 						UVFaceTexture* uvft = cth[fi][origTextureID] ;
879 						UVFaceTexture* tmp = new UVFaceTexture(*uvft);
880 						tmp->textureindex = tindx;
881 						tmp->type = 1;
882 						cth[fi][textureId] = tmp;
883 
884 
885 					}
886 				}else{
887 					//qDebug()<<"has no OriginalTextureCoords";
888 				}
889 			qDebug()<<"textureId:"<<textureId;
890 			if(merger_type==0){
891 				textureList[textureId]="baked_win_"+QString::number(bakeCounter);
892 			}else if(merger_type==1){
893 				textureList[textureId]="baked_sb_"+QString::number(bakeCounter);
894 			}
895 
896 			delete texMerger;
897 			return textureId;
898 			delete image;
899 
900 		}
901 	}
902 	return 0;
903 }
904 
905 
mergeTextureImagesWinnerTakesAll(int imgWidth,int imgHeight,QList<QImage> imgList)906 QImage PhotoTexturer::mergeTextureImagesWinnerTakesAll(int imgWidth, int imgHeight, QList<QImage> imgList){
907 	QImage image = QImage(imgWidth,imgHeight,QImage::Format_RGB32);
908 	int x;
909 	int y;
910 	for(x=0; x<imgWidth;x++){
911 		for(y=0;y<imgHeight;y++){
912 			QColor cpixel = QColor(0, 0, 0, 0);
913 			int i;
914 			for(i=0;i<imgList.size();i++){
915 				QImage tmpImg = imgList.at(i);
916 				QColor tmpPixel = QColor::fromRgba(tmpImg.pixel(x,y));
917 				if(cpixel.alpha()<tmpPixel.alpha()){
918 					cpixel = QColor(tmpPixel);
919 				}
920 			}
921 			image.setPixel(x,y,cpixel.rgba());
922 
923 		}
924 	}
925 	return image;
926 }
927 
convertToTsaiCamera(int camIdx,bool optimize,QString filename,MeshModel * mm)928 void PhotoTexturer::convertToTsaiCamera(int camIdx, bool optimize, QString filename,MeshModel *mm){
929 	if(camIdx>=0 && camIdx< cameras.size()){
930 		Camera* newCam = new Camera();
931 		Camera* oldCam = cameras.at(camIdx);
932 
933 		newCam->name = oldCam->name;
934 		newCam->resolution[0] = oldCam->resolution[0];
935 		newCam->resolution[1] = oldCam->resolution[1];
936 		newCam->textureImage = oldCam->textureImage;
937 		newCam->calibration = oldCam->calibration->calibrateToTsai(mm,optimize);
938 
939 		QDomDocument doc(Camera::XML_CAMERADOCUMENT);
940 		QDomElement root = doc.createElement(Camera::XML_CAMERADOCUMENT);
941 		newCam->saveAsXml(&doc,&root);
942 		doc.appendChild(root);
943 		QFile file(filename);
944 		file.open(QIODevice::WriteOnly);
945 		QTextStream qstream(&file);
946 		doc.save(qstream,1);
947 		file.close();
948 
949 	}
950 }
951 
exportMaxScript(QString filename,MeshModel * mm)952 void PhotoTexturer::exportMaxScript(QString filename,MeshModel *mm){
953 
954 	QFile* ms = new QFile(filename);
955 	if (ms->open(QIODevice::WriteOnly)){
956 	     QTextStream out(ms);
957 	     out << "(\n";
958 	     int i;
959 	     for (i=0;i<cameras.size();i++){
960 	    	 Camera* cam = cameras.at(i);
961 	    	 //TsaiCameraCalibration* tsai = dynamic_cast<TsaiCameraCalibration*>(cam->calibration);
962 	    	 TsaiCameraCalibration* tsai = dynamic_cast<TsaiCameraCalibration*>(cam->calibration->calibrateToTsai(mm,false));
963 	    	 if (tsai!=NULL){
964 	    		 out << "-- kappa1: "<< tsai->calib_const.kappa1<<"\n";
965 	    		 out << "-- Cx: "<< tsai->cam_para.Cx << "\tCy: "<<tsai->cam_para.Cy<<"\n";
966 	    		 out << "-- sx: "<< tsai->cam_para.sx<<"\n";
967 	    		 out << "-- p1: "<< tsai->calib_const.p1 << "\tp2: "<<tsai->calib_const.p2<<"\n";
968 	    		 out << "\n";
969 	    		 out << "r1 = [" << tsai->calib_const.r1<<",\t"<< -tsai->calib_const.r4<<",\t"<<-tsai->calib_const.r7<<"]\n";
970 	    		 out << "r2 = [" << tsai->calib_const.r2<<",\t"<< -tsai->calib_const.r5<<",\t"<<-tsai->calib_const.r8<<"]\n";
971 	    		 out << "r3 = [" << tsai->calib_const.r3<<",\t"<< -tsai->calib_const.r6<<",\t"<<-tsai->calib_const.r9<<"]\n";
972 	    		 out << "r4 = [" << tsai->calib_const.Tx<<",\t"<< -tsai->calib_const.Ty<<",\t"<<-tsai->calib_const.Tz<<"]\n";
973 
974 	    		 out<< "m = matrix3 r1 r2 r3 r4\n";
975 
976 	    		 out << "setRendApertureWidth ("<< tsai->cam_para.dpx * cam->resolution[0]<<")\n";//  -- horizontal size of sensor/filmback
977 	    		 out << "renderPixelAspect = " << tsai->cam_para.dpx/tsai->cam_para.dpy<<"\n"; //     -- non-square pixels?
978 	    		 out << "renderWidth = "<< cam->resolution[0] <<"\n";
979 	    		 out << "renderHeight = "<< cam->resolution[1] <<"\n";
980 
981 	    		 out << "freecamera name:\""<< cam->name <<"\" fov:(cameraFOV.MMtoFOV "<<tsai->calib_const.f<<") transform:(inverse m)\n";
982 	    		 out << "\n\n";
983 	    	 }
984 	     }
985 	     out << ")\n";
986 	     ms->close();
987 	}else{
988 		qDebug()<< "Could not open max script file." <<filename;
989 	}
990 
991 
992 }
993 
994 
995 
combineTextures(MeshModel * m)996 int PhotoTexturer::combineTextures(MeshModel* m){
997 	int textureId  = -1;
998 	if (vcg::tri::HasPerFaceAttribute(m->cm,UVTEXTURECOORDS)){
999 
1000 		CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> > ih = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> > (m->cm,UVTEXTURECOORDS);
1001 		CMeshO::FaceIterator fi;
1002 		textureId = generateTextureId();
1003 
1004 		int k =0;
1005 		for(fi=m->cm.face.begin(); fi!=m->cm.face.end(); ++fi) {
1006 			UVFaceTexture* ft =0;
1007 			int j;
1008 			for(j=0;j<cameras.size();j++){
1009 				UVFaceTexture* tmp = ih[fi][cameras.at(j)->textureId];
1010 				if (tmp!=NULL){
1011 					if(tmp->type == 0){
1012 						if (ft==0 || ft->faceAngleToCamera>tmp->faceAngleToCamera){
1013 
1014 							if(((tmp->u[0]>=0.0 && tmp->u[0] <=1.0)&&(tmp->v[0]>=0.0 && tmp->v[0] <=1.0))&&
1015 								((tmp->u[1]>=0.0 && tmp->u[1] <=1.0)&&(tmp->v[1]>=0.0 && tmp->v[1] <=1.0))&&
1016 								((tmp->u[2]>=0.0 && tmp->u[2] <=1.0)&&(tmp->v[2]>=0.0 && tmp->v[2] <=1.0))){
1017 								ft = tmp;
1018 							}
1019 						}
1020 					}
1021 				}
1022 			}
1023 
1024 			UVFaceTexture* tmp2 = NULL;
1025 			if(ft!=NULL){
1026 				tmp2 = new UVFaceTexture(*ft);
1027 				tmp2->type = 1;
1028 			}
1029 			ih[fi][textureId]=tmp2;
1030 
1031 
1032 			k++;
1033 		}
1034 	}
1035 	textureList[textureId] = "combined_"+QString::number(combineCounter);
1036 	combineCounter++;
1037 	return textureId;
1038 }
1039 
calculateZBuffer(MeshModel * mm,Camera * camera,QuadTreeNode * qtree,TextureFilterZB * zbuffer)1040 void PhotoTexturer::calculateZBuffer(MeshModel *mm,Camera* camera,QuadTreeNode *qtree, TextureFilterZB *zbuffer){
1041 
1042 	qDebug()<< "zbuffer->vm_height:"<<zbuffer->vm_height<<"zbuffer->vm_width:" <<zbuffer->vm_width;
1043 	int x,y;
1044 	for (y=0;y<zbuffer->vm_height;y++){
1045 		for (x=0;x<zbuffer->vm_width;x++){
1046 			double dx = ((double)x/(double)(zbuffer->vm_width-1));
1047 			double dy = ((double)y/(double)(zbuffer->vm_height-1));
1048 			QList<QuadTreeLeaf*>list;
1049 			qtree->getLeafs(dx,dy,list);
1050 			if(list.size()>0){
1051 				int i;
1052 				for (i=0;i<list.size();i++){
1053 					QuadTreeLeaf* leaf = list.at(i);
1054 					UVFaceTexture *uvft = dynamic_cast<UVFaceTexture*>(leaf);
1055 					if (uvft != 0){
1056 						double a,b,c,d;
1057 						uvft->getBarycentricCoordsForUV(dx,dy,a,b,c,d);
1058 						//qDebug() << "d:" << d;
1059 						if(d == 0.0){
1060 							CFaceO face = mm->cm.face.at(uvft->faceIndex);
1061 							vcg::Point3f point = face.V(0)->cP()*a+face.V(1)->cP()*b+face.V(2)->cP()*c;
1062 							double distance = sqrt(pow(camera->calibration->cameraPosition[0]-point[0],2)+pow(camera->calibration->cameraPosition[1]-point[1],2)+pow(camera->calibration->cameraPosition[2]-point[2],2));
1063 							//qDebug()<< "distance: " << distance;
1064 							if(zbuffer->getValue(x,y)== DBL_MIN||zbuffer->getValue(x,y)>distance){
1065 								zbuffer->setValue(x,y,distance);
1066 								//qDebug()<< "found z";
1067 							}
1068 						}else{
1069 
1070 						}
1071 					}
1072 
1073 				}
1074 			}
1075 		}
1076 	}
1077 
1078 }
1079 
reset(MeshModel * mm)1080 void PhotoTexturer::reset(MeshModel *mm){
1081 	if (origTextureID > -1){
1082 		restoreOriginalTextureCoordinates(mm);
1083 	}else{
1084 		mm->clearDataMask(MeshModel::MM_WEDGTEXCOORD);
1085 	}
1086 
1087 
1088 	QList<int> keys = textureList.keys();
1089 
1090 
1091 	for(int i =0; i< keys.size();i++){
1092 		int key = keys[i];
1093 		if(key != origTextureID){
1094 			QMap<int, QString>::const_iterator it = textureList.find(key);
1095 			if (it != textureList.end()){
1096 				if (vcg::tri::HasPerFaceAttribute(mm->cm,UVTEXTURECOORDS)){
1097 
1098 					CMeshO::PerFaceAttributeHandle<QMap<int,UVFaceTexture*> > ih = vcg::tri::Allocator<CMeshO>::GetPerFaceAttribute<QMap<int,UVFaceTexture*> > (mm->cm,UVTEXTURECOORDS);
1099 					CMeshO::FaceIterator fi;
1100 					for(fi=mm->cm.face.begin(); fi!=mm->cm.face.end(); ++fi) {
1101 						int i;
1102 						UVFaceTexture* ft = ih[fi][key];
1103 						delete ft;
1104 						ih[fi].remove(key);
1105 					}
1106 					//m->cm
1107 				}
1108 			}
1109 			textureList.remove(key);
1110 		}
1111 	}
1112 
1113 	for(int i = 0;i<cameras.size();i++){
1114 		Camera *c = cameras.at(i);
1115 		delete c;
1116 		cameras.clear();
1117 	}
1118 }
1119 
1120