Ask Your Question
0

Converting Mat of point cloud mesh to vector<cv::Point3d>

asked 2020-11-27 07:16:16 -0500

sigmoid90 gravatar image

updated 2020-11-27 09:02:52 -0500

My task is to project a point cloud of a scene to a plane image. I have 3D point cloud of scene represented as PLY mesh. Here is header an d few data lines in this PLY file:

ply
format ascii 1.0
comment PCL generated
element vertex 180768
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
property float nx
property float ny
property float nz
property float curvature
element camera 1
property float view_px
property float view_py
property float view_pz
property float x_axisx
property float x_axisy
property float x_axisz
property float y_axisx
property float y_axisy
property float y_axisz
property float z_axisx
property float z_axisy
property float z_axisz
property float focal
property float scalex
property float scaley
property float centerx
property float centery
property int viewportx
property int viewporty
property float k1
property float k2
end_header
0.021613657 0.60601699 -1.5027865 120 89 71 -0.92790836 -0.26353598 0.26369458 0.00016434079
-1.1746287 -1.7522405 -1.4859273 193 128 72 0.093781963 -0.043701902 0.99463314 0.048953384

I have found a way to project point cloud to image here. So far I load PLY model to cv::Mat using function loadPLYSimple from ppf_match_3d.

Mat scene_mat = loadPLYSimple("a_cloud.ply", 1);

I need to convert Mat representing the scene clout to vector<cv::point3d>. My Mat scene_mat has size: [6 x 180768]. How I can do it?

edit retag flag offensive close merge delete

Comments

please add the ply header to your question (and maybe the first few data lines), so we can estimate, what's in it

(the point data is probably float, not double, and there are either normals or colors present, but please show !)

also, the size() of your corresponding 2d image ?

berak gravatar imageberak ( 2020-11-27 08:31:41 -0500 )edit
1

I have updated the question with listing header an d few data lines in this PLY file. The size() is the size of the scene_mat Mat object.

sigmoid90 gravatar imagesigmoid90 ( 2020-11-27 09:04:21 -0500 )edit

can you also print out the 1st 2 lines of your scene_mat ? like:

cout << scene_mat(Rect(0,0,6,2)) << endl;

i'm afraid, the loadPLYSimple() method is a bit too simple for this task (it won't read colors properly, and assumes data is x,y,z,nx,ny,nz)

berak gravatar imageberak ( 2020-11-27 09:45:25 -0500 )edit
1

printing out the 1st 2 lines of my scene_mat gives this:

[0.021613657, 0.60601699, -1.5027865, 0.72544974, 0.53804189, 0.42922443;
 -0.92790836, -0.26353598, 0.26369458, 7.7904137e-05, -0.55682117, -0.83063239]

So is there another way to load PLY mesh in OpenCV?

sigmoid90 gravatar imagesigmoid90 ( 2020-11-27 10:05:55 -0500 )edit
1

Btw pcl_mesh2pcd gives me Segmentation fault (vtkPLYReader (0xe0f6e0): Cannot read geometry)

sigmoid90 gravatar imagesigmoid90 ( 2020-11-27 11:02:41 -0500 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2020-11-30 05:18:47 -0500

berak gravatar image

updated 2020-11-30 05:23:37 -0500

so, opencv's loadPLYSimple() won't work for your data. you could try to adapt the code from here to fit your specific needs, like:

#include <opencv2/opencv.hpp>
using namespace cv;

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

static std::vector<std::string> split(const std::string &text, char sep) {
  std::vector<std::string> tokens;
  std::size_t start = 0, end = 0;
  while ((end = text.find(sep, start)) != std::string::npos) {
    tokens.push_back(text.substr(start, end - start));
    start = end + 1;
  }
  tokens.push_back(text.substr(start));
  return tokens;
}



bool loadPLY(const char* fileName, std::vector<Point3f> &points, std::vector<Vec3b> &colors)
{
    int numVertices = 0;

    std::ifstream ifs(fileName);

    if (!ifs.is_open())
        CV_Error(Error::StsError, String("Error opening input file: ") + String(fileName) + "\n");

    std::string str;
    while (str.substr(0, 10) != "end_header")
    {
        std::vector<std::string> tokens = split(str,' ');
        if (tokens.size() == 3)
        {
            if (tokens[0] == "element" && tokens[1] == "vertex")
            {
                numVertices = atoi(tokens[2].c_str());
            }
        }
        else if (tokens.size() > 1 && tokens[0] == "format" && tokens[1] != "ascii")
            CV_Error(Error::StsBadArg, String("Cannot read file, only ascii ply format is currently supported..."));
        std::getline(ifs, str);
    }
    for (int i = 0; i < numVertices; i++)
    {
        float x,y,z,nx,ny,nz,curvature; // read *all* in, but only keep points & colors
        int r,g,b;
        ifs >> x >> y >> z >> r >> g >> b >> nx >> ny >> nz >> curvature;
        points.push_back(Point3f(x,y,z));
        colors.push_back(Vec3b(b,g,r));
    }
    return true;
}

int main() {

    std::vector<Point3f> points;
    std::vector<Vec3b> colors;

    loadPLY("cloud.ply", points, colors);
    cout << points[0] << points[1] << endl; // go check, if this is correct !
    cout << colors[0] << colors[1] << endl;
    return 0;
}

then, you could try to render an image from it:

int W = draw_img.cols;
int H = draw_img.rows;
float focal = 5; // e.g from the ply !

// project to 2d
Point p(focal * points[i].x / points[i].z, focal * points[i].y / points[i].z); 

// scale/offset to img coords
p.x = p.x * W/2 + W/2; 
p.y = p.y * H/2 + H/2;

// filled circle of some size
cv::circle(draw_img, p, 3, colors[i], -1);
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2020-11-27 07:16:16 -0500

Seen: 53 times

Last updated: Nov 30 '20