Browse Source

填色完成

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

562
libs/MVS/SceneTexture.cpp

@ -504,17 +504,26 @@ public: @@ -504,17 +504,26 @@ public:
const cv::Mat1f& weightAccum,
const cv::Mat1i& sampleCount,
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,
const cv::Mat1f& weightAccum);
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,
const cv::Mat1f& weightAccum,
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 ApplySharpening(Image8U3& image, float strength);
void ApplySharpening(cv::Mat& image, float strength);
void ApplyAutoWhiteBalance(cv::Mat& image, float strength);
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);
@ -9965,49 +9974,24 @@ Mesh::Image8U3Arr MeshTexture::GenerateMultiViewTextureAtlas( @@ -9965,49 +9974,24 @@ Mesh::Image8U3Arr MeshTexture::GenerateMultiViewTextureAtlas(
// 7. 第二次遍历:填充缝隙和未采样区域
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. 应用颜色校正和均匀化
// ApplyColorCorrection(textureAtlas, 0.5f); // 中等强度的颜色校正
// ApplyColorCorrection(textureMat, 0.5f); // 中等强度的颜色校正
// 9. 应用锐化
if (fSharpnessWeight > 0) {
// ApplySharpening(textureAtlas, fSharpnessWeight);
// ApplySharpening(textureMat, fSharpnessWeight);
}
DEBUG_EXTRA("Multi-view texture atlas generation complete");
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_,
const Point2f& pt2_,
@ -10085,7 +10069,6 @@ struct InpaintProgress { @@ -10085,7 +10069,6 @@ struct InpaintProgress {
std::exception_ptr exception{nullptr};
};
// 在函数内部实现进度监控
void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
const cv::Mat1i& sampleCount,
@ -10106,7 +10089,7 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas, @@ -10106,7 +10089,7 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
DEBUG_EXTRA("Starting gap filling for %dx%d texture", cols, rows);
// 1. 快速创建有效掩码
// 1. 创建有效掩码
cv::Mat1b validMask(rows, cols, (unsigned char)0);
int validPixels = 0;
@ -10127,14 +10110,28 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas, @@ -10127,14 +10110,28 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
validPixels, validRatio * 100.0f,
totalPixels - validPixels, (1.0f - validRatio) * 100.0f);
// 2. 快速形态学填充
if (validRatio > 0.7f) {
// 2. 使用距离变换填充小缝隙
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::Mat element3 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
cv::dilate(validMask, dilatedMask, element3);
int smallGapsFilled = 0;
#pragma omp parallel for schedule(static) reduction(+:smallGapsFilled)
int morphologyGapsFilled = 0;
#pragma omp parallel for schedule(static) reduction(+:morphologyGapsFilled)
for (int y = 0; y < rows; ++y) {
const unsigned char* dilatedRow = dilatedMask.ptr<unsigned char>(y);
const unsigned char* validRow = validMask.ptr<unsigned char>(y);
@ -10145,17 +10142,17 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas, @@ -10145,17 +10142,17 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
cv::Vec3b avgColor(0, 0, 0);
int count = 0;
for (int dy = -1; dy <= 1 && count < 2; ++dy) {
// 搜索更大的邻域
for (int dy = -2; dy <= 2; ++dy) {
int ny = y + dy;
if (ny < 0 || ny >= rows) continue;
const unsigned char* neighborMaskRow = validMask.ptr<unsigned char>(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;
if (nx < 0 || nx >= cols) continue;
if (dx == 0 && dy == 0) continue;
if (neighborMaskRow[nx]) {
avgColor += neighborTexRow[nx];
@ -10170,19 +10167,31 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas, @@ -10170,19 +10167,31 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
avgColor[1] / count,
avgColor[2] / count
);
smallGapsFilled++;
morphologyGapsFilled++;
}
}
}
}
DEBUG_EXTRA("Fast morphology filled %d small gaps", smallGapsFilled);
dilatedMask.copyTo(validMask);
DEBUG_EXTRA("Morphology filled %d small gaps", morphologyGapsFilled);
}
// 3. 识别剩余的大缝隙区域
cv::Mat1b remainingGaps = (validMask == 0);
int remainingGapArea = cv::countNonZero(remainingGaps);
// 4. 识别剩余的大缝隙区域
cv::Mat1b remainingGaps(rows, cols, (unsigned char)0);
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) {
DEBUG_EXTRA("No remaining gaps to fill");
@ -10192,89 +10201,326 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas, @@ -10192,89 +10201,326 @@ void MeshTexture::FillTextureGapsMultiView(cv::Mat& textureAtlas,
DEBUG_EXTRA("Remaining gaps: %d pixels (%.2f%% of total)",
remainingGapArea, static_cast<float>(remainingGapArea) / totalPixels * 100.0f);
// 4. 使用下采样加速
int downscaleFactor = 1;
cv::Mat downscaledAtlas, downscaledMask;
if (cols > 2048 || rows > 2048) {
downscaleFactor = 2;
cv::resize(textureAtlas, downscaledAtlas,
cv::Size(cols / downscaleFactor, rows / downscaleFactor),
0, 0, cv::INTER_LINEAR);
cv::resize(remainingGaps, downscaledMask,
cv::Size(cols / downscaleFactor, rows / downscaleFactor),
0, 0, cv::INTER_NEAREST);
cv::threshold(downscaledMask, downscaledMask, 127, 255, cv::THRESH_BINARY);
DEBUG_EXTRA("Downscaled image to %dx%d for faster processing",
cols / downscaleFactor, rows / downscaleFactor);
// 5. 分块inpaint处理大缝隙
DEBUG_EXTRA("Starting block-based inpainting for large gaps...");
// 创建用于inpaint的纹理副本
cv::Mat textureForInpaint = textureAtlas.clone();
// 分块inpaint
bool success = InpaintWithBlocks(textureForInpaint, remainingGaps, textureAtlas, 3, 256);
if (!success) {
DEBUG_EXTRA("Block-based inpaint failed, using advanced alternative...");
AdvancedGapFilling(textureAtlas, weightAccum, remainingGaps);
} else {
textureAtlas.copyTo(downscaledAtlas);
remainingGaps.copyTo(downscaledMask);
DEBUG_EXTRA("Block-based inpainting completed");
}
// 5. 使用分块inpaint
int inpaintRadius = 3;
DEBUG_EXTRA("Starting block-based inpainting (TELEA algorithm, radius=%d)...", inpaintRadius);
// 6. 最后检查并填充剩余的任何小缝隙
int finalGapsFilled = 0;
#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);
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) {
for (int dy = -radius; dy <= radius; ++dy) {
int ny = y + dy;
if (ny < 0 || ny >= rows) continue;
cv::Mat inpaintedDownscaled;
const float* neighborWeightRow = weightAccum.ptr<float>(ny);
const cv::Vec3b* neighborTexRow = textureAtlas.ptr<cv::Vec3b>(ny);
// 分块处理,避免卡住
bool success = InpaintWithBlocks(downscaledAtlas, downscaledMask, inpaintedDownscaled, inpaintRadius, 256);
for (int dx = -radius; dx <= radius; ++dx) {
int nx = x + dx;
if (nx < 0 || nx >= cols) continue;
if (dx == 0 && dy == 0) continue;
if (!success) {
DEBUG_EXTRA("Block-based inpaint failed, using fast alternative...");
FastAlternativeGapFilling(textureAtlas, weightAccum, validMask);
return;
if (neighborWeightRow[nx] > 0) {
avgColor += neighborTexRow[nx];
count++;
}
}
}
DEBUG_EXTRA("Block-based inpainting completed");
if (count > 0) {
textureRow[x] = cv::Vec3b(
avgColor[0] / count,
avgColor[1] / count,
avgColor[2] / count
);
finalGapsFilled++;
break;
}
}
}
}
}
}
// 6. 上采样结果
cv::Mat inpaintedFull;
if (downscaleFactor > 1) {
cv::resize(inpaintedDownscaled, inpaintedFull,
cv::Size(cols, rows), 0, 0, cv::INTER_LINEAR);
} else {
inpaintedDownscaled.copyTo(inpaintedFull);
if (finalGapsFilled > 0) {
DEBUG_EXTRA("Final pass filled %d remaining gaps", finalGapsFilled);
}
DEBUG_EXTRA("Total gap filling time: %s", TD_TIMER_GET_FMT().c_str());
}
// 辅助函数:使用距离变换加速最近邻填充
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::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;
}
}
// 7. 填充缝隙像素
// 使用最近有效像素的颜色
const cv::Point& nearest = validPoints[nearestIdx];
textureRow[x] = textureAtlas.at<cv::Vec3b>(nearest.y, nearest.x);
}
}
}
}
// 增强的距离变换填充函数
int MeshTexture::FillGapsByDistanceTransform(cv::Mat& textureAtlas,
const cv::Mat1f& weightAccum,
float maxDistance)
{
int rows = textureAtlas.rows;
int cols = textureAtlas.cols;
int filledPixels = 0;
int updateInterval = std::max(1, rows / 20);
int lastProgress = -1;
// 创建有效像素掩码
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) {
if (y % updateInterval == 0) {
int progress = static_cast<int>(100.0f * y / rows);
if (progress % 5 == 0 && progress != lastProgress) {
#pragma omp critical
{
if (progress != lastProgress) {
lastProgress = progress;
DEBUG_EXTRA("Gap filling progress: %d%%", progress);
const float* distRow = distance.ptr<float>(y);
const float* weightRow = weightAccum.ptr<float>(y);
cv::Vec3b* textureRow = textureAtlas.ptr<cv::Vec3b>(y);
for (int x = 0; x < cols; ++x) {
if (weightRow[x] <= 0 && (maxDistance <= 0 || distRow[x] <= maxDistance)) {
// 查找最近的有效像素
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++;
}
}
}
}
const unsigned char* gapRow = remainingGaps.ptr<unsigned char>(y);
return filledPixels;
}
// 高级缝隙填充方法
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);
const cv::Vec3b* inpaintRow = inpaintedFull.ptr<cv::Vec3b>(y);
for (int x = 0; x < cols; ++x) {
if (gapRow[x] && weightRow[x] <= 0) {
textureRow[x] = inpaintRow[x];
filledPixels++;
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++;
}
}
}
DEBUG_EXTRA("Texture gaps filled: %d pixels", filledPixels);
DEBUG_EXTRA("Total gap filling time: %s", TD_TIMER_GET_FMT().c_str());
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,
const cv::Mat1f& weightAccum,
const cv::Mat1b& validMask)
@ -10354,8 +10600,6 @@ void MeshTexture::FastAlternativeGapFilling(cv::Mat& textureAtlas, @@ -10354,8 +10600,6 @@ void MeshTexture::FastAlternativeGapFilling(cv::Mat& textureAtlas,
DEBUG_EXTRA("Fast alternative gap filling completed");
}
// 分块inpaint实现
bool MeshTexture::InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask,
cv::Mat& result, int radius, int blockSize)
{
@ -10409,55 +10653,6 @@ bool MeshTexture::InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask, @@ -10409,55 +10653,6 @@ bool MeshTexture::InpaintWithBlocks(cv::Mat& image, const cv::Mat1b& mask,
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)
{
if (strength <= 0) return;
@ -10465,8 +10660,6 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength) @@ -10465,8 +10660,6 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
DEBUG_EXTRA("Applying color correction (strength: %.2f)", strength);
TD_TIMER_START();
cv::Mat& imgMat = (cv::Mat&)image;
if (strength < 0.3f) {
// 轻微的颜色调整
ApplySimpleColorCorrection(image, strength);
@ -10475,7 +10668,7 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength) @@ -10475,7 +10668,7 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
// 1. 转换为LAB颜色空间进行更自然的颜色调整
cv::Mat labImage;
cv::cvtColor(imgMat, labImage, cv::COLOR_BGR2Lab);
cv::cvtColor(image, labImage, cv::COLOR_BGR2Lab);
// 分离通道
std::vector<cv::Mat> labChannels;
@ -10500,30 +10693,57 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength) @@ -10500,30 +10693,57 @@ void MeshTexture::ApplyColorCorrection(cv::Mat& image, float strength)
cv::merge(labChannels, labImage);
// 5. 转换回BGR
cv::cvtColor(labImage, imgMat, cv::COLOR_Lab2BGR);
cv::cvtColor(labImage, image, cv::COLOR_Lab2BGR);
// 6. 应用自动颜色平衡
ApplyAutoWhiteBalance(imgMat, strength * 0.5f);
ApplyAutoWhiteBalance(image, strength * 0.5f);
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;
DEBUG_EXTRA("Applying sharpening (strength: %.2f)", strength);
TD_TIMER_START();
cv::Mat& imgMat = (cv::Mat&)image;
// 1. 高斯模糊
cv::Mat blurred;
cv::GaussianBlur(imgMat, blurred, cv::Size(0, 0), 3);
cv::GaussianBlur(image, blurred, cv::Size(0, 0), 3);
// 2. 计算边缘掩码
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::convertScaleAbs(edges, edges);
@ -10532,13 +10752,13 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength) @@ -10532,13 +10752,13 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength)
cv::threshold(edges, sharpenMask, 10, 255, cv::THRESH_BINARY);
// 4. 对边缘区域应用反锐化掩蔽
cv::Mat sharpened = imgMat.clone();
cv::Mat sharpened = image.clone();
for (int y = 0; y < imgMat.rows; ++y) {
for (int x = 0; x < imgMat.cols; ++x) {
for (int y = 0; y < image.rows; ++y) {
for (int x = 0; x < image.cols; ++x) {
if (sharpenMask.at<uchar>(y, x) > 0) {
// 反锐化掩蔽公式: 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 sharpPixel;
@ -10554,7 +10774,7 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength) @@ -10554,7 +10774,7 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength)
}
// 5. 混合锐化后的图像
cv::addWeighted(imgMat, 1.0f - strength, sharpened, strength, 0, imgMat);
cv::addWeighted(image, 1.0f - strength, sharpened, strength, 0, image);
// 6. 可选的边缘增强
if (strength > 0.5f) {
@ -10562,7 +10782,7 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength) @@ -10562,7 +10782,7 @@ void MeshTexture::ApplySharpening(Image8U3& image, float strength)
-1, -1, -1,
-1, 9, -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());

Loading…
Cancel
Save