|
|
|
@ -1261,6 +1261,229 @@ bool MeshTexture::ListCameraFaces(FaceDataViewArr& facesDatas, float fOutlierThr |
|
|
|
} |
|
|
|
} |
|
|
|
++progress; |
|
|
|
++progress; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Temp
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
for (int_t idx=0; idx<(int_t)views.size(); ++idx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
#pragma omp flush (bAbort) |
|
|
|
|
|
|
|
if (bAbort) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
++progress; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const IIndex idxView(views[(IIndex)idx]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Image& imageData = images[idxView]; |
|
|
|
|
|
|
|
if (!imageData.IsValid()) { |
|
|
|
|
|
|
|
++progress; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string strPath = imageData.name; |
|
|
|
|
|
|
|
size_t lastSlash = strPath.find_last_of("/\\"); |
|
|
|
|
|
|
|
if (lastSlash == std::string::npos) lastSlash = 0; // 若无分隔符,从头开始
|
|
|
|
|
|
|
|
else lastSlash++; // 跳过分隔符
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 查找扩展名分隔符 '.' 的位置
|
|
|
|
|
|
|
|
size_t lastDot = strPath.find_last_of('.'); |
|
|
|
|
|
|
|
if (lastDot == std::string::npos) lastDot = strPath.size(); // 若无扩展名,截到末尾
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 截取文件名(不含路径和扩展名)
|
|
|
|
|
|
|
|
std::string strName = strPath.substr(lastSlash, lastDot - lastSlash); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// load image
|
|
|
|
|
|
|
|
unsigned level(nResolutionLevel); |
|
|
|
|
|
|
|
const unsigned imageSize(imageData.RecomputeMaxResolution(level, nMinResolution)); |
|
|
|
|
|
|
|
if ((imageData.image.empty() || MAXF(imageData.width,imageData.height) != imageSize) && !imageData.ReloadImage(imageSize)) { |
|
|
|
|
|
|
|
#ifdef TEXOPT_USE_OPENMP |
|
|
|
|
|
|
|
bAbort = true; |
|
|
|
|
|
|
|
#pragma omp flush (bAbort) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
imageData.UpdateCamera(scene.platforms); |
|
|
|
|
|
|
|
// compute gradient magnitude
|
|
|
|
|
|
|
|
imageData.image.toGray(imageGradMag, cv::COLOR_BGR2GRAY, true); |
|
|
|
|
|
|
|
cv::Mat grad[2]; |
|
|
|
|
|
|
|
mGrad[0].resize(imageGradMag.rows, imageGradMag.cols); |
|
|
|
|
|
|
|
grad[0] = cv::Mat(imageGradMag.rows, imageGradMag.cols, cv::DataType<real>::type, (void*)mGrad[0].data()); |
|
|
|
|
|
|
|
mGrad[1].resize(imageGradMag.rows, imageGradMag.cols); |
|
|
|
|
|
|
|
grad[1] = cv::Mat(imageGradMag.rows, imageGradMag.cols, cv::DataType<real>::type, (void*)mGrad[1].data()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cv::Sobel(imageGradMag, grad[0], cv::DataType<real>::type, 1, 0, 3, 1.0/8.0); |
|
|
|
|
|
|
|
cv::Sobel(imageGradMag, grad[1], cv::DataType<real>::type, 0, 1, 3, 1.0/8.0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(TImage<real>::EMatMap)imageGradMag = (mGrad[0].cwiseAbs2()+mGrad[1].cwiseAbs2()).cwiseSqrt(); |
|
|
|
|
|
|
|
// apply some blur on the gradient to lower noise/glossiness effects onto face-quality score
|
|
|
|
|
|
|
|
cv::GaussianBlur(imageGradMag, imageGradMag, cv::Size(15, 15), 0, 0, cv::BORDER_DEFAULT); |
|
|
|
|
|
|
|
// select faces inside view frustum
|
|
|
|
|
|
|
|
Mesh::FaceIdxArr cameraFaces; |
|
|
|
|
|
|
|
Mesh::FacesInserter inserter(cameraFaces); |
|
|
|
|
|
|
|
const TFrustum<float,5> frustum(Matrix3x4f(imageData.camera.P), (float)imageData.width, (float)imageData.height); |
|
|
|
|
|
|
|
octree.Traverse(frustum, inserter); |
|
|
|
|
|
|
|
// project all triangles in this view and keep the closest ones
|
|
|
|
|
|
|
|
faceMap.create(imageData.GetSize()); |
|
|
|
|
|
|
|
depthMap.create(imageData.GetSize()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::unordered_set<FIndex> tempFaces; |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// RasterMesh rasterer(vertices, imageData.camera, depthMap, faceMap);
|
|
|
|
|
|
|
|
RasterMesh rasterer(*this, vertices, imageData.camera, depthMap, faceMap, scene.mesh, false); |
|
|
|
|
|
|
|
RasterMesh::Triangle triangle; |
|
|
|
|
|
|
|
RasterMesh::TriangleRasterizer triangleRasterizer(triangle, rasterer); |
|
|
|
|
|
|
|
if (nIgnoreMaskLabel >= 0) { |
|
|
|
|
|
|
|
// import mask
|
|
|
|
|
|
|
|
BitMatrix bmask; |
|
|
|
|
|
|
|
// std::cout << "nIgnoreMaskLabel is open" << std::endl;
|
|
|
|
|
|
|
|
DepthEstimator::ImportIgnoreMask(imageData, imageData.GetSize(), (uint16_t)OPTDENSE::nIgnoreMaskLabel, bmask, &rasterer.mask); |
|
|
|
|
|
|
|
} else if (nIgnoreMaskLabel == -1) { |
|
|
|
|
|
|
|
// creating mask to discard invalid regions created during image radial undistortion
|
|
|
|
|
|
|
|
rasterer.mask = DetectInvalidImageRegions(imageData.image); |
|
|
|
|
|
|
|
#if TD_VERBOSE != TD_VERBOSE_OFF |
|
|
|
|
|
|
|
if (VERBOSITY_LEVEL > 2) |
|
|
|
|
|
|
|
cv::imwrite(String::FormatString("umask%04d.png", idxView), rasterer.mask); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
rasterer.Clear(); |
|
|
|
|
|
|
|
for (FIndex idxFace : cameraFaces) { |
|
|
|
|
|
|
|
rasterer.validFace = true; |
|
|
|
|
|
|
|
const Face& facet = faces[idxFace]; |
|
|
|
|
|
|
|
rasterer.idxFace = idxFace; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool bExistFace = facesDatas[idxFace].empty(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (scene.is_face_visible(strName.c_str(), idxFace) || bExistFace) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
rasterer.Project(facet, triangleRasterizer); |
|
|
|
|
|
|
|
if (!rasterer.validFace) |
|
|
|
|
|
|
|
rasterer.Project(facet, triangleRasterizer); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tempFaces = PerformLocalDepthConsistencyCheck(depthMap, faceMap, scene.mesh, idxView, strName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// compute the projection area of visible faces
|
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
CLISTDEF0IDX(uint32_t,FIndex) areas(faces.size()); |
|
|
|
|
|
|
|
areas.Memset(0); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef TEXOPT_USE_OPENMP |
|
|
|
|
|
|
|
#pragma omp critical |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
for (int j=0; j<faceMap.rows; ++j) { |
|
|
|
|
|
|
|
for (int i=0; i<faceMap.cols; ++i) { |
|
|
|
|
|
|
|
const FIndex& idxFace = faceMap(j,i); |
|
|
|
|
|
|
|
// ASSERT((idxFace == NO_ID && depthMap(j,i) == 0) || (idxFace != NO_ID && depthMap(j,i) > 0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (idxFace == NO_ID) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FaceDataArr& faceDatas = facesDatas[idxFace]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Pixel8U& pixel = imageData.image(j, i); |
|
|
|
|
|
|
|
// 假设是8位图像,RGB三个通道任一超过250即视为过曝
|
|
|
|
|
|
|
|
if (pixel.r > 250 || pixel.g > 250 || pixel.b > 250) { |
|
|
|
|
|
|
|
// continue;
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float brightnessPerceptual = (0.299f * pixel.r + 0.587f * pixel.g + 0.114f * pixel.b) / 255.0f; |
|
|
|
|
|
|
|
// printf("brightnessPerceptual=%f\n", brightnessPerceptual);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (brightnessPerceptual>0.95f) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (depthMap(j,i)>999.0f) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
uint32_t& area = areas[idxFace]; |
|
|
|
|
|
|
|
if (area++ == 0) { |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
if (faceDatas.empty() || faceDatas.back().idxView != idxView) { |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
// create new face-data
|
|
|
|
|
|
|
|
FaceData& faceData = faceDatas.emplace_back(); |
|
|
|
|
|
|
|
faceData.idxView = idxView; |
|
|
|
|
|
|
|
faceData.quality = imageGradMag(j,i); |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
faceData.color = imageData.image(j,i); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
faceData.bInvalidFacesRelative = true; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// update face-data
|
|
|
|
|
|
|
|
ASSERT(!faceDatas.empty()); |
|
|
|
|
|
|
|
FaceData& faceData = faceDatas.back(); |
|
|
|
|
|
|
|
ASSERT(faceData.idxView == idxView); |
|
|
|
|
|
|
|
faceData.quality = imageGradMag(j,i); |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
faceData.color = Color(imageData.image(j,i)); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
faceData.bInvalidFacesRelative = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t& area = areas[idxFace]; |
|
|
|
|
|
|
|
if (area++ == 0) { |
|
|
|
|
|
|
|
// create new face-data
|
|
|
|
|
|
|
|
FaceData& faceData = faceDatas.emplace_back(); |
|
|
|
|
|
|
|
faceData.idxView = idxView; |
|
|
|
|
|
|
|
faceData.quality = imageGradMag(j,i); |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
faceData.color = imageData.image(j,i); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
if (depthMap(j,i)>999.0f) |
|
|
|
|
|
|
|
faceData.bInvalidFacesRelative = true; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// update face-data
|
|
|
|
|
|
|
|
ASSERT(!faceDatas.empty()); |
|
|
|
|
|
|
|
FaceData& faceData = faceDatas.back(); |
|
|
|
|
|
|
|
ASSERT(faceData.idxView == idxView); |
|
|
|
|
|
|
|
faceData.quality += imageGradMag(j,i); |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
faceData.color += Color(imageData.image(j,i)); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
if (depthMap(j,i)>999.0f) |
|
|
|
|
|
|
|
faceData.bInvalidFacesRelative = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 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) { |
|
|
|
|
|
|
|
FaceDataArr& faceDatas = facesDatas[idxFace]; |
|
|
|
|
|
|
|
if (faceDatas.empty() || faceDatas.back().idxView != idxView) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
const Face& f = faces[idxFace]; |
|
|
|
|
|
|
|
const Vertex faceCenter((vertices[f[0]] + vertices[f[1]] + vertices[f[2]]) / 3.f); |
|
|
|
|
|
|
|
const Point3f camDir(Cast<Mesh::Type>(imageData.camera.C) - faceCenter); |
|
|
|
|
|
|
|
const Normal& faceNormal = scene.mesh.faceNormals[idxFace]; |
|
|
|
|
|
|
|
const float cosFaceCam(MAXF(0.001f, ComputeAngle(camDir.ptr(), faceNormal.ptr()))); |
|
|
|
|
|
|
|
faceDatas.back().quality *= SQUARE(cosFaceCam); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA |
|
|
|
|
|
|
|
FOREACH(idxFace, areas) { |
|
|
|
|
|
|
|
const uint32_t& area = areas[idxFace]; |
|
|
|
|
|
|
|
if (area > 0) { |
|
|
|
|
|
|
|
Color& color = facesDatas[idxFace].back().color; |
|
|
|
|
|
|
|
color = RGB2YCBCR(Color(color * (1.f/(float)area))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
++progress; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// */
|
|
|
|
|
|
|
|
// Temp
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef TEXOPT_USE_OPENMP |
|
|
|
#ifdef TEXOPT_USE_OPENMP |
|
|
|
if (bAbort) |
|
|
|
if (bAbort) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|