Browse Source

填色完成

ManualUV
hesuicong 2 weeks ago
parent
commit
992439bc44
  1. 588
      libs/MVS/SceneTexture.cpp

588
libs/MVS/SceneTexture.cpp

@ -500,21 +500,30 @@ public:
const cv::Point2f& b, const cv::Point2f& b,
const cv::Point2f& c); const cv::Point2f& c);
void FillTextureGapsMultiView(cv::Mat& textureAtlas, void FillTextureGapsMultiView(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum, const cv::Mat1f& weightAccum,
const cv::Mat1i& sampleCount, const cv::Mat1i& sampleCount,
Pixel8U colEmpty); Pixel8U colEmpty);
int FillGapsByDistanceTransform(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
float maxDistance);
void AdvancedGapFilling(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
const cv::Mat1b& gapMask);
void FillSmallGapsWithNearest(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
const cv::Rect& bbox);
void FillSmallGapsWithDistanceTransform(cv::Mat& textureAtlas, void FillSmallGapsWithDistanceTransform(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum); const cv::Mat1f& weightAccum);
bool InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask, bool InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask,
cv::Mat& result, int radius, int blockSize = 512); cv::Mat& result, int radius, int blockSize);
void FastAlternativeGapFilling(cv::Mat& textureAtlas, void FastAlternativeGapFilling(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum, const cv::Mat1f& weightAccum,
const cv::Mat1b& validMask); const cv::Mat1b& validMask);
void ApplySimpleColorCorrection(cv::Mat& imgMat, float strength); void ApplySimpleColorCorrection(cv::Mat& image, float strength);
void ApplyColorCorrection(cv::Mat& image, float strength); void ApplyColorCorrection(cv::Mat& image, float strength);
void ApplySharpening(Image8U3& image, float strength); void ApplySharpening(cv::Mat& image, float strength);
void ApplyAutoWhiteBalance(cv::Mat& image, float strength); void ApplyAutoWhiteBalance(cv::Mat& image, float strength);
Point2f ProjectPointWithAutoCorrection(const Camera& camera, const Vertex& worldPoint, const Image& sourceImage); Point2f ProjectPointWithAutoCorrection(const Camera& camera, const Vertex& worldPoint, const Image& sourceImage);
Point2f ProjectPointRobust(const Camera& camera, const Vertex& worldPoint, const Image& sourceImage, float searchRadius = 0.02f); Point2f ProjectPointRobust(const Camera& camera, const Vertex& worldPoint, const Image& sourceImage, float searchRadius = 0.02f);
@ -9963,51 +9972,26 @@ Mesh::Image8U3Arr MeshTexture::GenerateMultiViewTextureAtlas(
} }
} }
// 7. 第二次遍历:填充缝隙和未采样区域 // 7. 第二次遍历:填充缝隙和未采样区域
DEBUG_EXTRA("Filling gaps in texture atlas"); DEBUG_EXTRA("Filling gaps in texture atlas");
FillTextureGapsMultiView(textureAtlas, weightAccum, sampleCount, colEmpty); // 将 Image8U3 转换为 cv::Mat
cv::Mat textureMat = (cv::Mat&)textureAtlas;
cv::Mat1f weightMat = weightAccum;
cv::Mat1i sampleMat = sampleCount;
FillTextureGapsMultiView(textureMat, weightMat, sampleMat, colEmpty);
// 8. 应用颜色校正和均匀化 // 8. 应用颜色校正和均匀化
// ApplyColorCorrection(textureAtlas, 0.5f); // 中等强度的颜色校正 // ApplyColorCorrection(textureMat, 0.5f); // 中等强度的颜色校正
// 9. 应用锐化 // 9. 应用锐化
if (fSharpnessWeight > 0) { if (fSharpnessWeight > 0) {
// ApplySharpening(textureAtlas, fSharpnessWeight); // ApplySharpening(textureMat, fSharpnessWeight);
} }
DEBUG_EXTRA("Multi-view texture atlas generation complete"); DEBUG_EXTRA("Multi-view texture atlas generation complete");
return textures; return textures;
} }
void MeshTexture::ApplySimpleColorCorrection(cv::Mat& imgMat, float strength)
{
if (strength <= 0) return;
// 应用伽马校正
cv::Mat temp;
imgMat.convertTo(temp, CV_32FC3, 1.0/255.0);
// 调整对比度
cv::Mat adjusted = temp.clone();
float alpha = 1.0f + strength; // 对比度
float beta = -0.1f * strength; // 亮度调整
for (int y = 0; y < adjusted.rows; ++y) {
cv::Vec3f* row = adjusted.ptr<cv::Vec3f>(y);
for (int x = 0; x < adjusted.cols; ++x) {
row[x][0] = cv::saturate_cast<float>(alpha * row[x][0] + beta);
row[x][1] = cv::saturate_cast<float>(alpha * row[x][1] + beta);
row[x][2] = cv::saturate_cast<float>(alpha * row[x][2] + beta);
}
}
// 混合回原图
cv::addWeighted(temp, 1.0f - strength, adjusted, strength, 0.0, temp);
// 转换回8位
temp.convertTo(imgMat, CV_8UC3, 255.0);
}
// 获取三角形内的所有像素 // 获取三角形内的所有像素
std::vector<cv::Point> MeshTexture::GetPixelsInTriangle(const Point2f& pt1_, std::vector<cv::Point> MeshTexture::GetPixelsInTriangle(const Point2f& pt1_,
const Point2f& pt2_, const Point2f& pt2_,
@ -10085,7 +10069,6 @@ struct InpaintProgress {
std::exception_ptr exception{nullptr}; std::exception_ptr exception{nullptr};
}; };
// 在函数内部实现进度监控
void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas, void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum, const cv::Mat1f& weightAccum,
const cv::Mat1i& sampleCount, const cv::Mat1i& sampleCount,
@ -10106,7 +10089,7 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
DEBUG_EXTRA("Starting gap filling for %dx%d texture", cols, rows); DEBUG_EXTRA("Starting gap filling for %dx%d texture", cols, rows);
// 1. 快速创建有效掩码 // 1. 创建有效掩码
cv::Mat1b validMask(rows, cols, (unsigned char)0); cv::Mat1b validMask(rows, cols, (unsigned char)0);
int validPixels = 0; int validPixels = 0;
@ -10127,14 +10110,28 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
validPixels, validRatio * 100.0f, validPixels, validRatio * 100.0f,
totalPixels - validPixels, (1.0f - validRatio) * 100.0f); totalPixels - validPixels, (1.0f - validRatio) * 100.0f);
// 2. 快速形态学填充 // 2. 使用距离变换填充小缝隙
if (validRatio > 0.7f) { int smallGapsFilled = FillGapsByDistanceTransform(textureAtlas, weightAccum, 10.0f);
DEBUG_EXTRA("Distance transform filled %d small gaps (radius < 10)", smallGapsFilled);
// 3. 形态学填充扩展有效掩码
if (validRatio > 0.5f) { // 降低阈值,更多情况下使用形态学填充
// 更新有效掩码
#pragma omp parallel for schedule(static)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
unsigned char* maskRow = validMask.ptr<unsigned char>(y);
for (int x = 0; x < cols; ++x) {
maskRow[x] = (weightRow[x] > 0) ? 255 : 0;
}
}
cv::Mat1b dilatedMask; cv::Mat1b dilatedMask;
cv::Mat element3 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3)); cv::Mat element3 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
cv::dilate(validMask, dilatedMask, element3); cv::dilate(validMask, dilatedMask, element3);
int smallGapsFilled = 0; int morphologyGapsFilled = 0;
#pragma omp parallel for schedule(static) reduction(+:smallGapsFilled) #pragma omp parallel for schedule(static) reduction(+:morphologyGapsFilled)
for (int y = 0; y < rows; ++y) { for (int y = 0; y < rows; ++y) {
const unsigned char* dilatedRow = dilatedMask.ptr<unsigned char>(y); const unsigned char* dilatedRow = dilatedMask.ptr<unsigned char>(y);
const unsigned char* validRow = validMask.ptr<unsigned char>(y); const unsigned char* validRow = validMask.ptr<unsigned char>(y);
@ -10145,17 +10142,17 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
cv::Vec3b avgColor(0, 0, 0); cv::Vec3b avgColor(0, 0, 0);
int count = 0; int count = 0;
for (int dy = -1; dy <= 1 && count < 2; ++dy) { // 搜索更大的邻域
for (int dy = -2; dy <= 2; ++dy) {
int ny = y + dy; int ny = y + dy;
if (ny < 0 || ny >= rows) continue; if (ny < 0 || ny >= rows) continue;
const unsigned char* neighborMaskRow = validMask.ptr<unsigned char>(ny); const unsigned char* neighborMaskRow = validMask.ptr<unsigned char>(ny);
const cv::Vec3b* neighborTexRow = textureAtlas.ptr<cv::Vec3b>(ny); const cv::Vec3b* neighborTexRow = textureAtlas.ptr<cv::Vec3b>(ny);
for (int dx = -1; dx <= 1 && count < 2; ++dx) { for (int dx = -2; dx <= 2; ++dx) {
int nx = x + dx; int nx = x + dx;
if (nx < 0 || nx >= cols) continue; if (nx < 0 || nx >= cols) continue;
if (dx == 0 && dy == 0) continue;
if (neighborMaskRow[nx]) { if (neighborMaskRow[nx]) {
avgColor += neighborTexRow[nx]; avgColor += neighborTexRow[nx];
@ -10170,19 +10167,31 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
avgColor[1] / count, avgColor[1] / count,
avgColor[2] / count avgColor[2] / count
); );
smallGapsFilled++; morphologyGapsFilled++;
} }
} }
} }
} }
DEBUG_EXTRA("Fast morphology filled %d small gaps", smallGapsFilled); DEBUG_EXTRA("Morphology filled %d small gaps", morphologyGapsFilled);
dilatedMask.copyTo(validMask);
} }
// 3. 识别剩余的大缝隙区域 // 4. 识别剩余的大缝隙区域
cv::Mat1b remainingGaps = (validMask == 0); cv::Mat1b remainingGaps(rows, cols, (unsigned char)0);
int remainingGapArea = cv::countNonZero(remainingGaps); int remainingGapArea = 0;
#pragma omp parallel for schedule(static) reduction(+:remainingGapArea)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
unsigned char* gapRow = remainingGaps.ptr<unsigned char>(y);
for (int x = 0; x < cols; ++x) {
if (weightRow[x] <= 0) {
gapRow[x] = 255;
remainingGapArea++;
}
}
}
if (remainingGapArea == 0) { if (remainingGapArea == 0) {
DEBUG_EXTRA("No remaining gaps to fill"); DEBUG_EXTRA("No remaining gaps to fill");
@ -10192,89 +10201,326 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
DEBUG_EXTRA("Remaining gaps: %d pixels (%.2f%% of total)", DEBUG_EXTRA("Remaining gaps: %d pixels (%.2f%% of total)",
remainingGapArea, static_cast<float>(remainingGapArea) / totalPixels * 100.0f); remainingGapArea, static_cast<float>(remainingGapArea) / totalPixels * 100.0f);
// 4. 使用下采样加速 // 5. 分块inpaint处理大缝隙
int downscaleFactor = 1; DEBUG_EXTRA("Starting block-based inpainting for large gaps...");
cv::Mat downscaledAtlas, downscaledMask;
// 创建用于inpaint的纹理副本
if (cols > 2048 || rows > 2048) { cv::Mat textureForInpaint = textureAtlas.clone();
downscaleFactor = 2;
cv::resize(textureAtlas, downscaledAtlas, // 分块inpaint
cv::Size(cols / downscaleFactor, rows / downscaleFactor), bool success = InpaintWithBlocks(textureForInpaint, remainingGaps, textureAtlas, 3, 256);
0, 0, cv::INTER_LINEAR);
cv::resize(remainingGaps, downscaledMask, if (!success) {
cv::Size(cols / downscaleFactor, rows / downscaleFactor), DEBUG_EXTRA("Block-based inpaint failed, using advanced alternative...");
0, 0, cv::INTER_NEAREST); AdvancedGapFilling(textureAtlas, weightAccum, remainingGaps);
cv::threshold(downscaledMask, downscaledMask, 127, 255, cv::THRESH_BINARY);
DEBUG_EXTRA("Downscaled image to %dx%d for faster processing",
cols / downscaleFactor, rows / downscaleFactor);
} else { } else {
textureAtlas.copyTo(downscaledAtlas); DEBUG_EXTRA("Block-based inpainting completed");
remainingGaps.copyTo(downscaledMask);
} }
// 5. 使用分块inpaint // 6. 最后检查并填充剩余的任何小缝隙
int inpaintRadius = 3; int finalGapsFilled = 0;
DEBUG_EXTRA("Starting block-based inpainting (TELEA algorithm, radius=%d)...", inpaintRadius); #pragma omp parallel for schedule(static) reduction(+:finalGapsFilled)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
cv::Mat inpaintedDownscaled; for (int x = 0; x < cols; ++x) {
if (weightRow[x] <= 0) {
// 检查这个像素是否仍然是默认颜色
cv::Vec3b current = textureRow[x];
if (current[0] == 0 && current[1] == 0 && current[2] == 0) {
// 使用更大的邻域搜索
cv::Vec3b avgColor(0, 0, 0);
int count = 0;
// 分块处理,避免卡住 for (int radius = 1; radius <= 5; ++radius) {
bool success = InpaintWithBlocks(downscaledAtlas, downscaledMask, inpaintedDownscaled, inpaintRadius, 256); for (int dy = -radius; dy <= radius; ++dy) {
int ny = y + dy;
if (ny < 0 || ny >= rows) continue;
if (!success) { const float* neighborWeightRow = weightAccum.ptr<float>(ny);
DEBUG_EXTRA("Block-based inpaint failed, using fast alternative..."); const cv::Vec3b* neighborTexRow = textureAtlas.ptr<cv::Vec3b>(ny);
FastAlternativeGapFilling(textureAtlas, weightAccum, validMask);
return; for (int dx = -radius; dx <= radius; ++dx) {
int nx = x + dx;
if (nx < 0 || nx >= cols) continue;
if (dx == 0 && dy == 0) continue;
if (neighborWeightRow[nx] > 0) {
avgColor += neighborTexRow[nx];
count++;
}
}
}
if (count > 0) {
textureRow[x] = cv::Vec3b(
avgColor[0] / count,
avgColor[1] / count,
avgColor[2] / count
);
finalGapsFilled++;
break;
}
}
}
}
}
} }
DEBUG_EXTRA("Block-based inpainting completed"); if (finalGapsFilled > 0) {
DEBUG_EXTRA("Final pass filled %d remaining gaps", finalGapsFilled);
}
// 6. 上采样结果 DEBUG_EXTRA("Total gap filling time: %s", TD_TIMER_GET_FMT().c_str());
cv::Mat inpaintedFull; }
if (downscaleFactor > 1) {
cv::resize(inpaintedDownscaled, inpaintedFull, // 辅助函数:使用距离变换加速最近邻填充
cv::Size(cols, rows), 0, 0, cv::INTER_LINEAR); void MeshTexture::FillSmallGapsWithDistanceTransform(cv::Mat& textureAtlas,
} else { const cv::Mat1f& weightAccum)
inpaintedDownscaled.copyTo(inpaintedFull); {
int rows = textureAtlas.rows;
int cols = textureAtlas.cols;
// 创建有效像素掩码
cv::Mat1b validMask(rows, cols, (unsigned char)0);
#pragma omp parallel for schedule(static)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
unsigned char* maskRow = validMask.ptr<unsigned char>(y);
for (int x = 0; x < cols; ++x) {
maskRow[x] = (weightRow[x] > 0) ? 255 : 0;
}
} }
// 7. 填充缝隙像素 // 计算距离变换
int filledPixels = 0; cv::Mat distance;
int updateInterval = std::max(1, rows / 20); cv::distanceTransform(~validMask, distance, cv::DIST_L2, cv::DIST_MASK_PRECISE, CV_32F);
int lastProgress = -1;
#pragma omp parallel for schedule(static) reduction(+:filledPixels) // 找到最近的有效像素
cv::Mat nearestLabels;
cv::distanceTransform(~validMask, nearestLabels, cv::DIST_L2, cv::DIST_MASK_PRECISE, CV_32S);
// 填充缝隙
#pragma omp parallel for schedule(static)
for (int y = 0; y < rows; ++y) { for (int y = 0; y < rows; ++y) {
if (y % updateInterval == 0) { const float* distRow = distance.ptr<float>(y);
int progress = static_cast<int>(100.0f * y / rows); const int* labelRow = nearestLabels.ptr<int>(y);
if (progress % 5 == 0 && progress != lastProgress) { cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
#pragma omp critical const float* weightRow = weightAccum.ptr<float>(y);
{
if (progress != lastProgress) { for (int x = 0; x < cols; ++x) {
lastProgress = progress; if (weightRow[x] <= 0 && distRow[x] > 0 && distRow[x] < 10) { // 只填充距离小于10的缝隙
DEBUG_EXTRA("Gap filling progress: %d%%", progress); int nearestIdx = labelRow[x];
int nearestY = nearestIdx / cols;
int nearestX = nearestIdx % cols;
if (nearestY >= 0 && nearestY < rows && nearestX >= 0 && nearestX < cols) {
textureRow[x] = textureAtlas.at<cv::Vec3b>(nearestY, nearestX);
}
}
}
}
}
// 辅助函数:使用最近有效像素填充小缝隙
void MeshTexture::FillSmallGapsWithNearest(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
const cv::Rect& bbox)
{
int rows = textureAtlas.rows;
int cols = textureAtlas.cols;
// 限制边界
int x1 = std::max(0, bbox.x);
int y1 = std::max(0, bbox.y);
int x2 = std::min(cols, bbox.x + bbox.width);
int y2 = std::min(rows, bbox.y + bbox.height);
// 查找区域内所有有效像素的位置
std::vector<cv::Point> validPoints;
for (int y = y1; y < y2; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
for (int x = x1; x < x2; ++x) {
if (weightRow[x] > 0) {
validPoints.emplace_back(x, y);
}
}
}
if (validPoints.empty()) return;
// 对每个缝隙像素,使用最近的有效像素颜色
for (int y = y1; y < y2; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
for (int x = x1; x < x2; ++x) {
if (weightRow[x] <= 0) { // 是缝隙像素
// 找到最近的有效像素
int nearestIdx = 0;
float minDist = std::numeric_limits<float>::max();
for (size_t i = 0; i < validPoints.size(); ++i) {
int dx = validPoints[i].x - x;
int dy = validPoints[i].y - y;
float dist = dx*dx + dy*dy; // 平方距离
if (dist < minDist) {
minDist = dist;
nearestIdx = i;
} }
} }
// 使用最近有效像素的颜色
const cv::Point& nearest = validPoints[nearestIdx];
textureRow[x] = textureAtlas.at<cv::Vec3b>(nearest.y, nearest.x);
} }
} }
}
}
const unsigned char* gapRow = remainingGaps.ptr<unsigned char>(y); // 增强的距离变换填充函数
int MeshTexture::FillGapsByDistanceTransform(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
float maxDistance)
{
int rows = textureAtlas.rows;
int cols = textureAtlas.cols;
int filledPixels = 0;
// 创建有效像素掩码
cv::Mat1b validMask(rows, cols, (unsigned char)0);
#pragma omp parallel for schedule(static)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
unsigned char* maskRow = validMask.ptr<unsigned char>(y);
for (int x = 0; x < cols; ++x) {
maskRow[x] = (weightRow[x] > 0) ? 255 : 0;
}
}
// 计算距离变换
cv::Mat distance;
cv::Mat labels;
cv::distanceTransform(~validMask, distance, cv::DIST_L2, cv::DIST_MASK_PRECISE, CV_32F);
// 使用更精确的方法找到最近邻
#pragma omp parallel for schedule(static) reduction(+:filledPixels)
for (int y = 0; y < rows; ++y) {
const float* distRow = distance.ptr<float>(y);
const float* weightRow = weightAccum.ptr<float>(y); const float* weightRow = weightAccum.ptr<float>(y);
cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y); cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
const cv::Vec3b* inpaintRow = inpaintedFull.ptr<cv::Vec3b>(y);
for (int x = 0; x < cols; ++x) { for (int x = 0; x < cols; ++x) {
if (gapRow[x] && weightRow[x] <= 0) { if (weightRow[x] <= 0 && (maxDistance <= 0 || distRow[x] <= maxDistance)) {
textureRow[x] = inpaintRow[x]; // 查找最近的有效像素
filledPixels++; float minDist = FLT_MAX;
int bestY = -1, bestX = -1;
// 搜索范围基于距离
int searchRadius = std::min(std::max(1, static_cast<int>(distRow[x])), 20);
int startY = std::max(0, y - searchRadius);
int endY = std::min(rows - 1, y + searchRadius);
int startX = std::max(0, x - searchRadius);
int endX = std::min(cols - 1, x + searchRadius);
for (int ny = startY; ny <= endY; ++ny) {
const float* neighborWeightRow = weightAccum.ptr<float>(ny);
const cv::Vec3b* neighborTexRow = textureAtlas.ptr<cv::Vec3b>(ny);
for (int nx = startX; nx <= endX; ++nx) {
if (neighborWeightRow[nx] > 0) {
float dx = static_cast<float>(nx - x);
float dy = static_cast<float>(ny - y);
float dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
bestY = ny;
bestX = nx;
}
}
}
}
if (bestY != -1 && bestX != -1) {
textureRow[x] = textureAtlas.at<cv::Vec3b>(bestY, bestX);
filledPixels++;
}
} }
} }
} }
DEBUG_EXTRA("Texture gaps filled: %d pixels", filledPixels); return filledPixels;
DEBUG_EXTRA("Total gap filling time: %s", TD_TIMER_GET_FMT().c_str());
} }
// 高级缝隙填充方法
void MeshTexture::AdvancedGapFilling(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
const cv::Mat1b& gapMask)
{
int rows = textureAtlas.rows;
int cols = textureAtlas.cols;
int filledPixels = 0;
// 多次迭代,逐渐扩大搜索范围
for (int iteration = 0; iteration < 3; ++iteration) {
int iterationFilled = 0;
int searchRadius = 1 + iteration * 2; // 1, 3, 5
#pragma omp parallel for schedule(static) reduction(+:iterationFilled)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
const unsigned char* gapRow = gapMask.ptr<unsigned char>(y);
cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
for (int x = 0; x < cols; ++x) {
if (gapRow[x] == 255 && weightRow[x] <= 0) {
cv::Vec3b avgColor(0, 0, 0);
int count = 0;
for (int dy = -searchRadius; dy <= searchRadius; ++dy) {
int ny = y + dy;
if (ny < 0 || ny >= rows) continue;
const float* neighborWeightRow = weightAccum.ptr<float>(ny);
const cv::Vec3b* neighborTexRow = textureAtlas.ptr<cv::Vec3b>(ny);
for (int dx = -searchRadius; dx <= searchRadius; ++dx) {
int nx = x + dx;
if (nx < 0 || nx >= cols) continue;
if (dx == 0 && dy == 0) continue;
if (neighborWeightRow[nx] > 0) {
avgColor += neighborTexRow[nx];
count++;
}
}
}
if (count > 0) {
textureRow[x] = cv::Vec3b(
avgColor[0] / count,
avgColor[1] / count,
avgColor[2] / count
);
iterationFilled++;
}
}
}
}
filledPixels += iterationFilled;
DEBUG_EXTRA("Advanced filling iteration %d: filled %d pixels (radius=%d)",
iteration + 1, iterationFilled, searchRadius);
if (iterationFilled == 0) break;
}
DEBUG_EXTRA("Advanced gap filling completed, total filled: %d pixels", filledPixels);
}
void MeshTexture::FastAlternativeGapFilling(cv::Mat& textureAtlas, void MeshTexture::FastAlternativeGapFilling(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum, const cv::Mat1f& weightAccum,
const cv::Mat1b& validMask) const cv::Mat1b& validMask)
@ -10354,8 +10600,6 @@ void MeshTexture::FastAlternativeGapFilling(cv::Mat& textureAtlas,
DEBUG_EXTRA("Fast alternative gap filling completed"); DEBUG_EXTRA("Fast alternative gap filling completed");
} }
// 分块inpaint实现
bool MeshTexture::InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask, bool MeshTexture::InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask,
cv::Mat& result, int radius, int blockSize) cv::Mat& result, int radius, int blockSize)
{ {
@ -10409,55 +10653,6 @@ bool MeshTexture::InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask,
return true; return true;
} }
// 辅助函数:使用距离变换加速最近邻填充
void MeshTexture::FillSmallGapsWithDistanceTransform(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum)
{
int rows = textureAtlas.rows;
int cols = textureAtlas.cols;
// 创建有效像素掩码
cv::Mat1b validMask(rows, cols, (unsigned char)0);
#pragma omp parallel for schedule(static)
for (int y = 0; y < rows; ++y) {
const float* weightRow = weightAccum.ptr<float>(y);
unsigned char* maskRow = validMask.ptr<unsigned char>(y);
for (int x = 0; x < cols; ++x) {
maskRow[x] = (weightRow[x] > 0) ? 255 : 0;
}
}
// 计算距离变换
cv::Mat distance;
cv::distanceTransform(~validMask, distance, cv::DIST_L2, cv::DIST_MASK_PRECISE, CV_32F);
// 找到最近的有效像素
cv::Mat nearestLabels;
cv::distanceTransform(~validMask, nearestLabels, cv::DIST_L2, cv::DIST_MASK_PRECISE, CV_32S);
// 填充缝隙
#pragma omp parallel for schedule(static)
for (int y = 0; y < rows; ++y) {
const float* distRow = distance.ptr<float>(y);
const int* labelRow = nearestLabels.ptr<int>(y);
cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
const float* weightRow = weightAccum.ptr<float>(y);
for (int x = 0; x < cols; ++x) {
if (weightRow[x] <= 0 && distRow[x] > 0 && distRow[x] < 10) { // 只填充距离小于10的缝隙
int nearestIdx = labelRow[x];
int nearestY = nearestIdx / cols;
int nearestX = nearestIdx % cols;
if (nearestY >= 0 && nearestY < rows && nearestX >= 0 && nearestX < cols) {
textureRow[x] = textureAtlas.at<cv::Vec3b>(nearestY, nearestX);
}
}
}
}
}
// 颜色校正函数
void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength) void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
{ {
if (strength <= 0) return; if (strength <= 0) return;
@ -10465,8 +10660,6 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
DEBUG_EXTRA("Applying color correction (strength: %.2f)", strength); DEBUG_EXTRA("Applying color correction (strength: %.2f)", strength);
TD_TIMER_START(); TD_TIMER_START();
cv::Mat& imgMat = (cv::Mat&)image;
if (strength < 0.3f) { if (strength < 0.3f) {
// 轻微的颜色调整 // 轻微的颜色调整
ApplySimpleColorCorrection(image, strength); ApplySimpleColorCorrection(image, strength);
@ -10475,7 +10668,7 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
// 1. 转换为LAB颜色空间进行更自然的颜色调整 // 1. 转换为LAB颜色空间进行更自然的颜色调整
cv::Mat labImage; cv::Mat labImage;
cv::cvtColor(imgMat, labImage, cv::COLOR_BGR2Lab); cv::cvtColor(image, labImage, cv::COLOR_BGR2Lab);
// 分离通道 // 分离通道
std::vector<cv::Mat> labChannels; std::vector<cv::Mat> labChannels;
@ -10500,30 +10693,57 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
cv::merge(labChannels, labImage); cv::merge(labChannels, labImage);
// 5. 转换回BGR // 5. 转换回BGR
cv::cvtColor(labImage, imgMat, cv::COLOR_Lab2BGR); cv::cvtColor(labImage, image, cv::COLOR_Lab2BGR);
// 6. 应用自动颜色平衡 // 6. 应用自动颜色平衡
ApplyAutoWhiteBalance(imgMat, strength * 0.5f); ApplyAutoWhiteBalance(image, strength * 0.5f);
DEBUG_EXTRA("Color correction completed in %s", TD_TIMER_GET_FMT().c_str()); DEBUG_EXTRA("Color correction completed in %s", TD_TIMER_GET_FMT().c_str());
} }
void MeshTexture::ApplySharpening(Image8U3& image, float strength) void MeshTexture::ApplySimpleColorCorrection(cv::Mat& image, float strength)
{
if (strength <= 0) return;
// 应用伽马校正
cv::Mat temp;
image.convertTo(temp, CV_32FC3, 1.0/255.0);
// 调整对比度
cv::Mat adjusted = temp.clone();
float alpha = 1.0f + strength; // 对比度
float beta = -0.1f * strength; // 亮度调整
for (int y = 0; y < adjusted.rows; ++y) {
cv::Vec3f* row = adjusted.ptr<cv::Vec3f>(y);
for (int x = 0; x < adjusted.cols; ++x) {
row[x][0] = cv::saturate_cast<float>(alpha * row[x][0] + beta);
row[x][1] = cv::saturate_cast<float>(alpha * row[x][1] + beta);
row[x][2] = cv::saturate_cast<float>(alpha * row[x][2] + beta);
}
}
// 混合回原图
cv::addWeighted(temp, 1.0f - strength, adjusted, strength, 0.0, temp);
// 转换回8位
temp.convertTo(image, CV_8UC3, 255.0);
}
void MeshTexture::ApplySharpening(cv::Mat& image, float strength)
{ {
if (strength <= 0) return; if (strength <= 0) return;
DEBUG_EXTRA("Applying sharpening (strength: %.2f)", strength); DEBUG_EXTRA("Applying sharpening (strength: %.2f)", strength);
TD_TIMER_START(); TD_TIMER_START();
cv::Mat& imgMat = (cv::Mat&)image;
// 1. 高斯模糊 // 1. 高斯模糊
cv::Mat blurred; cv::Mat blurred;
cv::GaussianBlur(imgMat, blurred, cv::Size(0, 0), 3); cv::GaussianBlur(image, blurred, cv::Size(0, 0), 3);
// 2. 计算边缘掩码 // 2. 计算边缘掩码
cv::Mat gray, edges; cv::Mat gray, edges;
cv::cvtColor(imgMat, gray, cv::COLOR_BGR2GRAY); cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::Laplacian(gray, edges, CV_16S, 3); cv::Laplacian(gray, edges, CV_16S, 3);
cv::convertScaleAbs(edges, edges); cv::convertScaleAbs(edges, edges);
@ -10532,13 +10752,13 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength)
cv::threshold(edges, sharpenMask, 10, 255, cv::THRESH_BINARY); cv::threshold(edges, sharpenMask, 10, 255, cv::THRESH_BINARY);
// 4. 对边缘区域应用反锐化掩蔽 // 4. 对边缘区域应用反锐化掩蔽
cv::Mat sharpened = imgMat.clone(); cv::Mat sharpened = image.clone();
for (int y = 0; y < imgMat.rows; ++y) { for (int y = 0; y < image.rows; ++y) {
for (int x = 0; x < imgMat.cols; ++x) { for (int x = 0; x < image.cols; ++x) {
if (sharpenMask.at<uchar>(y, x) > 0) { if (sharpenMask.at<uchar>(y, x) > 0) {
// 反锐化掩蔽公式: sharpened = original + (original - blurred) * strength // 反锐化掩蔽公式: sharpened = original + (original - blurred) * strength
cv::Vec3b origPixel = imgMat.at<cv::Vec3b>(y, x); cv::Vec3b origPixel = image.at<cv::Vec3b>(y, x);
cv::Vec3b blurPixel = blurred.at<cv::Vec3b>(y, x); cv::Vec3b blurPixel = blurred.at<cv::Vec3b>(y, x);
cv::Vec3b sharpPixel; cv::Vec3b sharpPixel;
@ -10554,7 +10774,7 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength)
} }
// 5. 混合锐化后的图像 // 5. 混合锐化后的图像
cv::addWeighted(imgMat, 1.0f - strength, sharpened, strength, 0, imgMat); cv::addWeighted(image, 1.0f - strength, sharpened, strength, 0, image);
// 6. 可选的边缘增强 // 6. 可选的边缘增强
if (strength > 0.5f) { if (strength > 0.5f) {
@ -10562,7 +10782,7 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength)
-1, -1, -1, -1, -1, -1,
-1, 9, -1, -1, 9, -1,
-1, -1, -1); -1, -1, -1);
cv::filter2D(imgMat, imgMat, -1, kernel); cv::filter2D(image, image, -1, kernel);
} }
DEBUG_EXTRA("Sharpening completed in %s", TD_TIMER_GET_FMT().c_str()); DEBUG_EXTRA("Sharpening completed in %s", TD_TIMER_GET_FMT().c_str());

Loading…
Cancel
Save