优化性能
This commit is contained in:
1 parent
e1258c2d3e
commit
aadfbb4b08
1 file changed
+209
-3
+209
-3
@@ -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<std::vector<FIndex>> 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<FIndex>& GetTrianglesInCell(int x, int y) const {
|
||||
return grid[y * gridSize + x];
|
||||
}
|
||||
};
|
||||
|
||||
void GenerateDistanceFieldFast(cv::Mat& distanceField, cv::Mat& nearestFaceIdx,
|
||||
const std::vector<cv::Point>& seedPoints,
|
||||
int textureSize) {
|
||||
// 使用跳点传播算法
|
||||
distanceField = cv::Mat::zeros(textureSize, textureSize, CV_32FC1);
|
||||
nearestFaceIdx = cv::Mat::zeros(textureSize, textureSize, CV_32SC1);
|
||||
|
||||
// 初始化距离场
|
||||
distanceField.setTo(std::numeric_limits<float>::max());
|
||||
|
||||
// 标记种子点
|
||||
for (const auto& pt : seedPoints) {
|
||||
distanceField.at<float>(pt) = 0;
|
||||
nearestFaceIdx.at<int>(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<float>(y, x);
|
||||
int bestIdx = nearestFaceIdx.at<int>(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<float>(ny, nx) +
|
||||
sqrtf((dx*dx + dy*dy) * step * step);
|
||||
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
bestIdx = nearestFaceIdx.at<int>(ny, nx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
distanceField.at<float>(y, x) = minDist;
|
||||
nearestFaceIdx.at<int>(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<float>::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<float>(y, x) = 0.0f;
|
||||
nearestPixelIdx.at<int>(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<float>(y, x);
|
||||
int bestIdx = nearestPixelIdx.at<int>(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<float>(ny, nx);
|
||||
float dist = neighborDist + sqrtf((dx*dx + dy*dy) * step * step);
|
||||
|
||||
if (dist < minDist && nearestPixelIdx.at<int>(ny, nx) != -1) {
|
||||
minDist = dist;
|
||||
bestIdx = nearestPixelIdx.at<int>(ny, nx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestIdx != -1 && minDist < distanceField.at<float>(y, x)) {
|
||||
distanceField.at<float>(y, x) = minDist;
|
||||
nearestPixelIdx.at<int>(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<int>(y, x);
|
||||
float dist = distanceField.at<float>(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<unsigned char>(y);
|
||||
// const unsigned char* textureRow = textureMat.ptr<unsigned char>(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) {
|
||||
|
||||
Reference in new issue
Block a user