回退
This commit is contained in:
1 parent
b8f2e18fd3
commit
04495f3426
1 file changed
+32
-237
+32
-237
@@ -672,21 +672,6 @@ public:
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
struct ViewColorStats {
|
||||
double sumR = 0, sumG = 0, sumB = 0;
|
||||
int pixelCount = 0;
|
||||
bool valid = false;
|
||||
double gainR = 1.0, gainG = 1.0, gainB = 1.0;
|
||||
};
|
||||
|
||||
std::vector<ViewColorStats> m_viewStats;
|
||||
cv::Mat m_atlasViewMap; // CV_32SC1: 记录 atlas 每个像素的视图ID
|
||||
bool m_colorCorrectionReady = false;
|
||||
|
||||
// ===== 替换/添加这些函数声明 =====
|
||||
bool ComputeViewColorStatsDuringRasterization();
|
||||
void ApplyColorCorrectionToAtlas(Image8U3& atlas);
|
||||
|
||||
void FeatherSeams(
|
||||
const std::vector<SeamInfo>& seams,
|
||||
int textureSize,
|
||||
@@ -14312,16 +14297,6 @@ bool MeshTexture::RasterizeVirtualFaces(
|
||||
Image8U3& atlas = outTextures.back();
|
||||
atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
|
||||
|
||||
// ✅ 初始化视图颜色统计
|
||||
m_viewStats.resize(images.size());
|
||||
for (auto& s : m_viewStats) {
|
||||
s.sumR = s.sumG = s.sumB = 0;
|
||||
s.pixelCount = 0;
|
||||
s.valid = false;
|
||||
s.gainR = s.gainG = s.gainB = 1.0;
|
||||
}
|
||||
m_colorCorrectionReady = false;
|
||||
|
||||
// ✅ 初始化评分缓冲
|
||||
m_texelScores.assign(textureSize * textureSize, TexelScore{});
|
||||
|
||||
@@ -14397,10 +14372,14 @@ bool MeshTexture::RasterizeVirtualFaces(
|
||||
cv::INTER_LINEAR, cv::BORDER_CONSTANT,
|
||||
cv::Scalar(0, 0, 0));
|
||||
|
||||
// ✅ 拷贝到 atlas(OpenMP critical 区)
|
||||
#pragma omp critical
|
||||
{
|
||||
for (int y = 0; y < patchH; ++y) {
|
||||
for (int x = 0; x < patchW; ++x) {
|
||||
// 在 RasterizeVirtualFaces 的像素写入循环中
|
||||
// ✅ 只保留最核心的逻辑,不做任何衰减
|
||||
|
||||
cv::Vec3b color = patch.at<cv::Vec3b>(y, x);
|
||||
if (color[0] == 0 && color[1] == 0 && color[2] == 0)
|
||||
continue;
|
||||
@@ -14418,32 +14397,12 @@ bool MeshTexture::RasterizeVirtualFaces(
|
||||
? -1.0f
|
||||
: virtualFaceViewWeights[i][0];
|
||||
|
||||
// ✅ 统计:这个视图贡献了什么颜色(无论是否最终写入)
|
||||
if (viewID >= 0 && viewID < (IIndex)m_viewStats.size()) {
|
||||
ViewColorStats& vs = m_viewStats[viewID];
|
||||
vs.sumR += color[2]; // OpenMVS 内部是 BGR 顺序
|
||||
vs.sumG += color[1];
|
||||
vs.sumB += color[0];
|
||||
vs.pixelCount++;
|
||||
}
|
||||
|
||||
// ✅ 写入 atlas(评分高的赢)
|
||||
// ✅ 正常写入,不衰减,不修改
|
||||
if (currentScore > ts.score) {
|
||||
atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]};
|
||||
atlas(atlasY, atlasX) =
|
||||
Pixel8U{color[2], color[1], color[0]};
|
||||
ts.score = currentScore;
|
||||
ts.viewID = viewID;
|
||||
|
||||
// ✅ 关键修复:如果 view map 为空,立即创建
|
||||
if (m_atlasViewMap.empty()) {
|
||||
DEBUG_EXTRA("Creating m_atlasViewMap on demand: %d x %d", textureSize, textureSize);
|
||||
m_atlasViewMap = cv::Mat::zeros(textureSize, textureSize, CV_32SC1);
|
||||
}
|
||||
|
||||
// ✅ 再次检查边界(防御性编程)
|
||||
if (atlasY >= 0 && atlasY < m_atlasViewMap.rows &&
|
||||
atlasX >= 0 && atlasX < m_atlasViewMap.cols) {
|
||||
m_atlasViewMap.at<int>(atlasY, atlasX) = viewID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14453,201 +14412,37 @@ bool MeshTexture::RasterizeVirtualFaces(
|
||||
m_texelScores.clear();
|
||||
|
||||
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
|
||||
|
||||
// ============================================================
|
||||
// ✅ 视图级颜色校正(核心新增)
|
||||
// ============================================================
|
||||
{
|
||||
TD_TIMER_START();
|
||||
DEBUG_EXTRA("Computing view-level color statistics...");
|
||||
|
||||
// ---- 1. 计算每个视图的平均颜色 ----
|
||||
int totalValidViews = 0;
|
||||
double globalR = 0, globalG = 0, globalB = 0;
|
||||
int totalPixels = 0;
|
||||
|
||||
for (size_t vid = 0; vid < m_viewStats.size(); ++vid) {
|
||||
ViewColorStats& vs = m_viewStats[vid];
|
||||
if (vs.pixelCount > 50) { // 至少50个像素就认为有效
|
||||
vs.sumR /= vs.pixelCount;
|
||||
vs.sumG /= vs.pixelCount;
|
||||
vs.sumB /= vs.pixelCount;
|
||||
vs.valid = true;
|
||||
|
||||
globalR += vs.sumR * vs.pixelCount;
|
||||
globalG += vs.sumG * vs.pixelCount;
|
||||
globalB += vs.sumB * vs.pixelCount;
|
||||
totalPixels += vs.pixelCount;
|
||||
totalValidViews++;
|
||||
|
||||
DEBUG_EXTRA("View %zu: %d pixels, avgRGB=(%.1f,%.1f,%.1f)",
|
||||
vid, vs.pixelCount, vs.sumR, vs.sumG, vs.sumB);
|
||||
}
|
||||
}
|
||||
|
||||
if (totalValidViews < 2) {
|
||||
DEBUG_EXTRA("Only %d valid views, skipping color correction", totalValidViews);
|
||||
} else {
|
||||
// ---- 2. 计算全局平均颜色 ----
|
||||
globalR /= totalPixels;
|
||||
globalG /= totalPixels;
|
||||
globalB /= totalPixels;
|
||||
|
||||
DEBUG_EXTRA("Global avgRGB=(%.1f,%.1f,%.1f) from %d views, %d pixels",
|
||||
globalR, globalG, globalB, totalValidViews, totalPixels);
|
||||
|
||||
// ---- 3. 计算每个视图的增益 ----
|
||||
for (auto& vs : m_viewStats) {
|
||||
if (!vs.valid) continue;
|
||||
vs.gainR = globalR / (vs.sumR + 1e-6);
|
||||
vs.gainG = globalG / (vs.sumG + 1e-6);
|
||||
vs.gainB = globalB / (vs.sumB + 1e-6);
|
||||
|
||||
// 限制增益范围,防止极端值
|
||||
vs.gainR = std::max(0.5, std::min(2.0, vs.gainR));
|
||||
vs.gainG = std::max(0.5, std::min(2.0, vs.gainG));
|
||||
vs.gainB = std::max(0.5, std::min(2.0, vs.gainB));
|
||||
}
|
||||
|
||||
m_colorCorrectionReady = true;
|
||||
|
||||
// ---- 4. 应用颜色校正到 atlas ----
|
||||
DEBUG_EXTRA("Applying color correction to atlas...");
|
||||
for (int y = 0; y < textureSize; ++y) {
|
||||
for (int x = 0; x < textureSize; ++x) {
|
||||
cv::Vec3b& p = atlas.at<cv::Vec3b>(y, x);
|
||||
if (p[0] == 0 && p[1] == 0 && p[2] == 0) continue;
|
||||
|
||||
// 我们需要每个像素的视图ID → 用 ts.viewID
|
||||
// 但 m_texelScores 已经 clear 了
|
||||
// 所以这里用另一种方式:根据颜色反推增益
|
||||
// 更简单:重新遍历,用 m_texelScores 之前的值
|
||||
// → 改为:不 clear m_texelScores,或者另外存一份 viewID map
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Color correction completed: %s", TD_TIMER_GET_FMT().c_str());
|
||||
}
|
||||
|
||||
// 清理
|
||||
for (auto& s : m_viewStats) {
|
||||
s.sumR = s.sumG = s.sumB = 0;
|
||||
s.pixelCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Atlas size: %d x %d", atlas.rows, atlas.cols);
|
||||
DEBUG_EXTRA("View map size: %d x %d", m_atlasViewMap.rows, m_atlasViewMap.cols);
|
||||
if (atlas.rows != m_atlasViewMap.rows || atlas.cols != m_atlasViewMap.cols) {
|
||||
DEBUG_EXTRA("FATAL: Size mismatch!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// ✅ 接缝局部颜色混合(Local Color Blending)
|
||||
// ============================================================
|
||||
{
|
||||
|
||||
// ✅ 新增:接缝融合后处理
|
||||
if (true) { // 可配置开关
|
||||
TD_TIMER_START();
|
||||
DEBUG_EXTRA("Applying local color blending on seams...");
|
||||
|
||||
const int blendRadius = 3;
|
||||
|
||||
// 1. 计算接缝 mask(用 m_atlasViewMap)
|
||||
cv::Mat seamMask = cv::Mat::zeros(textureSize, textureSize, CV_8UC1);
|
||||
for (int y = 1; y < textureSize - 1; ++y) {
|
||||
for (int x = 1; x < textureSize - 1; ++x) {
|
||||
int vid = m_atlasViewMap.at<int>(y, x);
|
||||
if (vid <= 0) continue;
|
||||
|
||||
int nb[4] = {
|
||||
m_atlasViewMap.at<int>(y-1, x),
|
||||
m_atlasViewMap.at<int>(y+1, x),
|
||||
m_atlasViewMap.at<int>(y, x-1),
|
||||
m_atlasViewMap.at<int>(y, x+1)
|
||||
};
|
||||
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
if (nb[k] > 0 && nb[k] != vid) {
|
||||
seamMask.at<uchar>(y, x) = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 检测需要融合的接缝
|
||||
std::vector<SeamInfo> seams;
|
||||
if (!DetectSeamsForBlending(virtualFaceMap, virtualFaceViews, seams)) {
|
||||
DEBUG_EXTRA("Seam detection failed");
|
||||
return true; // 不影响主流程
|
||||
}
|
||||
// // 2. 方向性高斯羽化
|
||||
// FeatherSeams(seams, textureSize, atlas);
|
||||
|
||||
int seamCount = cv::countNonZero(seamMask);
|
||||
DEBUG_EXTRA("Detected %d seam pixels", seamCount);
|
||||
|
||||
if (seamCount > 0) {
|
||||
// 2. 膨胀形成过渡带
|
||||
cv::Mat kernel = cv::getStructuringElement(
|
||||
cv::MORPH_ELLIPSE, cv::Size(blendRadius * 2 + 1, blendRadius * 2 + 1));
|
||||
cv::dilate(seamMask, seamMask, kernel);
|
||||
|
||||
// 3. 对每条接缝做邻域混合
|
||||
int blended = 0;
|
||||
// 2. 对每个接缝进行融合
|
||||
for (const SeamInfo& seam : seams) {
|
||||
const VirtualFaceGeometry& geomA = m_virtualFaceGeometries[seam.faceA];
|
||||
const VirtualFaceGeometry& geomB = m_virtualFaceGeometries[seam.faceB];
|
||||
|
||||
// ✅ 关键修复:确保 ny, nx 在有效范围内
|
||||
for (int y = blendRadius; y < textureSize - blendRadius; ++y) {
|
||||
for (int x = blendRadius; x < textureSize - blendRadius; ++x) {
|
||||
if (seamMask.at<uchar>(y, x) == 0) continue;
|
||||
|
||||
int vidCenter = m_atlasViewMap.at<int>(y, x);
|
||||
if (vidCenter <= 0) continue;
|
||||
|
||||
// 使用 cv::Vec3f 进行计算,避免类型混乱
|
||||
cv::Vec3f centerColor(
|
||||
atlas.at<cv::Vec3b>(y, x)[2],
|
||||
atlas.at<cv::Vec3b>(y, x)[1],
|
||||
atlas.at<cv::Vec3b>(y, x)[0]
|
||||
);
|
||||
cv::Vec3f mixedColor = centerColor;
|
||||
float totalWeight = 0;
|
||||
|
||||
// ✅ 关键修复:添加严格的边界检查
|
||||
for (int dy = -blendRadius; dy <= blendRadius; ++dy) {
|
||||
int ny = y + dy;
|
||||
if (ny < 0 || ny >= textureSize) continue; // ✅ 边界检查
|
||||
|
||||
for (int dx = -blendRadius; dx <= blendRadius; ++dx) {
|
||||
if (dx == 0 && dy == 0) continue;
|
||||
|
||||
int nx = x + dx;
|
||||
if (nx < 0 || nx >= textureSize) continue; // ✅ 边界检查
|
||||
|
||||
int vidNb = m_atlasViewMap.at<int>(ny, nx);
|
||||
if (vidNb <= 0 || vidNb == vidCenter) continue;
|
||||
|
||||
float w = 1.0f / (dx*dx + dy*dy + 1.0f);
|
||||
|
||||
cv::Vec3f nbColor(
|
||||
atlas.at<cv::Vec3b>(ny, nx)[2],
|
||||
atlas.at<cv::Vec3b>(ny, nx)[1],
|
||||
atlas.at<cv::Vec3b>(ny, nx)[0]
|
||||
);
|
||||
|
||||
mixedColor += w * nbColor;
|
||||
totalWeight += w;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWeight > 0) {
|
||||
mixedColor /= (1.0f + totalWeight);
|
||||
|
||||
// ✅ 写回时确保类型正确
|
||||
atlas.at<cv::Vec3b>(y, x) = cv::Vec3b(
|
||||
cv::saturate_cast<uchar>(mixedColor[2]), // B
|
||||
cv::saturate_cast<uchar>(mixedColor[1]), // G
|
||||
cv::saturate_cast<uchar>(mixedColor[0]) // R
|
||||
);
|
||||
blended++;
|
||||
}
|
||||
}
|
||||
// 提取接缝两侧像素
|
||||
std::vector<Point2i> pixelsA, pixelsB;
|
||||
ExtractSeamPixels(seam, geomA, geomB, textureSize, pixelsA, pixelsB);
|
||||
|
||||
if (!pixelsA.empty() || !pixelsB.empty()) {
|
||||
// 执行融合
|
||||
BlendSeamPixels(seam, pixelsA, pixelsB, geomA, geomB, textureSize, atlas);
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Local color blending applied to %d seam pixels (%s)",
|
||||
blended, TD_TIMER_GET_FMT().c_str());
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Seam blending completed: %zu seams processed (%s)",
|
||||
seams.size(), TD_TIMER_GET_FMT().c_str());
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
|
||||
|
||||
Reference in new issue
Block a user