diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 06e566e..c17d621 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -9781,7 +9781,7 @@ Pixel8U SampleImageBilinear(const Image8U3& image, const Point2f& point) { return result; } -void FillTextureGaps(Image8U3& textureAtlas, const Mesh::TexCoordArr& faceTexcoords, +void FillTextureGaps2(Image8U3& textureAtlas, const Mesh::TexCoordArr& faceTexcoords, FIndex nFaces, const MeshTexture::LabelArr& faceLabels, const IIndexArr& views, int textureSize, Pixel8U colEmpty) { @@ -9926,6 +9926,213 @@ void FillTextureGaps(Image8U3& textureAtlas, const Mesh::TexCoordArr& faceTexcoo inpaintResult.copyTo(textureAtlas); } + DEBUG_EXTRA("纹理间隙填充完成"); +}// 修改TextureGrid结构体,在构造函数中传入纹理大小 +struct TextureGrid { + std::vector> grid; + float cellSize; + int gridSize; + int textureSize; // 添加纹理大小成员变量 + + TextureGrid(int _textureSize, int cellCount) : textureSize(_textureSize) { + cellSize = (float)textureSize / cellCount; + gridSize = cellCount; + grid.resize(gridSize * gridSize); + } + + void AddTriangle(FIndex faceIdx, const TexCoord* uvCoords, int _textureSize) { // 添加纹理大小参数 + int minX = _textureSize, maxX = 0; + int minY = _textureSize, maxY = 0; + for (int i = 0; i < 3; ++i) { + int px = std::max(0, std::min(_textureSize - 1, (int)(uvCoords[i].x * _textureSize))); + int py = std::max(0, std::min(_textureSize - 1, (int)(uvCoords[i].y * _textureSize))); + minX = std::min(minX, px); + maxX = std::max(maxX, px); + minY = std::min(minY, py); + maxY = std::max(maxY, py); + } + + int cellMinX = std::max(0, (int)(minX / cellSize)); + int cellMaxX = std::min(gridSize-1, (int)(maxX / cellSize)); + int cellMinY = std::max(0, (int)(minY / cellSize)); + int cellMaxY = std::min(gridSize-1, (int)(maxY / cellSize)); + + for (int cy = cellMinY; cy <= cellMaxY; ++cy) { + for (int cx = cellMinX; cx <= cellMaxX; ++cx) { + grid[cy * gridSize + cx].push_back(faceIdx); + } + } + } + + const std::vector& GetTrianglesInCell(int x, int y) const { + return grid[y * gridSize + x]; + } +}; + +void GenerateDistanceFieldFast(cv::Mat& distanceField, cv::Mat& nearestFaceIdx, + const std::vector& seedPoints, + int textureSize) { + // 使用跳点传播算法 + distanceField = cv::Mat::zeros(textureSize, textureSize, CV_32FC1); + nearestFaceIdx = cv::Mat::zeros(textureSize, textureSize, CV_32SC1); + + // 初始化距离场 + distanceField.setTo(std::numeric_limits::max()); + + // 标记种子点 + for (const auto& pt : seedPoints) { + distanceField.at(pt) = 0; + nearestFaceIdx.at(pt) = pt.y * textureSize + pt.x; // 存储自身索引 + } + + // 跳点传播 + for (int step = textureSize / 2; step >= 1; step /= 2) { + #pragma omp parallel for collapse(2) + for (int y = 0; y < textureSize; ++y) { + for (int x = 0; x < textureSize; ++x) { + float minDist = distanceField.at(y, x); + int bestIdx = nearestFaceIdx.at(y, x); + + for (int dy = -1; dy <= 1; dy += 2) { + for (int dx = -1; dx <= 1; dx += 2) { + int nx = x + dx * step; + int ny = y + dy * step; + + if (nx >= 0 && nx < textureSize && ny >= 0 && ny < textureSize) { + float dist = distanceField.at(ny, nx) + + sqrtf((dx*dx + dy*dy) * step * step); + + if (dist < minDist) { + minDist = dist; + bestIdx = nearestFaceIdx.at(ny, nx); + } + } + } + } + + distanceField.at(y, x) = minDist; + nearestFaceIdx.at(y, x) = bestIdx; + } + } + } +}void FillTextureGaps(Image8U3& textureAtlas, const Mesh::TexCoordArr& faceTexcoords, + FIndex nFaces, const MeshTexture::LabelArr& faceLabels, + int textureSize, Pixel8U colEmpty) +{ + DEBUG_EXTRA("开始填充纹理间隙..."); + + // 创建距离场 + cv::Mat distanceField(textureSize, textureSize, CV_32FC1, cv::Scalar(std::numeric_limits::max())); + cv::Mat nearestPixelIdx(textureSize, textureSize, CV_32SC1, cv::Scalar(-1)); + + // 1. 初始化种子点(已有纹理的像素) + for (int y = 0; y < textureSize; ++y) { + for (int x = 0; x < textureSize; ++x) { + const Pixel8U& pixel = textureAtlas(y, x); + if (pixel[0] != colEmpty[0] || pixel[1] != colEmpty[1] || pixel[2] != colEmpty[2]) { + distanceField.at(y, x) = 0.0f; + nearestPixelIdx.at(y, x) = y * textureSize + x; + } + } + } + + // 2. 跳点传播算法 + for (int step = textureSize / 2; step >= 1; step /= 2) { + for (int y = 0; y < textureSize; ++y) { + for (int x = 0; x < textureSize; ++x) { + float minDist = distanceField.at(y, x); + int bestIdx = nearestPixelIdx.at(y, x); + + for (int dy = -1; dy <= 1; dy += 2) { + for (int dx = -1; dx <= 1; dx += 2) { + int nx = x + dx * step; + int ny = y + dy * step; + + if (nx >= 0 && nx < textureSize && ny >= 0 && ny < textureSize) { + float neighborDist = distanceField.at(ny, nx); + float dist = neighborDist + sqrtf((dx*dx + dy*dy) * step * step); + + if (dist < minDist && nearestPixelIdx.at(ny, nx) != -1) { + minDist = dist; + bestIdx = nearestPixelIdx.at(ny, nx); + } + } + } + } + + if (bestIdx != -1 && minDist < distanceField.at(y, x)) { + distanceField.at(y, x) = minDist; + nearestPixelIdx.at(y, x) = bestIdx; + } + } + } + } + + // 3. 填充空白区域 + const float maxFillDistance = 5.0f; + int filledCount = 0; + + for (int y = 0; y < textureSize; ++y) { + for (int x = 0; x < textureSize; ++x) { + Pixel8U& pixel = textureAtlas(y, x); + if (pixel[0] == colEmpty[0] && pixel[1] == colEmpty[1] && pixel[2] == colEmpty[2]) { + int nearestIdx = nearestPixelIdx.at(y, x); + float dist = distanceField.at(y, x); + + if (nearestIdx != -1 && dist <= maxFillDistance) { + int nx = nearestIdx % textureSize; + int ny = nearestIdx / textureSize; + pixel = textureAtlas(ny, nx); + filledCount++; + } + } + } + } + + DEBUG_EXTRA("快速填充完成,填充了 %d 个像素", filledCount); + + // // 4. 优化版图像修复 + // cv::Mat mask = cv::Mat::zeros(textureSize, textureSize, CV_8UC1); + // cv::Mat textureMat = textureAtlas; + + // // 使用OpenCV向量化操作 + // unsigned char r = colEmpty[0]; + // unsigned char g = colEmpty[1]; + // unsigned char b = colEmpty[2]; + + // #pragma omp parallel for + // for (int y = 0; y < textureSize; ++y) { + // unsigned char* maskRow = mask.ptr(y); + // const unsigned char* textureRow = textureMat.ptr(y); + + // for (int x = 0; x < textureSize; ++x) { + // int idx = x * 3; + // if (textureRow[idx] == r && + // textureRow[idx + 1] == g && + // textureRow[idx + 2] == b) { + // maskRow[x] = 255; + // } + // } + // } + + // if (cv::countNonZero(mask) > 0) { + // // 优化inpaint参数 + // int inpaintRadius = 2; // 减少修复半径 + // cv::Mat inpaintResult; + + // // 如果空白区域很少,使用更快的算法 + // double blankRatio = cv::countNonZero(mask) / (double)(textureSize * textureSize); + // if (blankRatio < 0.01) { // 空白区域少于1% + // // 使用快速修复 + // cv::dilate(textureMat, inpaintResult, cv::Mat()); + // inpaintResult.copyTo(textureAtlas, mask); + // } else { + // // 使用inpaint + // cv::inpaint(textureMat, mask, inpaintResult, inpaintRadius, cv::INPAINT_TELEA); + // inpaintResult.copyTo(textureAtlas); + // } + // } + DEBUG_EXTRA("纹理间隙填充完成"); } @@ -10089,8 +10296,7 @@ Mesh::Image8U3Arr MeshTexture::GenerateTextureAtlasFromUV(const LabelArr& faceLa } // 5. 添加后处理填充函数 - - FillTextureGaps(textureAtlas, scene.mesh.faceTexcoords, (FIndex)scene.mesh.faces.size(), faceLabels, views, textureSize, colEmpty); + FillTextureGaps(textureAtlas, scene.mesh.faceTexcoords, (FIndex)scene.mesh.faces.size(), faceLabels, textureSize, colEmpty); // 6. 应用后处理 if (fSharpnessWeight > 0) {