diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 3818b25..ffc7346 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -1261,6 +1261,229 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr } ++progress; } + + // Temp + /* + for (int_t idx=0; idx<(int_t)views.size(); ++idx) + { + #pragma omp flush (bAbort) + if (bAbort) + { + ++progress; + continue; + } + const IIndex idxView(views[(IIndex)idx]); + + Image& imageData = images[idxView]; + if (!imageData.IsValid()) { + ++progress; + continue; + } + + std::string strPath = imageData.name; + size_t lastSlash = strPath.find_last_of("/\\"); + if (lastSlash == std::string::npos) lastSlash = 0; // 若无分隔符,从头开始 + else lastSlash++; // 跳过分隔符 + + // 查找扩展名分隔符 '.' 的位置 + size_t lastDot = strPath.find_last_of('.'); + if (lastDot == std::string::npos) lastDot = strPath.size(); // 若无扩展名,截到末尾 + + // 截取文件名(不含路径和扩展名) + std::string strName = strPath.substr(lastSlash, lastDot - lastSlash); + + // load image + unsigned level(nResolutionLevel); + const unsigned imageSize(imageData.RecomputeMaxResolution(level, nMinResolution)); + if ((imageData.image.empty() || MAXF(imageData.width,imageData.height) != imageSize) && !imageData.ReloadImage(imageSize)) { + #ifdef TEXOPT_USE_OPENMP + bAbort = true; + #pragma omp flush (bAbort) + continue; + #else + return false; + #endif + } + imageData.UpdateCamera(scene.platforms); + // compute gradient magnitude + imageData.image.toGray(imageGradMag, cv::COLOR_BGR2GRAY, true); + cv::Mat grad[2]; + mGrad[0].resize(imageGradMag.rows, imageGradMag.cols); + grad[0] = cv::Mat(imageGradMag.rows, imageGradMag.cols, cv::DataType::type, (void*)mGrad[0].data()); + mGrad[1].resize(imageGradMag.rows, imageGradMag.cols); + grad[1] = cv::Mat(imageGradMag.rows, imageGradMag.cols, cv::DataType::type, (void*)mGrad[1].data()); + + cv::Sobel(imageGradMag, grad[0], cv::DataType::type, 1, 0, 3, 1.0/8.0); + cv::Sobel(imageGradMag, grad[1], cv::DataType::type, 0, 1, 3, 1.0/8.0); + + (TImage::EMatMap)imageGradMag = (mGrad[0].cwiseAbs2()+mGrad[1].cwiseAbs2()).cwiseSqrt(); + // apply some blur on the gradient to lower noise/glossiness effects onto face-quality score + cv::GaussianBlur(imageGradMag, imageGradMag, cv::Size(15, 15), 0, 0, cv::BORDER_DEFAULT); + // select faces inside view frustum + Mesh::FaceIdxArr cameraFaces; + Mesh::FacesInserter inserter(cameraFaces); + const TFrustum frustum(Matrix3x4f(imageData.camera.P), (float)imageData.width, (float)imageData.height); + octree.Traverse(frustum, inserter); + // project all triangles in this view and keep the closest ones + faceMap.create(imageData.GetSize()); + depthMap.create(imageData.GetSize()); + + std::unordered_set tempFaces; + { + // RasterMesh rasterer(vertices, imageData.camera, depthMap, faceMap); + RasterMesh rasterer(*this, vertices, imageData.camera, depthMap, faceMap, scene.mesh, false); + RasterMesh::Triangle triangle; + RasterMesh::TriangleRasterizer triangleRasterizer(triangle, rasterer); + if (nIgnoreMaskLabel >= 0) { + // import mask + BitMatrix bmask; + // std::cout << "nIgnoreMaskLabel is open" << std::endl; + DepthEstimator::ImportIgnoreMask(imageData, imageData.GetSize(), (uint16_t)OPTDENSE::nIgnoreMaskLabel, bmask, &rasterer.mask); + } else if (nIgnoreMaskLabel == -1) { + // creating mask to discard invalid regions created during image radial undistortion + rasterer.mask = DetectInvalidImageRegions(imageData.image); + #if TD_VERBOSE != TD_VERBOSE_OFF + if (VERBOSITY_LEVEL > 2) + cv::imwrite(String::FormatString("umask%04d.png", idxView), rasterer.mask); + #endif + } + rasterer.Clear(); + for (FIndex idxFace : cameraFaces) { + rasterer.validFace = true; + const Face& facet = faces[idxFace]; + rasterer.idxFace = idxFace; + + bool bExistFace = facesDatas[idxFace].empty(); + + if (scene.is_face_visible(strName.c_str(), idxFace) || bExistFace) + { + rasterer.Project(facet, triangleRasterizer); + if (!rasterer.validFace) + rasterer.Project(facet, triangleRasterizer); + } + } + + tempFaces = PerformLocalDepthConsistencyCheck(depthMap, faceMap, scene.mesh, idxView, strName); + } + + // compute the projection area of visible faces + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + CLISTDEF0IDX(uint32_t,FIndex) areas(faces.size()); + areas.Memset(0); + #endif + + #ifdef TEXOPT_USE_OPENMP + #pragma omp critical + #endif + + { + for (int j=0; j 0)); + + if (idxFace == NO_ID) + continue; + + FaceDataArr& faceDatas = facesDatas[idxFace]; + + const Pixel8U& pixel = imageData.image(j, i); + // 假设是8位图像,RGB三个通道任一超过250即视为过曝 + if (pixel.r > 250 || pixel.g > 250 || pixel.b > 250) { + // continue; + } + + float brightnessPerceptual = (0.299f * pixel.r + 0.587f * pixel.g + 0.114f * pixel.b) / 255.0f; + // printf("brightnessPerceptual=%f\n", brightnessPerceptual); + + if (brightnessPerceptual>0.95f) + continue; + + { + if (depthMap(j,i)>999.0f) + { + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + uint32_t& area = areas[idxFace]; + if (area++ == 0) { + #else + if (faceDatas.empty() || faceDatas.back().idxView != idxView) { + #endif + // create new face-data + FaceData& faceData = faceDatas.emplace_back(); + faceData.idxView = idxView; + faceData.quality = imageGradMag(j,i); + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + faceData.color = imageData.image(j,i); + #endif + faceData.bInvalidFacesRelative = true; + } else { + // update face-data + ASSERT(!faceDatas.empty()); + FaceData& faceData = faceDatas.back(); + ASSERT(faceData.idxView == idxView); + faceData.quality = imageGradMag(j,i); + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + faceData.color = Color(imageData.image(j,i)); + #endif + faceData.bInvalidFacesRelative = true; + } + continue; + } + } + + uint32_t& area = areas[idxFace]; + if (area++ == 0) { + // create new face-data + FaceData& faceData = faceDatas.emplace_back(); + faceData.idxView = idxView; + faceData.quality = imageGradMag(j,i); + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + faceData.color = imageData.image(j,i); + #endif + if (depthMap(j,i)>999.0f) + faceData.bInvalidFacesRelative = true; + } else { + // update face-data + ASSERT(!faceDatas.empty()); + FaceData& faceData = faceDatas.back(); + ASSERT(faceData.idxView == idxView); + faceData.quality += imageGradMag(j,i); + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + faceData.color += Color(imageData.image(j,i)); + #endif + if (depthMap(j,i)>999.0f) + faceData.bInvalidFacesRelative = true; + } + } + } + // adjust face quality with camera angle relative to face normal + // tries to increase chances of a camera with perpendicular view on the surface (smoothened normals) to be selected + FOREACH(idxFace, facesDatas) { + FaceDataArr& faceDatas = facesDatas[idxFace]; + if (faceDatas.empty() || faceDatas.back().idxView != idxView) + continue; + const Face& f = faces[idxFace]; + const Vertex faceCenter((vertices[f[0]] + vertices[f[1]] + vertices[f[2]]) / 3.f); + const Point3f camDir(Cast(imageData.camera.C) - faceCenter); + const Normal& faceNormal = scene.mesh.faceNormals[idxFace]; + const float cosFaceCam(MAXF(0.001f, ComputeAngle(camDir.ptr(), faceNormal.ptr()))); + faceDatas.back().quality *= SQUARE(cosFaceCam); + } + #if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA + FOREACH(idxFace, areas) { + const uint32_t& area = areas[idxFace]; + if (area > 0) { + Color& color = facesDatas[idxFace].back().color; + color = RGB2YCBCR(Color(color * (1.f/(float)area))); + } + } + #endif + } + ++progress; + } + // */ + // Temp + #ifdef TEXOPT_USE_OPENMP if (bAbort) return false; diff --git a/libs/MVS/mask_face_occlusion.py b/libs/MVS/mask_face_occlusion.py index 906c7a1..efeded8 100755 --- a/libs/MVS/mask_face_occlusion.py +++ b/libs/MVS/mask_face_occlusion.py @@ -1353,7 +1353,7 @@ class ModelProcessor: face_visible = v0_visible | v1_visible | v2_visible # 使用与CPU版本相同的后续处理 - shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 10) + shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 6) expanded_visibility = self._expand_face_visibility(face_visible.cpu().numpy(), 30) shrunk_visibility2 = self._shrink_face_visibility(face_visible.cpu().numpy(), 50) expanded_edge = expanded_visibility & ~shrunk_visibility2