@ -43,6 +43,8 @@
@@ -43,6 +43,8 @@
# include "cuda/MeshTextureCUDA.h"
# include <sstream>
# include <filesystem>
# include "ColorComparisonFace.h"
# include "ColorComparisonPixel.h"
namespace fs = std : : filesystem ;
@ -76,6 +78,8 @@ using namespace MVS;
@@ -76,6 +78,8 @@ using namespace MVS;
# define TEXOPT_INFERENCE_TRWS 2
# define TEXOPT_INFERENCE TEXOPT_INFERENCE_LBP
# define MASK_FACE_OCCLUSION
// #define TEST
// #define USE_CUDA
// inference algorithm
@ -590,6 +594,336 @@ public:
@@ -590,6 +594,336 @@ public:
return distances [ distances . size ( ) / 2 ] ;
}
static Color computeMedianColor ( const std : : vector < Color > & colors ) {
if ( colors . empty ( ) ) return Color : : ZERO ;
// 分别计算RGB通道的中位数
std : : vector < float > rVals , gVals , bVals ;
rVals . reserve ( colors . size ( ) ) ;
gVals . reserve ( colors . size ( ) ) ;
bVals . reserve ( colors . size ( ) ) ;
for ( const Color & c : colors ) {
rVals . push_back ( c . z ) ;
gVals . push_back ( c . y ) ;
bVals . push_back ( c . x ) ;
}
auto getMedian = [ ] ( std : : vector < float > & vals ) {
size_t n = vals . size ( ) / 2 ;
std : : nth_element ( vals . begin ( ) , vals . begin ( ) + n , vals . end ( ) ) ;
float median = vals [ n ] ;
if ( vals . size ( ) % 2 = = 0 ) {
std : : nth_element ( vals . begin ( ) , vals . begin ( ) + n - 1 , vals . end ( ) ) ;
median = ( median + vals [ n - 1 ] ) * 0.5f ;
}
return median ;
} ;
std : : vector < float > rTemp = rVals , gTemp = gVals , bTemp = bVals ;
return Color ( getMedian ( rTemp ) , getMedian ( gTemp ) , getMedian ( bTemp ) ) ;
}
static float computeColorDistance ( const Color & c1 , const Color & c2 ) {
// 欧氏距离
float dr = c1 . z - c2 . z ;
float dg = c1 . y - c2 . y ;
float db = c1 . x - c2 . x ;
return std : : sqrt ( dr * dr + dg * dg + db * db ) ;
}
static Color computeRobustFaceColor ( const FaceDataArr & faceDatas , float threshold = 2.0f ) {
if ( faceDatas . empty ( ) ) {
return Color : : ZERO ;
}
// 1. 提取所有颜色
std : : vector < Color > colors ;
colors . reserve ( faceDatas . size ( ) ) ;
for ( const FaceData & fd : faceDatas ) {
colors . push_back ( fd . color ) ;
}
// 2. 分别计算RGB三个通道的中位数
Color medianColor = computeMedianColor ( colors ) ;
// 3. 计算每个颜色到中位数的距离
std : : vector < float > distances ;
distances . reserve ( colors . size ( ) ) ;
for ( const Color & color : colors ) {
distances . push_back ( computeColorDistance ( color , medianColor ) ) ;
}
// 4. 计算距离的中位数和MAD(绝对中位差)
std : : vector < float > sortedDistances = distances ;
std : : sort ( sortedDistances . begin ( ) , sortedDistances . end ( ) ) ;
float medianDistance = sortedDistances [ sortedDistances . size ( ) / 2 ] ;
// 计算绝对偏差
std : : vector < float > absoluteDeviations ;
absoluteDeviations . reserve ( distances . size ( ) ) ;
for ( float d : distances ) {
absoluteDeviations . push_back ( std : : abs ( d - medianDistance ) ) ;
}
std : : sort ( absoluteDeviations . begin ( ) , absoluteDeviations . end ( ) ) ;
float mad = absoluteDeviations [ absoluteDeviations . size ( ) / 2 ] ;
// 5. 确定阈值(使用3倍MAD规则)
float distanceThreshold = medianDistance + threshold * mad ;
// 6. 计算筛选后的颜色均值
Color sumColor = Color : : ZERO ;
int validCount = 0 ;
for ( size_t i = 0 ; i < colors . size ( ) ; + + i ) {
if ( distances [ i ] < = distanceThreshold ) {
sumColor + = colors [ i ] ;
validCount + + ;
} else {
// 可选:记录被剔除的颜色
// std::cout << "剔除异常颜色: " << colors[i] << ", 距离: " << distances[i] << std::endl;
}
}
if ( validCount > 0 ) {
return sumColor / static_cast < float > ( validCount ) ;
} else {
// 如果没有有效颜色,返回中位数
return medianColor ;
}
}
static Color computeFaceColorDifference ( Mesh : : Color & refColor , Color & faceColor ) {
// printf("refColor:%f,%f,%f; faceColor:%d,%d,%d\n", refColor.r,refColor.g,refColor.b,faceColor[0],faceColor[1],faceColor[2]);
// 将refColor(0-255整数)转换为0-1范围的浮点数
Color refColorFloat (
refColor . r / 255.0f ,
refColor . g / 255.0f ,
refColor . b / 255.0f
) ;
// 计算差值(浮点数,可能有负值)
// 假设faceColor已经是0-1范围的浮点数
Color difference (
refColorFloat [ 0 ] - faceColor [ 0 ] / 255.0f ,
refColorFloat [ 1 ] - faceColor [ 1 ] / 255.0f ,
refColorFloat [ 2 ] - faceColor [ 2 ] / 255.0f
) ;
return difference ;
}
static float computeFaceColorDifferenceF ( Mesh : : Color & refColor , Color & faceColor ) {
// printf("refColor:%f,%f,%f; faceColor:%d,%d,%d\n", refColor.r,refColor.g,refColor.b,faceColor[0],faceColor[1],faceColor[2]);
// 将refColor(0-255整数)转换为0-1范围的浮点数
Color refColorFloat (
refColor . r / 255.0f ,
refColor . g / 255.0f ,
refColor . b / 255.0f
) ;
// 计算差值(浮点数,可能有负值)
// 假设faceColor已经是0-1范围的浮点数
Color difference (
refColorFloat [ 0 ] - faceColor [ 0 ] / 255.0f ,
refColorFloat [ 1 ] - faceColor [ 1 ] / 255.0f ,
refColorFloat [ 2 ] - faceColor [ 2 ] / 255.0f
) ;
int dr = difference [ 0 ] ;
int dg = difference [ 0 ] ;
int db = difference [ 0 ] ;
return std : : sqrt ( dr * dr + dg * dg + db * db ) ;
}
static float computeMeshColorDifferenceF ( const Mesh : : Color & refColor1 , const Mesh : : Color & refColor2 ) {
// 将颜色转换为0-1范围的浮点数
Color refColorFloat1 (
refColor1 . r / 255.0f ,
refColor1 . g / 255.0f ,
refColor1 . b / 255.0f
) ;
Color refColorFloat2 (
refColor2 . r / 255.0f ,
refColor2 . g / 255.0f ,
refColor2 . b / 255.0f
) ;
// 计算差值(浮点数)
Color difference (
refColorFloat2 [ 0 ] - refColorFloat1 [ 0 ] ,
refColorFloat2 [ 1 ] - refColorFloat1 [ 1 ] ,
refColorFloat2 [ 2 ] - refColorFloat1 [ 2 ]
) ;
// 计算欧氏距离(浮点数)
float dr = difference [ 0 ] ;
float dg = difference [ 1 ] ; // 修正:使用difference[1]
float db = difference [ 2 ] ; // 修正:使用difference[2]
return std : : sqrt ( dr * dr + dg * dg + db * db ) ;
}
static float computeColorDifferenceEnhanced ( const Mesh : : Color & c1 , const Mesh : : Color & c2 ) {
// 转换为0-1
float r1 = c1 . r / 255.0f ;
float g1 = c1 . g / 255.0f ;
float b1 = c1 . b / 255.0f ;
float r2 = c2 . r / 255.0f ;
float g2 = c2 . g / 255.0f ;
float b2 = c2 . b / 255.0f ;
// 计算亮度
float lum1 = 0.299f * r1 + 0.587f * g1 + 0.114f * b1 ;
float lum2 = 0.299f * r2 + 0.587f * g2 + 0.114f * b2 ;
// 亮度差异权重
float lumDiff = std : : abs ( lum1 - lum2 ) ;
// 色度差异
float chromaDiff = std : : sqrt (
( r1 - r2 ) * ( r1 - r2 ) +
( g1 - g2 ) * ( g1 - g2 ) +
( b1 - b2 ) * ( b1 - b2 )
) ;
// 综合差异(亮度权重更高)
return 0.7f * lumDiff + 0.3f * chromaDiff ;
}
static float computeColorDifferenceHSV2 ( Mesh : : Color & c1 , Mesh : : Color & c2 ) {
// RGB转HSV
auto rgb2hsv = [ ] ( float r , float g , float b , float & h , float & s , float & v ) {
float cmax = std : : max ( { r , g , b } ) ;
float cmin = std : : min ( { r , g , b } ) ;
float delta = cmax - cmin ;
v = cmax ;
if ( cmax > 0 ) {
s = delta / cmax ;
} else {
s = 0 ;
}
if ( delta > 0 ) {
if ( cmax = = r ) {
h = 60.0f * fmod ( ( g - b ) / delta , 6.0f ) ;
} else if ( cmax = = g ) {
h = 60.0f * ( ( ( b - r ) / delta ) + 2.0f ) ;
} else if ( cmax = = b ) {
h = 60.0f * ( ( ( r - g ) / delta ) + 4.0f ) ;
}
if ( h < 0 ) h + = 360.0f ;
} else {
h = 0 ;
}
} ;
// 转换为0-1
float r1 = c1 . r / 255.0f , g1 = c1 . g / 255.0f , b1 = c1 . b / 255.0f ;
float r2 = c2 . r / 255.0f , g2 = c2 . g / 255.0f , b2 = c2 . b / 255.0f ;
float h1 , s1 , v1 , h2 , s2 , v2 ;
rgb2hsv ( r1 , g1 , b1 , h1 , s1 , v1 ) ;
rgb2hsv ( r2 , g2 , b2 , h2 , s2 , v2 ) ;
// 归一化H到0-1
h1 / = 360.0f ; h2 / = 360.0f ;
// 计算HSV空间距离(色相差异需考虑环形特性)
float dh = std : : min ( fabs ( h1 - h2 ) , 1.0f - fabs ( h1 - h2 ) ) ;
float ds = fabs ( s1 - s2 ) ;
float dv = fabs ( v1 - v2 ) ;
// 加权距离(色相最重要,饱和度次之,亮度最不重要)
return std : : sqrt ( 0.5f * dh * dh + 0.3f * ds * ds + 0.2f * dv * dv ) ;
}
static float computeColorDifferenceHSV ( MeshColor & c1 , MeshColor & c2 ) {
// RGB转HSV
auto rgb2hsv = [ ] ( float r , float g , float b , float & h , float & s , float & v ) {
float cmax = std : : max ( { r , g , b } ) ;
float cmin = std : : min ( { r , g , b } ) ;
float delta = cmax - cmin ;
v = cmax ;
if ( cmax > 0 ) {
s = delta / cmax ;
} else {
s = 0 ;
}
if ( delta > 0 ) {
if ( cmax = = r ) {
h = 60.0f * fmod ( ( g - b ) / delta , 6.0f ) ;
} else if ( cmax = = g ) {
h = 60.0f * ( ( ( b - r ) / delta ) + 2.0f ) ;
} else if ( cmax = = b ) {
h = 60.0f * ( ( ( r - g ) / delta ) + 4.0f ) ;
}
if ( h < 0 ) h + = 360.0f ;
} else {
h = 0 ;
}
} ;
// 转换为0-1
float r1 = c1 . r / 255.0f , g1 = c1 . g / 255.0f , b1 = c1 . b / 255.0f ;
float r2 = c2 . r / 255.0f , g2 = c2 . g / 255.0f , b2 = c2 . b / 255.0f ;
float h1 , s1 , v1 , h2 , s2 , v2 ;
rgb2hsv ( r1 , g1 , b1 , h1 , s1 , v1 ) ;
rgb2hsv ( r2 , g2 , b2 , h2 , s2 , v2 ) ;
// 归一化H到0-1
h1 / = 360.0f ; h2 / = 360.0f ;
// 计算HSV空间距离(色相差异需考虑环形特性)
float dh = std : : min ( fabs ( h1 - h2 ) , 1.0f - fabs ( h1 - h2 ) ) ;
float ds = fabs ( s1 - s2 ) ;
float dv = fabs ( v1 - v2 ) ;
// 加权距离(色相最重要,饱和度次之,亮度最不重要)
return std : : sqrt ( 0.5f * dh * dh + 0.3f * ds * ds + 0.2f * dv * dv ) ;
}
static float computeColorSimilarityWeighted ( const Mesh : : Color & c1 , const Mesh : : Color & c2 ) {
// 人眼对绿色最敏感,红色次之,蓝色最不敏感
const float weightR = 0.299f ;
const float weightG = 0.587f ;
const float weightB = 0.114f ;
float dr = ( c1 . r - c2 . r ) / 255.0f ;
float dg = ( c1 . g - c2 . g ) / 255.0f ;
float db = ( c1 . b - c2 . b ) / 255.0f ;
return std : : sqrt ( weightR * dr * dr + weightG * dg * dg + weightB * db * db ) ;
}
static bool isTestFace ( std : : unordered_set < int > & face_test , int idxFace ) {
if ( face_test . find ( idxFace ) ! = face_test . end ( ) ) {
return true ;
}
// if (idxFace==18919||idxFace==18925||idxFace==18926||
// idxFace==18932||idxFace==478724||idxFace==803492||
// idxFace==803496||idxFace==803497||idxFace==803507||idxFace==803508||
// idxFace==18921)
// {
// return true;
// }
return false ;
}
//*/
/*
// 采用ITU-R BT.601标准系数,增加数值稳定性处理
@ -673,6 +1007,9 @@ public:
@@ -673,6 +1007,9 @@ public:
Mesh : : TexIndexArr & faceTexindices ; // for each face, the texture-coordinates of the vertices
Mesh : : Image8U3Arr & texturesDiffuse ; // texture containing the diffuse color
Mesh : : ColorArr & faceColorsGaussian ;
Mesh : : ColorArr faceOriginalColors ;
// constant the entire time
Mesh : : VertexArr & vertices ;
Mesh : : FaceArr & faces ;
@ -726,14 +1063,23 @@ MeshTexture::MeshTexture(Scene& _scene, unsigned _nResolutionLevel, unsigned _nM
@@ -726,14 +1063,23 @@ MeshTexture::MeshTexture(Scene& _scene, unsigned _nResolutionLevel, unsigned _nM
faces ( _scene . mesh . faces ) ,
images ( _scene . images ) ,
scene ( _scene ) ,
alternativeTexture ( nullptr )
alternativeTexture ( nullptr ) ,
faceColorsGaussian ( _scene . mesh . faceColors ) ,
faceOriginalColors ( )
{
// 分配空间
faceOriginalColors . Resize ( _scene . mesh . faceColors . size ( ) ) ;
// 用默认值填充
for ( size_t i = 0 ; i < faceOriginalColors . size ( ) ; + + i ) {
faceOriginalColors [ i ] = Mesh : : Color ( 0 , 0 , 0 ) ; // 或使用其他默认值
}
}
MeshTexture : : ~ MeshTexture ( )
{
vertexFaces . Release ( ) ;
vertexBoundary . Release ( ) ;
faceFaces . Release ( ) ;
faceColorsGaussian . Release ( ) ;
}
void MeshTexture : : ComputeFaceCurvatures ( ) const {
@ -786,9 +1132,21 @@ void MeshTexture::ListVertexFaces()
@@ -786,9 +1132,21 @@ void MeshTexture::ListVertexFaces()
scene . mesh . ListIncidenteFaceFaces ( ) ;
}
static ColorComparisonFace * g_colorComparisonFace = nullptr ;
static ColorComparisonPixel * g_colorComparisonPixel = nullptr ;
// extract array of faces viewed by each image
bool MeshTexture : : ListCameraFaces ( FaceDataViewArr & facesDatas , float fOutlierThreshold , int nIgnoreMaskLabel , const IIndexArr & _views , bool bUseVirtualFaces )
{
# ifdef TEST
std : : string outputDir = " /home/algo/Documents/openMVS/data/446442/color_comparison/ " ;
g_colorComparisonFace = new ColorComparisonFace ( outputDir ) ;
std : : map < IIndex , std : : map < FIndex , std : : vector < cv : : Point > > > testFacePixelsByView ;
g_colorComparisonPixel = new ColorComparisonPixel ( outputDir ) ;
# endif
// create faces octree
Mesh : : Octree octree ;
Mesh : : FacesInserter : : CreateOctree ( octree , scene . mesh ) ;
@ -1133,6 +1491,100 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
@@ -1133,6 +1491,100 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
// if (!(scene.mesh.invalidFacesRelative.data.contains(idxFace) && scene.is_face_visible_relative(idxFace)))
// if (false)
{
/*
Mesh : : Color gaussianColor = faceColorsGaussian [ idxFace ] ;
FaceData & faceData = faceDatas . emplace_back ( ) ;
faceData . idxView = idxView ;
faceData . quality = imageGradMag ( j , i ) ;
# if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
// printf("gaussianColor:%d, %d, %d\n", gaussianColor[0], gaussianColor[1], gaussianColor[2]);
faceData . color = Color ( gaussianColor [ 0 ] / 255.0f , gaussianColor [ 1 ] / 255.0f , gaussianColor [ 2 ] / 255.0f ) ;
# endif
continue ;
//*/
//*
if ( idxFace < faceColorsGaussian . size ( ) )
{
Mesh : : Color gaussianColor = faceColorsGaussian [ idxFace ] ;
// printf("idxFace(%d) gaussianColor:%d, %d, %d\n", idxFace, gaussianColor[0], gaussianColor[1], gaussianColor[2]);
Color imageColor = Color ( imageData . image ( j , i ) ) ;
// printf("idxFace(%d) imageColor:%f, %f, %f\n", idxFace, imageColor[0], imageColor[1], imageColor[2]);
Mesh : : Color originalColor = Mesh : : Color ( imageColor [ 0 ] , imageColor [ 1 ] , imageColor [ 2 ] ) ;
MeshColor gaussianMeshColor ( gaussianColor . r , gaussianColor . g , gaussianColor . b ) ;
MeshColor originalMeshColor ( originalColor . r , originalColor . g , originalColor . b ) ;
float colorDistance = computeColorDifferenceHSV ( gaussianMeshColor , originalMeshColor ) ;
// printf("colorDistance=%f\n",colorDistance);
float threshold = 0.31f ; // 基础阈值
// printf("colorDistance=%f\n",colorDistance);
if ( colorDistance > threshold )
{
// FaceData& faceData = faceDatas.emplace_back();
// faceData.idxView = idxView;
// faceData.quality = 0;
// faceData.bInvalidFacesRelative = true;
// printf("faceData.quality=%f\n", faceData.quality);
# if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
// faceData.color = imageData.image(j,i);
# endif
// continue;
}
//*/
# ifdef TEST
bool bFilter = ( colorDistance > threshold ) ? true : false ;
std : : string full_path = imageData . name ;
// 找到最后一个斜杠
size_t slash_pos = full_path . find_last_of ( " / \\ " ) ;
// 提取文件名(带扩展名)
std : : string filename = ( slash_pos ! = std : : string : : npos )
? full_path . substr ( slash_pos + 1 )
: full_path ;
// 去掉扩展名
size_t dot_pos = filename . find_last_of ( " . " ) ;
if ( dot_pos ! = std : : string : : npos ) {
filename = filename . substr ( 0 , dot_pos ) ;
}
if ( isTestFace ( scene . face_test , idxFace ) )
{
// printf("Test face(%d) Color: gaussian(%d,%d,%d), image(%s) color(%d,%d,%d), colorDistance(%f), threshold(%f), filter=%b\n",idxFace, gaussianColor.r, gaussianColor.g, gaussianColor.b,
// filename.c_str(), originalColor.r, originalColor.g, originalColor.b, colorDistance, threshold, bFilter);
// 创建MeshColor对象
MeshColor gaussianMeshColor ( gaussianColor . r , gaussianColor . g , gaussianColor . b ) ;
MeshColor originalMeshColor ( originalColor . r , originalColor . g , originalColor . b ) ;
// 添加到批处理器
if ( g_colorComparisonPixel ) {
g_colorComparisonPixel - > addColorInfo ( idxFace ,
gaussianMeshColor ,
originalMeshColor ,
colorDistance , threshold , filename ) ;
}
// 添加到批处理器
if ( g_colorComparisonFace ) {
testFacePixelsByView [ idxView ] [ idxFace ] . push_back ( cv : : Point ( i , j ) ) ;
printf ( " testFacePixels imageView(%s), idxFace(%d) push_back (%d, %d) \n " , filename . c_str ( ) , idxFace , i , j ) ;
}
}
# endif
}
if ( depthMap ( j , i ) > 999.0f )
{
/*
@ -1145,10 +1597,12 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
@@ -1145,10 +1597,12 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
// printf("faceData.quality=%f\n", faceData.quality);
# if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
faceData . color = imageData . image ( j , i ) ;
// faceData.color = Point3f::ZERO;
# endif
continue ;
*/
//*/
/*
# if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
uint32_t & area = areas [ idxFace ] ;
if ( area + + = = 0 ) {
@ -1175,6 +1629,7 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
@@ -1175,6 +1629,7 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
faceData . bInvalidFacesRelative = true ;
}
continue ;
//*/
}
}
@ -1210,6 +1665,160 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
@@ -1210,6 +1665,160 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
}
}
}
# ifdef TEST
auto itView = testFacePixelsByView . find ( idxView ) ;
if ( itView ! = testFacePixelsByView . end ( ) ) {
const auto & facePixelsMap = itView - > second ;
// 打印视图信息
printf ( " === 处理视图 %d: %s === \n " , idxView , strName . c_str ( ) ) ;
printf ( " 这个视图有 %zu 个测试面 \n " , facePixelsMap . size ( ) ) ;
// 遍历这个视图中的所有测试面
for ( const auto & faceEntry : facePixelsMap ) {
FIndex idxFace = faceEntry . first ;
const std : : vector < cv : : Point > & pixels = faceEntry . second ;
printf ( " 处理面 %d: 有 %zu 个像素 \n " , idxFace , pixels . size ( ) ) ;
// 检查像素是否为空
if ( pixels . empty ( ) ) {
printf ( " ⚠️ 面 %d 没有像素,跳过 \n " , idxFace ) ;
continue ;
}
// 计算面片区域的包围盒
int minX = INT_MAX , minY = INT_MAX ;
int maxX = 0 , maxY = 0 ;
// 打印前几个像素的位置
int printLimit = std : : min ( 3 , ( int ) pixels . size ( ) ) ;
for ( int i = 0 ; i < printLimit ; + + i ) {
printf ( " 像素 %d: (%d, %d) \n " , i , pixels [ i ] . x , pixels [ i ] . y ) ;
}
if ( pixels . size ( ) > 3 ) {
printf ( " 还有 %zu 个像素... \n " , pixels . size ( ) - 3 ) ;
}
// 计算包围盒
for ( const auto & pt : pixels ) {
if ( pt . x < minX ) minX = pt . x ;
if ( pt . x > maxX ) maxX = pt . x ;
if ( pt . y < minY ) minY = pt . y ;
if ( pt . y > maxY ) maxY = pt . y ;
}
printf ( " 包围盒: minX=%d, maxX=%d, minY=%d, maxY=%d \n " , minX , maxX , minY , maxY ) ;
// 扩展一些边界
int padding = 2 ;
int imageWidth = static_cast < int > ( imageData . width ) ;
int imageHeight = static_cast < int > ( imageData . height ) ;
// 扩展前检查边界
minX = std : : max ( 0 , minX - padding ) ;
maxX = std : : min ( imageWidth - 1 , maxX + padding ) ;
minY = std : : max ( 0 , minY - padding ) ;
maxY = std : : min ( imageHeight - 1 , maxY + padding ) ;
// 确保扩展后 min <= max
if ( minX > maxX ) {
printf ( " ⚠️ 扩展后 minX > maxX,交换 \n " ) ;
std : : swap ( minX , maxX ) ;
}
if ( minY > maxY ) {
printf ( " ⚠️ 扩展后 minY > maxY,交换 \n " ) ;
std : : swap ( minY , maxY ) ;
}
int width = maxX - minX + 1 ;
int height = maxY - minY + 1 ;
printf ( " 扩展后: 左上(%d,%d) 宽高(%d,%d) \n " , minX , minY , width , height ) ;
// 检查尺寸是否有效
if ( width < = 0 | | height < = 0 ) {
printf ( " ⚠️ 面 %d 无效尺寸,跳过 \n " , idxFace ) ;
continue ;
}
// 检查是否在图像范围内
if ( minX < 0 | | minX > = imageWidth | |
maxX < 0 | | maxX > = imageWidth | |
minY < 0 | | minY > = imageHeight | |
maxY < 0 | | maxY > = imageHeight ) {
printf ( " ⚠️ 面 %d 超出图像范围,跳过 \n " , idxFace ) ;
continue ;
}
// 提取图像区域
cv : : Rect roi ( minX , minY , width , height ) ;
printf ( " 提取ROI: x=%d, y=%d, width=%d, height=%d \n " ,
roi . x , roi . y , roi . width , roi . height ) ;
// 验证ROI
if ( roi . x < 0 | | roi . y < 0 | |
roi . x + roi . width > imageWidth | |
roi . y + roi . height > imageHeight ) {
printf ( " ⚠️ 面 %d ROI验证失败,跳过 \n " , idxFace ) ;
continue ;
}
cv : : Mat imageRegion = imageData . image ( roi ) . clone ( ) ;
if ( imageRegion . empty ( ) ) {
printf ( " ⚠️ 面 %d 图像区域为空,跳过 \n " , idxFace ) ;
continue ;
}
printf ( " 提取图像区域成功: %dx%d \n " , imageRegion . cols , imageRegion . rows ) ;
// 计算图像区域的平均颜色
cv : : Scalar meanColor = cv : : mean ( imageRegion ) ;
MeshColor originalColor ( meanColor [ 2 ] , meanColor [ 1 ] , meanColor [ 0 ] ) ; // OpenCV是BGR格式
// 获取高斯颜色
Mesh : : Color gaussianColor = faceColorsGaussian [ idxFace ] ;
MeshColor gaussianMeshColor ( gaussianColor . r , gaussianColor . g , gaussianColor . b ) ;
// 计算颜色距离
float colorDistance = computeColorDifferenceHSV ( gaussianMeshColor , originalColor ) ;
float threshold = 0.31f ; // 基础阈值
bool bFilter = ( colorDistance > threshold ) ;
std : : string full_path = imageData . name ;
size_t slash_pos = full_path . find_last_of ( " / \\ " ) ;
std : : string filename = ( slash_pos ! = std : : string : : npos )
? full_path . substr ( slash_pos + 1 )
: full_path ;
size_t dot_pos = filename . find_last_of ( " . " ) ;
if ( dot_pos ! = std : : string : : npos ) {
filename = filename . substr ( 0 , dot_pos ) ;
}
printf ( " Test face(%d) Color: gaussian(%d,%d,%d), image(%s) color(%d,%d,%d), colorDistance(%.4f), threshold(%.4f), filter=%s \n " ,
idxFace , gaussianColor . r , gaussianColor . g , gaussianColor . b ,
filename . c_str ( ) , originalColor . r , originalColor . g , originalColor . b ,
colorDistance , threshold , bFilter ? " true " : " false " ) ;
// 添加到批处理器
if ( g_colorComparisonFace ) {
g_colorComparisonFace - > addColorInfo ( idxFace ,
gaussianMeshColor ,
imageRegion ,
colorDistance , threshold , filename ) ;
printf ( " ✅ 面 %d 已添加到批处理器 \n " , idxFace ) ;
}
}
printf ( " === 视图 %d 处理完成 === \n \n " , idxView ) ;
} else {
printf ( " 视图 %d: 没有测试面 \n " , idxView ) ;
}
# endif
// adjust face quality with camera angle relative to face normal
// tries to increase chances of a camera with perpendicular view on the surface (smoothened normals) to be selected
FOREACH ( idxFace , facesDatas ) {
@ -1249,6 +1858,25 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
@@ -1249,6 +1858,25 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr
FaceOutlierDetection ( faceDatas , fOutlierThreshold ) ;
}
# endif
# ifdef TEST
if ( g_colorComparisonFace ) {
// 创建实际图像区域对比图
printf ( " 创建实际图像区域对比图,包含 %d 个face,%d 条记录 \n " ,
g_colorComparisonFace - > getTotalFaces ( ) , g_colorComparisonFace - > getTotalRecords ( ) ) ;
g_colorComparisonFace - > createBatchComparison ( 10 , 500 ) ;
delete g_colorComparisonFace ;
g_colorComparisonFace = nullptr ;
}
if ( g_colorComparisonPixel ) {
g_colorComparisonPixel - > createBatchComparison ( 10 , 500 ) ; // 每行4个,最多20个
delete g_colorComparisonPixel ;
g_colorComparisonPixel = nullptr ;
}
# endif
return true ;
}
@ -1690,7 +2318,7 @@ std::unordered_set<FIndex> MeshTexture::PerformLocalDepthConsistencyCheck(DepthM
@@ -1690,7 +2318,7 @@ std::unordered_set<FIndex> MeshTexture::PerformLocalDepthConsistencyCheck(DepthM
// 第三遍:清除不一致区域的深度值(现在可以安全修改原始depthMap)
for ( int r = 0 ; r < depthMap . rows ; + + r ) {
for ( int c = 0 ; c < depthMap . cols ; + + c ) {
if ( consistencyMask ( r , c ) = = 255 )
if ( consistencyMask ( r , c ) = = 255 )
{
const FIndex idxFace = faceMap ( r , c ) ;
if ( idxFace = = NO_ID | | idxFace > = mesh . faces . size ( ) ) {
@ -4215,9 +4843,12 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4215,9 +4843,12 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
for ( const FaceData & fd : faceDatas ) {
sumColor + = fd . color ;
}
faceColors [ idxFace ] = sumColor / faceDatas . size ( ) ;
// faceColors[idxFace] = sumColor / faceDatas.size();
faceColors [ idxFace ] = computeRobustFaceColor ( faceDatas , 10.0f ) ;
}
do {
const FIndex startPos = RAND ( ) % remainingFaces . size ( ) ;
const FIndex virtualFaceCenterFaceID = remainingFaces [ startPos ] ;
@ -4359,8 +4990,8 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4359,8 +4990,8 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
if ( angleDeg < = 45.0f )
{
// filteredCams.push_back(idxView);
/ /*
filteredCams . push_back ( idxView ) ;
/*
float brightnessScore = CalculateBrightnessScore ( imageData ) ; // 亮度评分函数
float angleScore = 1.0f - ( angleDeg / 45.0f ) ;
float qualityScore = 0.0f ;
@ -4382,9 +5013,9 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
@@ -4382,9 +5013,9 @@ bool MeshTexture::CreateVirtualFaces62(FaceDataViewArr& facesDatas, FaceDataView
}
else
{
// filteredCams.push_back(idxView);
filteredCams . push_back ( idxView ) ;
/ /*
/*
float brightnessScore = CalculateBrightnessScore ( imageData ) ; // 亮度评分函数
float angleScore = 1.0f - ( angleDeg / 45.0f ) ;
float qualityScore = 0.0f ;
@ -9234,11 +9865,41 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
@@ -9234,11 +9865,41 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
for ( const FIndex idxFace : texturePatch . faces ) {
const Face & face = faces [ idxFace ] ;
TexCoord * texcoords = faceTexcoords . data ( ) + idxFace * 3 ;
TexCoord centroid ( 0 , 0 ) ;
for ( int i = 0 ; i < 3 ; + + i ) {
texcoords [ i ] = imageData . camera . ProjectPointP ( vertices [ face [ i ] ] ) ;
centroid + = texcoords [ i ] ;
ASSERT ( imageData . image . isInsideWithBorder ( texcoords [ i ] , border ) ) ;
aabb . InsertFull ( texcoords [ i ] ) ;
}
centroid / = 3.0f ;
// 获取重心处的颜色
int cx = static_cast < int > ( centroid . x + 0.5f ) ;
int cy = static_cast < int > ( centroid . y + 0.5f ) ;
// 边界检查
cx = std : : max ( 0 , std : : min ( cx , imageData . image . cols - 1 ) ) ;
cy = std : : max ( 0 , std : : min ( cy , imageData . image . rows - 1 ) ) ;
# ifdef TEST
// 获取颜色
const Pixel8U & pixel = imageData . image ( cy , cx ) ;
faceOriginalColors [ idxFace ] = Mesh : : Color ( pixel . r , pixel . g , pixel . b ) ;
// if (idxFace==18919||idxFace==18925||idxFace==18926||
// idxFace==18932||idxFace==478724||idxFace==803492||
// idxFace==803496||idxFace==803497||idxFace==803507||idxFace==803508||
// idxFace==18921)
if ( isTestFace ( scene . face_test , idxFace ) )
{
Mesh : : Color originalColor = faceOriginalColors [ idxFace ] ;
printf ( " idxFace(%d) record originalColor:%d, %d, %d \n " , idxFace , originalColor [ 0 ] , originalColor [ 1 ] , originalColor [ 2 ] ) ;
}
# endif
}
// compute relative texture coordinates
ASSERT ( imageData . image . isInside ( Point2f ( aabb . ptMin ) ) ) ;
@ -9464,7 +10125,78 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
@@ -9464,7 +10125,78 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
patch = patch . t ( ) ;
x = 1 ; y = 0 ;
}
// 检查并处理目标面
for ( const FIndex idxFace : texturePatch . faces ) {
if ( isTestFace ( scene . face_test , idxFace ) )
// if (idxFace==78133)
{
// 找到这个面对应于纹理块中的区域
TexCoord * texcoords = faceTexcoords . data ( ) + idxFace * 3 ;
// 计算在纹理块内的局部坐标
TexCoord localCoords [ 3 ] ;
for ( int v = 0 ; v < 3 ; + + v ) {
localCoords [ v ] = TexCoord (
texcoords [ v ] [ x ] ,
texcoords [ v ] [ y ]
) ;
}
// 转换为相对于纹理块的坐标
TexCoord offset ( texturePatch . rect . tl ( ) ) ;
for ( int v = 0 ; v < 3 ; + + v ) {
localCoords [ v ] + = offset ;
}
// 在patch中填充三角形为黑色
cv : : Point2f triangle [ 3 ] ;
for ( int v = 0 ; v < 3 ; + + v ) {
triangle [ v ] = cv : : Point2f (
localCoords [ v ] . x - texturePatch . rect . x ,
localCoords [ v ] . y - texturePatch . rect . y
) ;
}
const cv : : Point2f * ppt [ 1 ] = { triangle } ;
int npt [ ] = { 3 } ;
std : : vector < cv : : Point > trianglePoints ( 3 ) ;
for ( int v = 0 ; v < 3 ; + + v ) {
trianglePoints [ v ] = cv : : Point (
static_cast < int > ( localCoords [ v ] . x - texturePatch . rect . x + 0.5f ) ,
static_cast < int > ( localCoords [ v ] . y - texturePatch . rect . y + 0.5f )
) ;
}
std : : vector < std : : vector < cv : : Point > > contours = { trianglePoints } ;
// cv::fillPoly(patch, contours, cv::Scalar(0, 0, 0));
Mesh : : Color gaussianColor = faceColorsGaussian [ idxFace ] ;
// printf("idxFace(%d) gaussianColor:%d, %d, %d\n", idxFace, gaussianColor[0], gaussianColor[1], gaussianColor[2]);
Mesh : : Color originalColor = faceOriginalColors [ idxFace ] ;
// printf("idxFace(%d) originalColor:%d, %d, %d\n", idxFace, originalColor[0], originalColor[1], originalColor[2]);
MeshColor gaussianMeshColor ( gaussianColor . r , gaussianColor . g , gaussianColor . b ) ;
MeshColor originalMeshColor ( originalColor . r , originalColor . g , originalColor . b ) ;
// float colorDistance = computeColorSimilarityWeighted(gaussianColor, originalColor);
// float colorDistance = computeColorDifferenceEnhanced(gaussianColor, originalColor);
float colorDistance = computeColorDifferenceHSV ( gaussianMeshColor , originalMeshColor ) ;
// printf("colorDistance=%f\n",colorDistance);
float threshold = 0.12f ; // 基础阈值
// 考虑面的面积:小面对颜色变化更敏感
// float faceArea = faces[idxFace].area;
// if (faceArea < 0.001f) { // 非常小的面
// threshold *= 0.8f; // 更严格的阈值
// }
// if (colorDistance>threshold)
// cv::fillPoly(patch, contours, cv::Scalar(gaussianColor[0], gaussianColor[1], gaussianColor[2]));
}
}
patch . copyTo ( texturesDiffuse [ idxTexture ] ( rect ) ) ;
}
else
@ -10406,6 +11138,26 @@ bool Scene::LoadVisibleFacesData(std::map<std::string, std::unordered_set<int>>&
@@ -10406,6 +11138,26 @@ bool Scene::LoadVisibleFacesData(std::map<std::string, std::unordered_set<int>>&
return true ;
}
// 从文件加载遮挡数据
bool Scene : : LoadTestFacesData ( std : : unordered_set < int > & face_test , std : : string & basePath ) {
printf ( " LoadTestFacesData %s \n " , basePath . c_str ( ) ) ;
std : : ifstream testFacesFile ( basePath + " _test_faces.txt " ) ;
if ( ! testFacesFile . is_open ( ) ) {
return false ;
}
std : : string line ;
while ( std : : getline ( testFacesFile , line ) ) {
int face_index = std : : stoi ( line ) ;
face_test . insert ( face_index ) ;
printf ( " insert face_index=%d \n " , face_index ) ;
}
testFacesFile . close ( ) ;
return true ;
}
// texture mesh
// - minCommonCameras: generate texture patches using virtual faces composed of coplanar triangles sharing at least this number of views (0 - disabled, 3 - good value)
// - fSharpnessWeight: sharpness weight to be applied on the texture (0 - disabled, 0.5 - good value)
@ -10413,7 +11165,7 @@ bool Scene::LoadVisibleFacesData(std::map<std::string, std::unordered_set<int>>&
@@ -10413,7 +11165,7 @@ bool Scene::LoadVisibleFacesData(std::map<std::string, std::unordered_set<int>>&
bool Scene : : TextureMesh ( unsigned nResolutionLevel , unsigned nMinResolution , unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness ,
bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight ,
int nIgnoreMaskLabel , int maxTextureSize , const IIndexArr & views , const SEACAVE : : String & baseFileName , bool bOriginFaceview ,
const std : : string & inputFileName , const std : : string & meshFileName )
const std : : string & inputFileName , const std : : string & meshFileName , bool bExistVertexColor )
{
if ( ! bOriginFaceview )
{
@ -10427,6 +11179,14 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
@@ -10427,6 +11179,14 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
if ( mesh . faceNormals . empty ( ) ) {
mesh . ComputeNormalFaces ( ) ; // 计算面法向量
}
if ( bExistVertexColor )
{
printf ( " bExistVertexColor true \n " ) ;
if ( mesh . faceColors . empty ( ) ) {
mesh . ComputeColorFaces ( ) ; // 计算面法向量
}
}
// 确保顶点边界信息已计算
if ( mesh . vertexBoundary . empty ( ) ) {
@ -10481,7 +11241,6 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
@@ -10481,7 +11241,6 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
}
printf ( " id=%s \n " , id . c_str ( ) ) ;
# ifdef MASK_FACE_OCCLUSION
//*
fs : : path p ( baseFileName . c_str ( ) ) ;
// 2. 获取父路径 (e.g., /path/to/data/scene)
@ -10499,6 +11258,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
@@ -10499,6 +11258,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
basePath = baseFileName . substr ( 0 , secondLastSlash + 1 ) ;
/*/
# ifdef MASK_FACE_OCCLUSION
// printf("basePath=%s\n", basePath.c_str());
if ( ! LoadVisibleFacesData ( visible_faces_map , face_visible_relative , edge_faces_map , delete_edge_faces_map , basePath ) )
@ -10507,6 +11267,13 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
@@ -10507,6 +11267,13 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
}
# endif
# ifdef TEST
if ( ! LoadTestFacesData ( face_test , basePath ) )
{
printf ( " LoadVisibleFacesData error \n " ) ;
}
# endif
// assign the best view to each face
{
TD_TIMER_STARTD ( ) ;