void BOP_Merge2::mergeFaces(BOP_Mesh *m, BOP_Index v) { m_mesh = m; #ifdef BOP_DEBUG cout << "##############################" << endl; #endif cleanup( ); m_firstVertex = v; bool cont = false; // Merge faces mergeFaces(); do { // Add quads ... cont = createQuads(); // ... and merge new faces if( cont ) cont = mergeFaces(); #ifdef BOP_DEBUG cout << "called mergeFaces " << cont << endl; #endif // ... until the merge is not succesful } while(cont); }
/** * Returns a new quad from the merge of two faces (one quad and one triangle) * that share the vertex v and come from the same original face. * @param faceI mesh face (quad or triangle) with index v * @param faceJ mesh face (quad or triangle) with index v * @param v vertex index shared by both faces * @return if the merge is possible, a new quad without v */ BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v) { if (faceI->size() == 3) { if (faceJ->size() == 4) return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,v); } else if (faceI->size() == 4) { if (faceJ->size() == 3) return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,v); } return NULL; }
/** * Simplifies a mesh, merging its faces. * @param m mesh * @param v index of the first mergeable vertex (can be removed by merge) */ void BOP_Merge::mergeFaces(BOP_Mesh *m, BOP_Index v) { m_mesh = m; m_firstVertex = v; bool cont = false; // Merge faces mergeFaces(); do { // Add quads ... cont = createQuads(); if (cont) { // ... and merge new faces cont = mergeFaces(); } // ... until the merge is not succesful } while(cont); }
/** * Simplifies a mesh, merging its faces. */ bool BOP_Merge::mergeFaces() { BOP_Indexs mergeVertices; BOP_Vertexs vertices = m_mesh->getVertexs(); BOP_IT_Vertexs v = vertices.begin(); const BOP_IT_Vertexs verticesEnd = vertices.end(); // Advance to first mergeable vertex advance(v,m_firstVertex); BOP_Index pos = m_firstVertex; // Add unbroken vertices to the list while(v!=verticesEnd) { if ((*v)->getTAG() != BROKEN) mergeVertices.push_back(pos); v++;pos++; } // Merge faces with that vertices return mergeFaces(mergeVertices); }
/** * Simplifies a mesh, merging the faces with vertex v that come from the same face. * @param oldFaces sequence of old mesh faces obtained from the merge * @param newFaces sequence of new mesh faces obtained from the merge * @param vertices sequence of indexs (v1 ... vi = v ... vn) where : * v is the current vertex to test, * vj (j < i) are tested vertices, * vk (k >= i) are vertices required to test to merge vj * (so if a vertex vk can't be merged, the merge is not possible). * @return true if the vertex v was 'merged' (obviously it could require to test * some new vertices that will be added to the vertices list) */ bool BOP_Merge::mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) { bool merged = true; // Get faces with v that come from the same original face, (without the already 'merged' from vertices) BOP_LFaces facesByOriginalFace; getFaces(facesByOriginalFace,vertices,v); if (facesByOriginalFace.size()==0) { // All the faces with this vertex were already merged!!! return true; } else { // Merge faces const BOP_IT_LFaces facesEnd = facesByOriginalFace.end(); for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin(); (facesByOriginalFaceX != facesEnd)&&merged; facesByOriginalFaceX++) { merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,vertices,v); } } return merged; }
//------------------------------------------------------------------------------------------------------- bool Exporter::processMesh(RawMesh& rawMesh, const char* fileName) { rawMesh_ = &rawMesh; meshData_.reset(new(std::nothrow) Mesh::Data); if(!meshData_) { std::cout << "error: not enough memory" << std::endl; return false; } numVertices_ = rawMesh_->positions_.getSize(); meshData_->boundingBox = rawMesh_->boundingBox_; boneIndices_.destroy(); boneWeights_.destroy(); vertices_.clear(); newToOldVertexMapping_.clear(); std::cout << "processing raw mesh..." << std::endl; faces_ = rawMesh_->faces_; if(faces_.getSize() != rawMesh_->faces_.getSize()) { std::cout << "error: not enough memory" << std::endl; return false; } std::cout << "merging faces..." << std::endl; numVertices_ = mergeFaces(faces_, rawMesh_->normalFaces_, faces_, numVertices_); if(numVertices_ == 0) { std::cout << "error: could not merge faces" << std::endl; return false; } numVertices_ = mergeFaces(faces_, rawMesh_->textureFaces_, faces_, numVertices_); if(numVertices_ == 0) { std::cout << "error: could not merge faces" << std::endl; return false; } if(!rawMesh_->bones_.isEmpty()) { std::cout << "reading bone indices and weights..." << std::endl; if(!boneIndices_.create(numVertices_) || !boneWeights_.create(numVertices_)) { std::cout << "error: not enough memory" << std::endl; return false; } uint32_t numFaces = faces_.getSize(); for(uint32_t i = 0; i < numFaces; ++i) { const RawMesh::Face& face = rawMesh_->faces_[i]; for(uint8_t j = 0; j < 3; ++j) { uint32_t vertexIndex = faces_[i].indices[j]; boneIndices_[vertexIndex] = rawMesh_->boneIndices_[face.indices[j]]; boneWeights_[vertexIndex] = rawMesh_->boneWeights_[face.indices[j]]; } } } std::cout << "computing tangent space..." << std::endl; if(!computeTangentSpace()) { std::cout << "error: broken mesh" << std::endl; return false; } std::cout << "preparing vertex streams..." << std::endl; if(!prepareVertexStreams()) { std::cout << "error: not enough memory" << std::endl; return false; } std::cout << "preparing faces..." << std::endl; if(!prepareFaces()) { std::cout << "error: not enough memory" << std::endl; return false; } std::cout << "preparing subsets..." << std::endl; if(!prepareSubsets()) { std::cout << "error: not enough memory" << std::endl; return false; } if(!rawMesh_->bones_.isEmpty()) { std::cout << "preparing skeleton..."; auto& skeleton = meshData_->skeleton; skeleton.reset(new(std::nothrow) Skeleton); if(!skeleton) { std::cout << "error: not enough memory" << std::endl; return false; } skeleton->getBones() = rawMesh_->bones_; if(skeleton->getBones().getSize() != rawMesh_->bones_.getSize()) { std::cout << "error: not enough memory" << std::endl; return false; } } std::cout << "writing mesh to the file..." << std::endl; std::ofstream stream(fileName, std::ios_base::binary); MeshManager meshManager; if(!meshManager.writeMesh(stream, *meshData_)) { std::cout << "error: could not write mesh to the file" << std::endl; return false; } std::cout << "mesh has " << numVertices_; std::cout << " vertices and " << faces_.getSize() << " faces" << std::endl; return true; }
vector<Face> FaceDetect::detectFaces(const IplImage* inputImage, const CvSize& size) { if (inputImage->imageData == 0) { cout<<"Bad image given, not detecting faces."<<endl; return vector<Face>(); } CvSize originalSize = size; if (!size.width && !size.height) originalSize = cvSize(inputImage->width, inputImage->height); clock_t init, detect, duration; if (DEBUG) init = clock(); IplImage* scaled = 0; d->scaleFactor = 1; int inputArea = inputImage->width*inputImage->height; if (DEBUG) printf("Input area : %d\n", inputArea); if (inputArea > getRecommendedImageSizeForDetection() * getRecommendedImageSizeForDetection()) { if (DEBUG) cout << "downscaling input image" << endl; scaled = libface::LibFaceUtils::resizeToArea(inputImage, 786432, d->scaleFactor); } const IplImage* image = scaled ? scaled : inputImage; updateParameters(cvSize(image->width, image->height), originalSize); // Now loop through each cascade, apply it, and get back a vector of detected faces vector<vector<Face> > primaryResults(d->cascadeSet->getSize()); vector<Face> finalResult; d->storage = cvCreateMemStorage(0); for (int i = 0; i < d->cascadeSet->getSize(); ++i) { if (d->cascadeProperties[i].primaryCascade) { if (DEBUG) detect = clock(); primaryResults[i] = cascadeResult(image, d->cascadeSet->getCascade(i).haarcasc, d->primaryParams); if (DEBUG) { duration = clock() - detect; cout <<"Primary detection with " << d->cascadeSet->getCascade(i).name << ": " << ((double)duration / ((double)CLOCKS_PER_SEC)) << " sec" << endl; } } } // After intelligently "merging" overlaps of face regions by different cascades, // this creates a list of faces. finalResult = mergeFaces(image, primaryResults, d->maxDistance, d->minDuplicates); //LibFaceUtils::showImage(image, finalResult); // Verify faces using other cascades for (vector<Face>::iterator it = finalResult.begin(); it != finalResult.end(); ) { if (!verifyFace(image, *it)) it = finalResult.erase(it); else ++it; } cvReleaseMemStorage(&d->storage); if (scaled) cvReleaseImage(&scaled); // Insert extracted images into face for (vector<Face>::iterator it = finalResult.begin(); it != finalResult.end(); ++it) { // rescale to full image if (d->scaleFactor != 1) { it->setX1(lround(it->getX1() * d->scaleFactor)); it->setY1(lround(it->getY1() * d->scaleFactor)); it->setX2(lround(it->getX2() * d->scaleFactor)); it->setY2(lround(it->getY2() * d->scaleFactor)); } //Extract face-image from whole-image. CvRect rect = cvRect(it->getX1(), it->getY1(), it->getWidth(), it->getHeight()); IplImage* faceImg = LibFaceUtils::copyRect(inputImage, rect); it->setFace(faceImg); } if (DEBUG) { duration = clock() - init; cout << "Total time : " << ((double)duration / ((double)CLOCKS_PER_SEC))<< " sec" << endl; } return finalResult; }
/** * Merge a set of faces removing the vertex index v. * @param faces set of faces * @param oldFaces set of old faces obtained from the merge * @param newFaces set of new faces obtained from the merge * @param vertices sequence of indexs (v1 ... vi = v ... vn) where : * v is the current vertex to test, * vj (j < i) are tested vertices, * vk (k >= i) are vertices required to test to merge vj * (so if a vertex vk can't be merged, the merge is not possible). * @param v vertex index * @return true if the merge is succesful, false otherwise */ bool BOP_Merge::mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) { bool merged = false; if (faces.size() == 2) { // Merge a pair of faces into a new face without v BOP_Face *faceI = faces[0]; BOP_Face *faceJ = faces[1]; BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v); if (faceK != NULL) { newFaces.push_back(faceK); oldFaces.push_back(faceI); oldFaces.push_back(faceJ); merged = true; } else merged = false; } else if (faces.size() == 4) { // Merge two pair of faces into a new pair without v // First we try to perform a simplify merge to avoid more pending vertices // (for example, if we have two triangles and two quads it will be better // to do 3+4 and 3+4 than 3+3 and 4+4) BOP_Face *oldFace1 = faces[0]; BOP_Face *oldFace2, *newFace1; unsigned int indexJ = 1; while (indexJ < faces.size() && !merged) { oldFace2 = faces[indexJ]; newFace1 = mergeFaces(oldFace1,oldFace2,v); if (newFace1 != NULL) merged = true; else indexJ++; } if (merged) { // Merge the other pair of faces unsigned int indexK, indexL; if (indexJ == 1) {indexK = 2;indexL = 3;} else if (indexJ == 2) {indexK = 1;indexL = 3;} else {indexK = 1;indexL = 2;} BOP_Face *oldFace3 = faces[indexK]; BOP_Face *oldFace4 = faces[indexL]; unsigned int oldSize = vertices.size(); BOP_Face *newFace2 = mergeFaces(oldFace3,oldFace4,vertices,v); if (newFace2 != NULL) { newFaces.push_back(newFace1); newFaces.push_back(newFace2); oldFaces.push_back(oldFace1); oldFaces.push_back(oldFace2); oldFaces.push_back(oldFace3); oldFaces.push_back(oldFace4); merged = true; } else { // Undo all changes delete newFace1; merged = false; unsigned int count = vertices.size() - oldSize; if (count != 0) vertices.erase(vertices.end() - count, vertices.end()); } } if (!merged) { // Try a complete merge merged = true; while (faces.size()>0 && merged) { indexJ = 1; BOP_Face *faceI = faces[0]; merged = false; while (indexJ < faces.size()) { BOP_Face *faceJ = faces[indexJ]; BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v); if (faceK != NULL) { // faceK = faceI + faceJ and it does not include v! faces.erase(faces.begin()+indexJ,faces.begin()+(indexJ+1)); faces.erase(faces.begin(),faces.begin()+1); newFaces.push_back(faceK); oldFaces.push_back(faceI); oldFaces.push_back(faceJ); merged = true; break; } else indexJ++; } } } } else merged = false; // there are N=1 or N=3 or N>4 faces! // Return merge result return merged; }
/** * Simplifies a mesh, merging the faces with the specified vertices. * @param mergeVertices vertices to test * @return true if a face merge was performed */ bool BOP_Merge::mergeFaces(BOP_Indexs &mergeVertices) { // Check size > 0! if (mergeVertices.size() == 0) return false; // New faces added by merge BOP_Faces newFaces; // Old faces removed by merge BOP_Faces oldFaces; // Get the first vertex index and add it to // the current pending vertices to merge BOP_Index v = mergeVertices[0]; BOP_Indexs pendingVertices; pendingVertices.push_back(v); // Get faces with index v that come from the same original face BOP_LFaces facesByOriginalFace; getFaces(facesByOriginalFace,v); bool merged = true; // Check it has any unbroken face if (facesByOriginalFace.size()==0) { // v has not any unbroken face (so it's a new BROKEN vertex) (m_mesh->getVertex(v))->setTAG(BROKEN); merged = false; } // Merge vertex faces const BOP_IT_LFaces facesEnd = facesByOriginalFace.end(); for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin(); (facesByOriginalFaceX != facesEnd)&&merged; facesByOriginalFaceX++) { merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,pendingVertices,v); } // Check if the are some pendingVertices to merge if (pendingVertices.size() > 1 && merged) { // There are pending vertices that we need to merge in order to merge v ... for(unsigned int i=1;i<pendingVertices.size() && merged;i++) merged = mergeFaces(oldFaces,newFaces,pendingVertices,pendingVertices[i]); } // If merge was succesful ... if (merged) { // Set old faces to BROKEN... const BOP_IT_Faces oldFacesEnd = oldFaces.end(); for(BOP_IT_Faces face=oldFaces.begin();face!=oldFacesEnd;face++) (*face)->setTAG(BROKEN); // ... and add merged faces (that are the new merged faces without pending vertices) const BOP_IT_Faces newFacesEnd = newFaces.end(); for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) { m_mesh->addFace(*newFace); // Also, add new face vertices to the queue of vertices to merge if they weren't for(BOP_Index i = 0;i<(*newFace)->size();i++) { BOP_Index vertexIndex = (*newFace)->getVertex(i); if (vertexIndex >= m_firstVertex && !containsIndex(mergeVertices,vertexIndex)) mergeVertices.push_back(vertexIndex); } } // Set the merged vertices to BROKEN ... const BOP_IT_Indexs pendingEnd = pendingVertices.end(); for(BOP_IT_Indexs pendingVertex = pendingVertices.begin(); pendingVertex != pendingEnd;pendingVertex++) { BOP_Index pV = *pendingVertex; m_mesh->getVertex(pV)->setTAG(BROKEN); // ... and remove them from mergeVertices queue const BOP_IT_Indexs mergeEnd = mergeVertices.end(); for(BOP_IT_Indexs mergeVertex = mergeVertices.begin(); mergeVertex != mergeEnd;mergeVertex++) { BOP_Index mV = *mergeVertex; if (mV == pV) { mergeVertices.erase(mergeVertex); break; } } } } else { // The merge was not succesful, remove the vertex frome merge vertices queue mergeVertices.erase(mergeVertices.begin()); // free the not used newfaces const BOP_IT_Faces newFacesEnd = newFaces.end(); for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) { delete (*newFace); } } // Invoke mergeFaces and return the merge result return (mergeFaces(mergeVertices) || merged); }