From e472d45d999bf3bcab5b5c7afe051d5854ef0d56 Mon Sep 17 00:00:00 2001
From: Anatoly Baksheev <no@email>
Date: Mon, 13 Jan 2014 13:30:34 +0400
Subject: [PATCH] updated mesh reading (texture support)

---
 modules/viz/include/opencv2/viz.hpp     |   5 +-
 modules/viz/src/precomp.hpp             |   1 +
 modules/viz/src/types.cpp               | 120 ++++++++++--------------
 modules/viz/src/vtk/vtkCloudMatSink.cpp |  25 ++++-
 modules/viz/src/vtk/vtkCloudMatSink.h   |   4 +-
 5 files changed, 77 insertions(+), 78 deletions(-)

diff --git a/modules/viz/include/opencv2/viz.hpp b/modules/viz/include/opencv2/viz.hpp
index 89810d547..a532ba783 100644
--- a/modules/viz/include/opencv2/viz.hpp
+++ b/modules/viz/include/opencv2/viz.hpp
@@ -99,9 +99,10 @@ namespace cv
         CV_EXPORTS Mat  readCloud (const String& file, OutputArray colors = noArray(), OutputArray normals = noArray());
 
         ///////////////////////////////////////////////////////////////////////////////////////////////
-        /// Read mesh. Only ply format is supported now
+        /// Reads mesh. Only ply format is supported now. The function tries to read texture from png-file,
+        /// and in case of faulure, just leaves the texture field empty.
 
-        CV_EXPORTS Mesh readMesh (const String& file);
+        CV_EXPORTS Mesh readMesh(const String& file);
 
         ///////////////////////////////////////////////////////////////////////////////////////////////
         /// Read/write poses and trajectories
diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp
index d5f969a49..bf154e76e 100644
--- a/modules/viz/src/precomp.hpp
+++ b/modules/viz/src/precomp.hpp
@@ -122,6 +122,7 @@
 #include <vtkPLYReader.h>
 #include <vtkOBJReader.h>
 #include <vtkSTLReader.h>
+#include <vtkPNGReader.h>
 #include <vtkOBJExporter.h>
 #include <vtkVRMLExporter.h>
 #include <vtkTensorGlyph.h>
diff --git a/modules/viz/src/types.cpp b/modules/viz/src/types.cpp
index 09a2f4d0f..bf61432cb 100644
--- a/modules/viz/src/types.cpp
+++ b/modules/viz/src/types.cpp
@@ -57,80 +57,56 @@ cv::viz::MouseEvent::MouseEvent(const Type& _type, const MouseButton& _button, c
 ////////////////////////////////////////////////////////////////////
 /// cv::viz::Mesh3d
 
-namespace cv { namespace viz { namespace
-{
-    struct MeshUtils
-    {
-        static Mesh loadMesh(const String &file)
-        {
-            Mesh mesh;
-
-            vtkSmartPointer<vtkPLYReader> reader = vtkSmartPointer<vtkPLYReader>::New();
-            reader->SetFileName(file.c_str());
-            reader->Update();
-
-            vtkSmartPointer<vtkPolyData> poly_data = reader->GetOutput();
-            CV_Assert("File does not exist or file format is not supported." && poly_data);
-
-            vtkSmartPointer<vtkPoints> mesh_points = poly_data->GetPoints();
-            vtkIdType nr_points = mesh_points->GetNumberOfPoints();
-
-            mesh.cloud.create(1, nr_points, CV_32FC3);
-
-            Vec3f *mesh_cloud = mesh.cloud.ptr<Vec3f>();
-            for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints(); i++)
-            {
-                Vec3d point;
-                mesh_points->GetPoint(i, point.val);
-                mesh_cloud[i] = point;
-            }
-
-            // Then the color information, if any
-            vtkUnsignedCharArray* poly_colors = 0;
-            if (poly_data->GetPointData())
-                poly_colors = vtkUnsignedCharArray::SafeDownCast(poly_data->GetPointData()->GetScalars());
-
-            if (poly_colors && (poly_colors->GetNumberOfComponents() == 3))
-            {
-                mesh.colors.create(1, nr_points, CV_8UC3);
-                Vec3b *mesh_colors = mesh.colors.ptr<cv::Vec3b>();
-
-                for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints(); i++)
-                {
-                    Vec3b point_color;
-                    poly_colors->GetTupleValue(i, point_color.val);
-
-                    std::swap(point_color[0], point_color[2]); // RGB -> BGR
-                    mesh_colors[i] = point_color;
-                }
-            }
-            else
-                mesh.colors.release();
-
-            // Now handle the polygons
-            vtkIdType* cell_points;
-            vtkIdType nr_cell_points;
-            vtkCellArray * mesh_polygons = poly_data->GetPolys();
-            mesh_polygons->InitTraversal();
-
-            mesh.polygons.create(1, mesh_polygons->GetSize(), CV_32SC1);
-
-            int* polygons = mesh.polygons.ptr<int>();
-            while (mesh_polygons->GetNextCell(nr_cell_points, cell_points))
-            {
-                *polygons++ = nr_cell_points;
-                for (int i = 0; i < nr_cell_points; ++i)
-                    *polygons++ = static_cast<int>(cell_points[i]);
-            }
-
-            return mesh;
-        }
-    };
-}}}
-
 cv::viz::Mesh cv::viz::Mesh::load(const String& file)
 {
-    return MeshUtils::loadMesh(file);
+    vtkSmartPointer<vtkPLYReader> reader = vtkSmartPointer<vtkPLYReader>::New();
+    reader->SetFileName(file.c_str());
+    reader->Update();
+
+    vtkSmartPointer<vtkPolyData> polydata = reader->GetOutput();
+    CV_Assert("File does not exist or file format is not supported." && polydata);
+
+    Mesh mesh;
+    vtkSmartPointer<vtkCloudMatSink> sink = vtkSmartPointer<vtkCloudMatSink>::New();
+    sink->SetOutput(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords);
+    sink->SetInputConnection(reader->GetOutputPort());
+    sink->Write();
+
+    // Now handle the polygons
+
+    vtkSmartPointer<vtkCellArray> polygons = polydata->GetPolys();
+    mesh.polygons.create(1, polygons->GetSize(), CV_32SC1);
+    int* poly_ptr = mesh.polygons.ptr<int>();
+
+    polygons->InitTraversal();
+    vtkIdType nr_cell_points, *cell_points;
+    while (polygons->GetNextCell(nr_cell_points, cell_points))
+    {
+        *poly_ptr++ = nr_cell_points;
+        for (vtkIdType i = 0; i < nr_cell_points; ++i)
+            *poly_ptr++ = (int)cell_points[i];
+    }
+
+    String::size_type pos = file.find_last_of('.');
+    String png = (pos == String::npos) ? file : file.substr(0, pos+1) + "png";
+
+    vtkSmartPointer<vtkPNGReader> png_reader = vtkSmartPointer<vtkPNGReader>::New();
+
+    if (png_reader->CanReadFile(png.c_str()))
+    {
+        png_reader->SetFileName(png.c_str());
+        png_reader->Update();
+        vtkSmartPointer<vtkImageData> imagedata = png_reader->GetOutput();
+
+        Size sz(imagedata->GetDimensions()[0], imagedata->GetDimensions()[1]);
+        int channels = imagedata->GetNumberOfScalarComponents();
+        CV_Assert(imagedata->GetScalarType() == VTK_UNSIGNED_CHAR);
+
+        void *ptr = imagedata->GetScalarPointer(0,0,0);
+        Mat(sz, CV_8UC(channels), ptr).copyTo(mesh.texture);
+    }
+
+    return mesh;
 }
 
 ////////////////////////////////////////////////////////////////////
diff --git a/modules/viz/src/vtk/vtkCloudMatSink.cpp b/modules/viz/src/vtk/vtkCloudMatSink.cpp
index cf1eb4648..09ef0cca9 100644
--- a/modules/viz/src/vtk/vtkCloudMatSink.cpp
+++ b/modules/viz/src/vtk/vtkCloudMatSink.cpp
@@ -52,11 +52,12 @@ namespace cv { namespace viz
 cv::viz::vtkCloudMatSink::vtkCloudMatSink() {}
 cv::viz::vtkCloudMatSink::~vtkCloudMatSink() {}
 
-void cv::viz::vtkCloudMatSink::SetOutput(OutputArray _cloud, OutputArray _colors, OutputArray _normals)
+void cv::viz::vtkCloudMatSink::SetOutput(OutputArray _cloud, OutputArray _colors, OutputArray _normals, OutputArray _tcoords)
 {
     cloud = _cloud;
     colors = _colors;
     normals = _normals;
+    tcoords = _tcoords;
 }
 
 void cv::viz::vtkCloudMatSink::WriteData()
@@ -120,12 +121,32 @@ void cv::viz::vtkCloudMatSink::WriteData()
         Mat buffer(cloud.size(), CV_64FC(channels));
         Vec3d *cptr = buffer.ptr<Vec3d>();
         for(size_t i = 0; i < buffer.total(); ++i)
-            *cptr++ = Vec3d(scalars_data->GetTuple(i));
+            *cptr++ = Vec3d(normals_data->GetTuple(i));
 
         buffer.convertTo(normals, vtktype == VTK_FLOAT ? CV_32F : CV_64F);
     }
     else
         normals.release();
+
+    vtkSmartPointer<vtkDataArray> coords_data = input->GetPointData() ? input->GetPointData()->GetTCoords() : 0;
+
+    if (tcoords.needed() && coords_data)
+    {
+        int vtktype = coords_data->GetDataType();
+
+        CV_Assert(vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE);
+        CV_Assert(cloud.total() == (size_t)coords_data->GetNumberOfTuples());
+
+        Mat buffer(cloud.size(), CV_64FC2);
+        Vec2d *cptr = buffer.ptr<Vec2d>();
+        for(size_t i = 0; i < buffer.total(); ++i)
+            *cptr++ = Vec2d(coords_data->GetTuple(i));
+
+        buffer.convertTo(tcoords, vtktype == VTK_FLOAT ? CV_32F : CV_64F);
+
+    }
+    else
+        tcoords.release();
 }
 
 void cv::viz::vtkCloudMatSink::PrintSelf(ostream& os, vtkIndent indent)
diff --git a/modules/viz/src/vtk/vtkCloudMatSink.h b/modules/viz/src/vtk/vtkCloudMatSink.h
index 69262f247..3af9e6544 100644
--- a/modules/viz/src/vtk/vtkCloudMatSink.h
+++ b/modules/viz/src/vtk/vtkCloudMatSink.h
@@ -59,7 +59,7 @@ namespace cv
           vtkTypeMacro(vtkCloudMatSink,vtkPolyDataWriter)
           void PrintSelf(ostream& os, vtkIndent indent);
 
-          void SetOutput(OutputArray cloud, OutputArray colors = noArray(), OutputArray normals = noArray());
+          void SetOutput(OutputArray cloud, OutputArray colors = noArray(), OutputArray normals = noArray(), OutputArray tcoords = noArray());
 
         protected:
           vtkCloudMatSink();
@@ -67,7 +67,7 @@ namespace cv
 
           void WriteData();
 
-          _OutputArray cloud, colors, normals;
+          _OutputArray cloud, colors, normals, tcoords;
 
         private:
           vtkCloudMatSink(const vtkCloudMatSink&);  // Not implemented.