Merge pull request #25382 from savuor:rv/fix_mesh_load

Fix mesh loading for texture coordinates and face indices #25382

### This PR changes

* Texture coordinates were stored incorrectly (3-channel array is read as if there were 2 channels), fixed
* Faces were pushed back to the output array instead of indexed writing which produced a lot of empty faces, fixed
* A set of ground truth tests were added to cover these issues
* `std::vector<cv::Mat>` support added for `saveMesh()` which is required for Python bindings
* More command line args were added to rasterization test data generator

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
pull/25422/head
Rostislav Vasilikhin 10 months ago committed by GitHub
parent 3e561d8353
commit 6699ca1a40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      modules/3d/misc/python/test/test_iomesh.py
  2. 6
      modules/3d/perf/perf_rendering.cpp
  3. 55
      modules/3d/src/pointcloud/load_point_cloud.cpp
  4. 181
      modules/3d/test/test_pointcloud.cpp
  5. 8
      modules/3d/test/test_rendering.cpp
  6. 219
      samples/opengl/opengl_testdata_generator.cpp

@ -32,7 +32,7 @@ class raster_test(NewOpenCVTests):
if a.shape not in goodShapes:
self.fail(errorMsg % s)
if texCoords.shape not in [(1, 18, 2), (18, 1, 2)]:
if texCoords.shape not in [(1, 18, 2), (18, 1, 2), (18, 2)]:
self.fail('texture coordinates array should be 1x18x2 or 18x1x2')
if isinstance(indices, numpy.ndarray):
if indices.shape not in [(1, 6, 3), (6, 1, 3)]:

@ -285,10 +285,8 @@ PERF_TEST_P(RenderingTest, rasterizeTriangles, ::testing::Combine(
if (shadingType != RASTERIZE_SHADING_WHITE)
{
// let vertices be in BGR format to avoid later color conversions
// cvtColor does not work with 1d Mats
std::vector<Mat> xyz;
cv::split(colors, xyz);
cv::merge(std::vector<Mat>{xyz[2], xyz[1], xyz[0]}, colors);
// mixChannels does not support in-place operation
cv::mixChannels(Mat(colors).clone(), colors, {0, 2, 1, 1, 2, 0});
}
double zNear = 0.1, zFar = 50.0;

@ -140,7 +140,7 @@ void loadMesh(const String &filename, OutputArray vertices, OutputArrayOfArrays
std::vector<std::vector<int32_t>> vec_indices;
std::vector<Point3f> vec_texCoords;
int nTexCoords;
int nTexCoords = 0;
decoder->readData(vec_vertices, vec_normals, vec_rgb, vec_texCoords, nTexCoords, vec_indices, 0);
@ -210,32 +210,30 @@ void loadMesh(const String &filename, OutputArray vertices, OutputArrayOfArrays
if (texCoords.needed())
{
int ch = texCoords.empty() ? 0 : texCoords.channels();
Mat texMat = Mat(1, static_cast<int>(vec_texCoords.size()), CV_MAKETYPE(CV_32F, nTexCoords), vec_texCoords.data());
if (ch == nTexCoords)
{
texMat.copyTo(texCoords);
}
else
if (nTexCoords)
{
Mat newTexMat;
std::vector<Mat> varr;
cv::split(texMat, varr);
if (ch == 2 && nTexCoords == 3)
{
std::vector<Mat> marr = { varr[0], varr[1] };
cv::merge(marr, newTexMat);
}
else if (ch == 3 && nTexCoords == 2)
CV_Assert(!texCoords.fixedType() || (texCoords.type() == CV_MAKE_TYPE(CV_32F, nTexCoords)));
Mat tex3(vec_texCoords);
if (nTexCoords == 3)
{
std::vector<Mat> marr = { varr[0], varr[1], Mat::zeros(varr[0].size(), CV_32F) };
cv::merge(marr, newTexMat);
tex3.copyTo(texCoords);
}
else
else if (nTexCoords == 2)
{
newTexMat = texMat;
// if texCoords is empty then channels() can be any number
bool has3ch = texCoords.channels() == 3;
int ch = has3ch ? 3 : 2;
std::vector<int> permut = has3ch ? std::vector<int>{ 0, 0, 1, 1, -1, 2 } : std::vector<int>{ 0, 0, 1, 1 };
texCoords.createSameSize(vec_texCoords, CV_MAKE_TYPE(CV_32F, ch));
Mat out = texCoords.getMat();
cv::mixChannels(tex3, out, permut);
}
newTexMat.copyTo(texCoords);
}
else
{
texCoords.clear();
}
}
@ -280,7 +278,8 @@ void saveMesh(const String &filename, InputArray vertices, InputArrayOfArrays in
std::vector<std::vector<int32_t>> vec_indices;
CV_Assert(indices.depth() == CV_32S);
if (indices.kind() == _InputArray::KindFlag::STD_VECTOR_VECTOR)
if (indices.kind() == _InputArray::KindFlag::STD_VECTOR_VECTOR ||
indices.kind() == _InputArray::KindFlag::STD_VECTOR_MAT)
{
std::vector<Mat> mat_indices;
indices.getMatVector(mat_indices);
@ -312,13 +311,9 @@ void saveMesh(const String &filename, InputArray vertices, InputArrayOfArrays in
}
if (nTexCoords == 2)
{
std::vector<Point2f> vec2_texCoords;
texCoords.copyTo(vec2_texCoords);
for (size_t i = 0; i < vec2_texCoords.size(); i++)
{
Point2f p = vec2_texCoords[i];
vec_texCoords.push_back({p.x, p.y, 0});
}
// extend by 3rd zero channel
vec_texCoords.resize(texCoords.total());
cv::mixChannels(texCoords, vec_texCoords, {0, 0, 1, 1, -1, 2});
}
if (nTexCoords == 3)
{

@ -11,67 +11,135 @@
namespace opencv_test { namespace {
TEST(PointCloud, LoadPointCloudObj)
struct OriginalObjGoldValues
{
std::vector<cv::Point3f> points_gold = {
{-5.93915f, -0.13257f, 2.55837f},
{-5.93915f, 1.86743f, 2.55837f},
{-5.93915f, -0.13257f, -1.16339f},
{-5.93915f, 1.86743f, -1.16339f},
{0.399941f, -0.13257f, 2.55837f},
{0.399941f, 1.86743f, 2.55837f},
{0.399941f, -0.13257f, -1.16339f},
{0.399941f, 1.86743f, -1.16339f}
};
std::vector<cv::Point3f> normals_gold = {
{-1.0000f, 0.0000f, 0.0000f},
{ 0.0000f, 0.0000f, -1.0000f},
{ 1.0000f, 0.0000f, 0.0000f},
{ 0.0000f, 0.0000f, 1.0000f},
{ 0.0000f, -1.0000f, 0.0000f},
{ 0.0000f, 1.0000f, 0.0000f}
};
std::vector<cv::Point3f> rgb_gold = {
{0.0756f, 0.5651f, 0.5829f},
{0.8596f, 0.1105f, 0.8455f},
{0.8534f, 0.6143f, 0.3950f},
{0.0438f, 0.6308f, 0.3065f},
{0.9716f, 0.7170f, 0.8378f},
{0.2472f, 0.7701f, 0.0234f},
{0.6472f, 0.7467f, 0.5981f},
{0.3502f, 0.7954f, 0.0443f}
};
OriginalObjGoldValues()
{
std::array<float, 6> vals = { -5.93915f, -0.13257f, 2.55837f, 1.86743f, -1.16339f, 0.399941f };
points =
{
{ vals[0], vals[1], vals[2] },
{ vals[0], vals[3], vals[2] },
{ vals[0], vals[1], vals[4] },
{ vals[0], vals[3], vals[4] },
{ vals[5], vals[1], vals[2] },
{ vals[5], vals[3], vals[2] },
{ vals[5], vals[1], vals[4] },
{ vals[5], vals[3], vals[4] },
};
normals =
{
{-1.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, -1.0f},
{ 1.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 1.0f},
{ 0.0f, -1.0f, 0.0f},
{ 0.0f, 1.0f, 0.0f}
};
rgb =
{
{0.0756f, 0.5651f, 0.5829f},
{0.8596f, 0.1105f, 0.8455f},
{0.8534f, 0.6143f, 0.3950f},
{0.0438f, 0.6308f, 0.3065f},
{0.9716f, 0.7170f, 0.8378f},
{0.2472f, 0.7701f, 0.0234f},
{0.6472f, 0.7467f, 0.5981f},
{0.3502f, 0.7954f, 0.0443f}
};
std::vector<std::pair<int, int>> tcvals =
{
{ 3, 0 },
{ 5, 0 },
{ 5, 2 },
{ 3, 2 },
{ 5, 4 },
{ 3, 4 },
{ 5, 6 },
{ 3, 6 },
{ 5, 8 },
{ 3, 8 },
{ 1, 4 },
{ 1, 6 },
{ 7, 4 },
{ 7, 6 },
};
for (const auto& p : tcvals)
{
texCoords.push_back({p.first * 0.125f, p.second * 0.125f});
}
// mesh data is duplicated for each face
std::vector<std::array<int, 9>> fileIndices =
{
{ 1, 1, 1, /**/ 2, 2, 1, /**/ 4, 3, 1 },
{ 3, 4, 2, /**/ 4, 3, 2, /**/ 8, 5, 2 },
{ 7, 6, 3, /**/ 8, 5, 3, /**/ 6, 7, 3 },
{ 5, 8, 4, /**/ 6, 7, 4, /**/ 2, 9, 4 },
{ 3, 11, 5, /**/ 7, 6, 5, /**/ 5, 8, 5 },
{ 8, 5, 6, /**/ 4, 13, 6, /**/ 2, 14, 6 },
};
for (const auto& fi : fileIndices)
{
pointsMesh.push_back(points.at(fi[0] - 1));
pointsMesh.push_back(points.at(fi[3] - 1));
pointsMesh.push_back(points.at(fi[6] - 1));
rgbMesh.push_back(rgb.at(fi[0] - 1));
rgbMesh.push_back(rgb.at(fi[3] - 1));
rgbMesh.push_back(rgb.at(fi[6] - 1));
texCoordsMesh.push_back(texCoords.at(fi[1] - 1));
texCoordsMesh.push_back(texCoords.at(fi[4] - 1));
texCoordsMesh.push_back(texCoords.at(fi[7] - 1));
normalsMesh.push_back(normals.at(fi[2] - 1));
normalsMesh.push_back(normals.at(fi[5] - 1));
normalsMesh.push_back(normals.at(fi[8] - 1));
}
indices =
{
{ 0, 1, 2},
{ 3, 4, 5},
{ 6, 7, 8},
{ 9, 10, 11},
{12, 13, 14},
{15, 16, 17},
};
}
std::vector<Point3f> points, pointsMesh, normals, normalsMesh, rgb, rgbMesh;
std::vector<Point2f> texCoords, texCoordsMesh;
std::vector<std::vector<int32_t>> indices;
};
OriginalObjGoldValues origGold;
TEST(PointCloud, LoadPointCloudObj)
{
std::vector<cv::Point3f> points, normals, rgb;
auto folder = cvtest::TS::ptr()->get_data_path();
cv::loadPointCloud(folder + "pointcloudio/orig.obj", points, normals, rgb);
EXPECT_EQ(points_gold, points);
EXPECT_EQ(rgb_gold, rgb);
EXPECT_EQ(normals_gold, normals);
EXPECT_EQ(origGold.points, points);
EXPECT_EQ(origGold.rgb, rgb);
EXPECT_EQ(origGold.normals, normals);
}
TEST(PointCloud, LoadObjNoNormals)
{
std::vector<cv::Point3f> points_gold = {
{-5.93915f, -0.13257f, 2.55837f},
{-5.93915f, 1.86743f, 2.55837f},
{-5.93915f, -0.13257f, -1.16339f},
{-5.93915f, 1.86743f, -1.16339f},
{0.399941f, -0.13257f, 2.55837f},
{0.399941f, 1.86743f, 2.55837f},
{0.399941f, -0.13257f, -1.16339f},
{0.399941f, 1.86743f, -1.16339f}};
std::vector<cv::Point3f> points, normals;
auto folder = cvtest::TS::ptr()->get_data_path();
cv::loadPointCloud(folder + "pointcloudio/orig_no_norms.obj", points, normals);
EXPECT_EQ(points_gold, points);
EXPECT_EQ(origGold.points, points);
EXPECT_TRUE(normals.empty());
}
@ -125,11 +193,11 @@ TEST(PointCloud, LoadSaveMeshObj)
std::string new_path = tempfile("new_mesh.obj");
cv::loadMesh(folder + "pointcloudio/orig.obj", points, indices, normals, colors, texCoords);
EXPECT_FALSE(points.empty());
EXPECT_FALSE(indices.empty());
EXPECT_FALSE(normals.empty());
EXPECT_FALSE(colors.empty());
EXPECT_FALSE(texCoords.empty());
EXPECT_EQ(origGold.pointsMesh, points);
EXPECT_EQ(origGold.indices, indices);
EXPECT_EQ(origGold.normalsMesh, normals);
EXPECT_EQ(origGold.rgbMesh, colors);
EXPECT_EQ(origGold.texCoordsMesh, texCoords);
cv::saveMesh(new_path, points, indices, normals, colors, texCoords);
std::vector<cv::Point3f> points_gold, normals_gold, colors_gold;
@ -164,8 +232,17 @@ TEST_P(PlyTest, LoadSaveMesh)
std::string new_path = tempfile("new_mesh.ply");
cv::loadMesh(folder + fname, points_gold, indices_gold, normals_gold, colors_gold);
EXPECT_FALSE(points_gold.empty());
EXPECT_FALSE(indices_gold.empty());
size_t truePts, trueFaces;
if (fname.find("/dragon.ply") != fname.npos)
{
truePts = 50000; trueFaces = 100000;
}
else
{
truePts = 8; trueFaces = 12;
}
EXPECT_EQ(points_gold.size(), truePts);
EXPECT_EQ(indices_gold.size(), trueFaces);
cv::saveMesh(new_path, points_gold, indices_gold, normals_gold, colors_gold);

@ -516,13 +516,11 @@ protected:
if (shadingType != RASTERIZE_SHADING_WHITE)
{
// let vertices be in BGR format to avoid later color conversions
// mixChannels() does not support in-place operation
colors = Mat(modelData.colors);
colors.convertTo(colors, ftype);
// let vertices be in BGR format to avoid later color conversions
// cvtColor does not work with 1d Mats
std::vector<Mat> xyz;
cv::split(colors, xyz);
cv::merge(std::vector<Mat>{xyz[2], xyz[1], xyz[0]}, colors);
cv::mixChannels(colors.clone(), colors, {0, 2, 1, 1, 2, 0});
}
indices = Mat(modelData.indices);

@ -1,4 +1,5 @@
#include <iostream>
#include <map>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
@ -78,6 +79,9 @@ public:
upVector = Vec3d(0.0, 1.0, 0.0);
fovy = 45.0;
zNear = 0.1;
zFar = 50;
scaleCoeff = 1000.0;
vertices = std::vector<Vec3f>(4, {2.0f, 0, -2.0f});
colors = std::vector<Vec3f>(4, {0, 0, 1.0f});
@ -91,6 +95,9 @@ public:
upVector = Vec3d( 0.0, 1.0, 0.0);
fovy = 45.0;
zNear = 0.1;
zFar = 50;
scaleCoeff = 1000.0;
objectPath = objPath;
std::vector<vector<int>> indvec;
@ -119,6 +126,9 @@ public:
upVector = Vec3d(0.0, 1.0, 0.0);
fovy = 45.0;
zNear = 0.1;
zFar = 50;
scaleCoeff = 1000.0;
vertices =
{
@ -152,6 +162,9 @@ public:
upVector = Vec3d(0.0, 1.0, 0.0);
fovy = 45.0;
zNear = 0.1;
zFar = 50;
scaleCoeff = 1000.0;
vertices =
{
@ -181,6 +194,9 @@ public:
upVector = Vec3d(0.0, 1.0, 0.0);
fovy = 60.0;
zNear = 0.1;
zFar = 50;
scaleCoeff = 1000.0;
vertices =
{
@ -208,11 +224,35 @@ public:
}
}
ModelData(std::string modelPath, double fov, double near, double far, double scale, Vec3d pos, Vec3d center, Vec3d up)
{
objectPath = modelPath;
position = pos;
lookat = center;
upVector = up;
fovy = fov;
zNear = near;
zFar = far;
scaleCoeff = scale;
std::vector<vector<int>> indvec;
loadMesh(objectPath, vertices, indvec, noArray(), colors);
if (vertices.size() != colors.size())
{
std::runtime_error("Model should contain normals for each vertex");
}
for (const auto &vec : indvec)
{
indices.push_back({vec[0], vec[1], vec[2]});
}
}
Vec3d position;
Vec3d lookat;
Vec3d upVector;
double fovy;
double fovy, zNear, zFar, scaleCoeff;
std::vector<Vec3f> vertices;
std::vector<Vec3i> indices;
@ -239,13 +279,11 @@ void draw(void* userdata)
}
static void generateImage(cv::Size imgSz, TriangleShadingType shadingType, TriangleCullingMode cullingMode,
ModelType modelType, std::string modelPath, cv::Mat& colorImage, cv::Mat& depthImage)
const ModelData& modelData, cv::Mat& colorImage, cv::Mat& depthImage)
{
namedWindow("OpenGL", WINDOW_OPENGL);
resizeWindow("OpenGL", imgSz.width, imgSz.height);
ModelData modelData(modelType, modelPath);
DrawData data;
std::vector<Vec3f> vertices;
@ -293,10 +331,9 @@ static void generateImage(cv::Size imgSz, TriangleShadingType shadingType, Trian
data.arr.setColorArray(colors4f);
data.indices.copyFrom(idxLinear);
double zNear = 0.1, zFar = 50;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(modelData.fovy, (double)imgSz.width / imgSz.height, zNear, zFar);
gluPerspective(modelData.fovy, (double)imgSz.width / imgSz.height, modelData.zNear, modelData.zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
@ -343,10 +380,10 @@ static void generateImage(cv::Size imgSz, TriangleShadingType shadingType, Trian
// map from [0, 1] to [zNear, zFar]
for (auto it = depthImage.begin<float>(); it != depthImage.end<float>(); ++it)
{
*it = (float)(zNear * zFar / (double(*it) * (zNear - zFar) + zFar));
*it = (float)(modelData.zNear * modelData.zFar / (double(*it) * (modelData.zNear - modelData.zFar) + modelData.zFar));
}
cv::flip(depthImage, depthImage, 0);
depthImage.convertTo(depthImage, CV_16U, 1000.0);
depthImage.convertTo(depthImage, CV_16U, modelData.scaleCoeff);
char key = (char)waitKey(40);
if (key == 27)
@ -364,6 +401,26 @@ int main(int argc, char* argv[])
"{ help h usage ? | | show this message }"
"{ outPath | | output path for generated images }"
"{ modelPath | | path to 3d model to render }"
"{ custom | | pass it to use custom camera parameters instead of iterating through test parameters }"
"{ fov | 45.0 | (if custom parameters are used) field of view }"
"{ posx | 1.0 | (if custom parameters are used) camera position x }"
"{ posy | 1.0 | (if custom parameters are used) camera position y }"
"{ posz | 1.0 | (if custom parameters are used) camera position z }"
"{ lookatx | 0.0 | (if custom parameters are used) lookup camera direction x }"
"{ lookaty | 0.0 | (if custom parameters are used) lookup camera direction y }"
"{ lookatz | 0.0 | (if custom parameters are used) lookup camera direction z }"
"{ upx | 0.0 | (if custom parameters are used) up camera direction x }"
"{ upy | 1.0 | (if custom parameters are used) up camera direction y }"
"{ upz | 0.0 | (if custom parameters are used) up camera direction z }"
"{ resx | 640 | (if custom parameters are used) camera resolution x }"
"{ resy | 480 | (if custom parameters are used) camera resolution y }"
"{ zNear | 0.1 | (if custom parameters are used) near z clipping plane }"
"{ zFar | 50 | (if custom parameters are used) far z clipping plane }"
"{ scaleCoeff | 1000 | (if custom parameters are used) scale coefficient for saving depth }"
"{ shading | | (if custom parameters are used) shading type: white/flat/shaded }"
"{ culling | | (if custom parameters are used) culling type: none/cw/ccw }"
"{ colorPath | | (if custom parameters are used) output path for color image }"
"{ depthPath | | (if custom parameters are used) output path for depth image }"
);
parser.about("This app is used to generate test data for triangleRasterize() function");
@ -380,77 +437,109 @@ int main(int argc, char* argv[])
return -1;
}
std::string outPath = parser.get<std::string>("outPath");
if (outPath.empty())
if (parser.has("custom"))
{
std::cout << "No output path given" << std::endl;
return -1;
double fov = parser.get<double>("fov");
Vec3d position, lookat, upVector;
position[0] = parser.get<double>("posx");
position[1] = parser.get<double>("posy");
position[2] = parser.get<double>("posz");
lookat[0] = parser.get<double>("lookatx");
lookat[1] = parser.get<double>("lookaty");
lookat[2] = parser.get<double>("lookatz");
upVector[0] = parser.get<double>("upx");
upVector[1] = parser.get<double>("upy");
upVector[2] = parser.get<double>("upz");
Size res;
res.width = parser.get<int>("resx");
res.height = parser.get<int>("resy");
double zNear = parser.get<double>("zNear");
double zFar = parser.get<double>("zFar");
double scaleCoeff = parser.get<double>("scaleCoeff");
std::map<std::string, cv::TriangleShadingType> shadingTxt = {
{ "white", RASTERIZE_SHADING_WHITE },
{ "flat", RASTERIZE_SHADING_FLAT },
{ "shaded", RASTERIZE_SHADING_SHADED },
};
cv::TriangleShadingType shadingType = shadingTxt.at(parser.get<std::string>("shading"));
std::map<std::string, cv::TriangleCullingMode> cullingTxt = {
{ "none", RASTERIZE_CULLING_NONE },
{ "cw", RASTERIZE_CULLING_CW },
{ "ccw", RASTERIZE_CULLING_CCW },
};
cv::TriangleCullingMode cullingMode = cullingTxt.at(parser.get<std::string>("culling"));
std::string colorPath = parser.get<std::string>("colorPath");
std::string depthPath = parser.get<std::string>("depthPath");
Mat colorImage, depthImage;
ModelData modelData(modelPath, fov, zNear, zFar, scaleCoeff, position, lookat, upVector);
generateImage(res, shadingType, cullingMode, modelData, colorImage, depthImage);
cv::imwrite(colorPath, colorImage);
cv::imwrite(depthPath, depthImage);
}
std::array<cv::Size, 4> resolutions = { cv::Size {700, 700}, cv::Size {640, 480}, cv::Size(256, 256), cv::Size(320, 240) };
for (const auto& res : resolutions)
else
{
for (const auto shadingType : {
RASTERIZE_SHADING_WHITE,
RASTERIZE_SHADING_FLAT,
RASTERIZE_SHADING_SHADED
})
std::string outPath = parser.get<std::string>("outPath");
if (outPath.empty())
{
std::string shadingName;
switch (shadingType)
{
case RASTERIZE_SHADING_WHITE: shadingName = "White"; break;
case RASTERIZE_SHADING_FLAT: shadingName = "Flat"; break;
case RASTERIZE_SHADING_SHADED: shadingName = "Shaded"; break;
default:
break;
}
std::cout << "No output path given" << std::endl;
return -1;
}
for (const auto cullingMode : {
RASTERIZE_CULLING_NONE,
RASTERIZE_CULLING_CW,
RASTERIZE_CULLING_CCW
})
std::array<cv::Size, 4> resolutions = {cv::Size{700, 700}, cv::Size{640, 480}, cv::Size(256, 256), cv::Size(320, 240)};
std::vector<std::pair<cv::TriangleShadingType, std::string>> shadingTxt = {
{RASTERIZE_SHADING_WHITE, "White"},
{RASTERIZE_SHADING_FLAT, "Flat"},
{RASTERIZE_SHADING_SHADED, "Shaded"},
};
std::vector<std::pair<cv::TriangleCullingMode, std::string>> cullingTxt = {
{RASTERIZE_CULLING_NONE, "None"},
{RASTERIZE_CULLING_CW, "CW"},
{RASTERIZE_CULLING_CCW, "CCW"},
};
std::vector<std::pair<ModelType, std::string>> modelTxt = {
{ModelType::File, "File"},
{ModelType::Clipping, "Clipping"},
{ModelType::Color, "Color"},
{ModelType::Centered, "Centered"},
};
for (const auto& res : resolutions)
{
for (const auto shadingPair : shadingTxt)
{
std::string cullingName;
switch (cullingMode)
{
case RASTERIZE_CULLING_NONE: cullingName = "None"; break;
case RASTERIZE_CULLING_CW: cullingName = "CW"; break;
case RASTERIZE_CULLING_CCW: cullingName = "CCW"; break;
default: break;
}
cv::TriangleShadingType shadingType = shadingPair.first;
std::string shadingName = shadingPair.second;
for (const auto modelType : {
ModelType::File,
ModelType::Clipping,
ModelType::Color,
ModelType::Centered,
})
for (const auto cullingPair : cullingTxt)
{
std::string modelName;
switch (modelType)
cv::TriangleCullingMode cullingMode = cullingPair.first;
std::string cullingName = cullingPair.second;
for (const auto modelPair : modelTxt)
{
case ModelType::File: modelName = "File"; break;
case ModelType::Clipping: modelName = "Clipping"; break;
case ModelType::Color: modelName = "Color"; break;
case ModelType::Centered: modelName = "Centered"; break;
default:
break;
}
ModelType modelType = modelPair.first;
std::string modelName = modelPair.second;
std::string suffix = cv::format("%s_%dx%d_Cull%s", modelName.c_str(), res.width, res.height, cullingName.c_str());
std::string suffix = cv::format("%s_%dx%d_Cull%s", modelName.c_str(), res.width, res.height, cullingName.c_str());
std::cout << suffix + "_" + shadingName << "..." << std::endl;
std::cout << suffix + "_" + shadingName << "..." << std::endl;
cv::Mat colorImage, depthImage;
generateImage(res, shadingType, cullingMode, modelType, modelPath, colorImage, depthImage);
cv::Mat colorImage, depthImage;
std::string gtPathColor = outPath + "/example_image_" + suffix + "_" + shadingName + ".png";
std::string gtPathDepth = outPath + "/depth_image_" + suffix + ".png";
ModelData modelData(modelType, modelPath);
generateImage(res, shadingType, cullingMode, modelData, colorImage, depthImage);
cv::imwrite(gtPathColor, colorImage);
cv::imwrite(gtPathDepth, depthImage);
std::string gtPathColor = outPath + "/example_image_" + suffix + "_" + shadingName + ".png";
std::string gtPathDepth = outPath + "/depth_image_" + suffix + ".png";
cv::imwrite(gtPathColor, colorImage);
cv::imwrite(gtPathDepth, depthImage);
}
}
}
}

Loading…
Cancel
Save