怎么从电脑后端传点云文件(pcd、ply格式)到安卓app,app能把点云显示出来?

怎么从电脑后端传点云文件(pcd、ply格式)到安卓app,app能把点云显示出来?
后端为python Flask,发送的数据为response_data,包括浮点数、图片和点云。
radius_cloud为open3d.geometry.PointCloud格式数据,我目前的处理是获取点的坐标值,是一个二维数组,进行传输,但是在安卓前端不知道怎么利用这个数组显示点云。

    cloud_list=np.asarray(radius_cloud.points).tolist()
    response_data=[{
        "height":height,
        "rel_depth":rel_depth,
        "mask":mask,
        "tree_cloud":cloud_list
    }]
    json_str = json.dumps(response_data)
return json_str

我找到一个安卓app显示点云的示例:https://blog.csdn.net/zzhceo/article/details/126303089
但是其使用的点云数据是.raw格式,且从手机内存读取。
我的问题是:怎么从电脑后端传点云文件(pcd、ply格式)到安卓app,app能把点云显示出来?
或者有没有办法在android(java)中利用彩色图和深度图生成三维点云?

看看raw格式是什么,是否可以转换,写一个转换程序适配下

可以在 Flask 后端将点云文件以二进制流的形式发送给安卓前端,然后在安卓前端使用类似 CSDN 示例中的方法读取点云数据,然后使用 Open3D 或其他点云可视化工具来显示点云。

回答引用ChatGPT:
要将点云文件从电脑后端传输到安卓应用程序,可以通过网络传输协议(例如HTTP)将点云数据作为响应(response)发送到安卓应用程序。

可以将点云数据转换为二进制格式,例如PLY或PCD格式,然后将其作为HTTP响应的一部分发送到安卓应用程序。在安卓应用程序中,可以使用相应的库(例如pcl或open3d)加载点云数据,并将其显示在屏幕上。

以下是一个可能的实现方法:
1 在电脑后端中,使用open3d或pcl库将点云数据读取为PointCloud对象,并将其转换为PLY或PCD格式的二进制数据。

import open3d as o3d

point_cloud = o3d.io.read_point_cloud("example.ply")
point_cloud_binary = point_cloud.to_legacy_format()

2 将点云数据作为HTTP响应发送到安卓应用程序。您可以使用Python的Flask库来实现这一点。

from flask import Flask, Response

app = Flask(__name__)

@app.route('/pointcloud')
def send_pointcloud():
    point_cloud = o3d.io.read_point_cloud("example.ply")
    point_cloud_binary = point_cloud.to_legacy_format()
    return Response(point_cloud_binary, mimetype='application/octet-stream')

3 安卓应用程序中,使用HttpClient库从后端服务器获取点云数据,并将其加载到PointCloud对象中。以下是一个简单的示例代码:

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;

// Fetch point cloud data from the server
String url = "http://your_server/pointcloud";
HttpGet httpGet = new HttpGet(url);
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(httpGet);

// Read the binary data from the response
byte[] pointCloudBytes = EntityUtils.toByteArray(response.getEntity());

// Load the binary data into a PointCloud object
InputStream stream = new ByteArrayInputStream(pointCloudBytes);
ByteBuffer buffer = ByteBuffer.wrap(pointCloudBytes);
PointCloud pointCloud = new PointCloud();
pointCloud.fromLegacyFormat(buffer);

4 在安卓应用程序中,使用OpenGL或Vulkan等图形API来将点云数据渲染到屏幕上。您可以使用PointCloudRenderer库来实现这一点。

import android.opengl.GLSurfaceView;
import android.content.Context;
import android.opengl.GLES20;
import org.open3d.PointCloud;
import org.open3d.PointCloudRenderer;

public class MyGLSurfaceView extends GLSurfaceView {

    private final PointCloudRenderer renderer;
    private final PointCloud pointCloud;

    public MyGLSurfaceView(Context context) {
        super(context);
        
        // Load point cloud data from the server
        String url = "http://your_server/pointcloud";
        HttpGet httpGet = new HttpGet(url);
        DefaultHttpClient client = new DefaultHttpClient();
        HttpResponse response = client.execute(httpGet);
        byte[] pointCloudBytes = EntityUtils.toByteArray(response.getEntity());
        ByteBuffer buffer = ByteBuffer.wrap(pointCloudBytes);
        pointCloud = new PointCloud();
        pointCloud.fromLegacyFormat(buffer);

// Display point cloud data in the Android app
        PointCloudRenderer renderer = new PointCloudRenderer();
        renderer.update(pointCloud);
        renderer.setCameraPose(cameraPose); // Optional camera pose
        view.setRenderer(renderer);

这段代码使用了一个名为 PointCloudRenderer 的渲染器来显示点云数据。首先,我们需要创建一个 PointCloudRenderer 实例,然后调用 update() 方法,将从服务器获取到的点云数据传递给渲染器。

如果您想要设置相机姿态,可以使用 setCameraPose() 方法,将相机姿态传递给渲染器。最后,将渲染器设置为视图(View)的渲染器,这样就能在安卓设备上显示点云数据了。
PointCloudRenderer 是一个自定义的类,需要您根据您的需要自行实现。通常,这个类应该继承自 GLSurfaceView.Renderer 类,以实现 OpenGL 渲染器。在 update() 方法中,您需要将点云数据转换为适合 OpenGL 渲染的格式,例如使用 VertexBuffer 和 IndexBuffer。
总之,如果您能够将从服务器获取的点云数据转换为适合 OpenGL 渲染的格式,并实现一个自定义的 PointCloudRenderer 类来渲染点云数据,那么您就能够在安卓设备上显示点云数据了。

想要将点云数据从 Python 后端传输到安卓前端并正确显示,有多种可行的方式,以下是其中几种建议:

将点云数据转换为类似 PLY 或者 OBJ 等标准格式,然后发送到安卓前端,使用安卓开源库如 min3d 等展示点云数据。

将点云数据序列化为字符串,然后发送到安卓前端,在安卓前端使用 Java 开源库如 jPCT-AE 等解析点云数据并显示

感谢!但是

point_cloud_binary = point_cloud.to_legacy_format()

报错了,似乎没有这种用法

AttributeError: 'open3d.cpu.pybind.geometry.PointCloud' object has no attribute 'to_legacy_format'

以下答案由GPT-3.5大模型与博主波罗歌共同编写:

  1. 从电脑后端传点云文件(pcd、ply格式)到安卓app

可以使用HTTP协议进行文件传输。在Python Flask后端中,使用Flask的send_file方法将点云文件返回给客户端。在安卓应用中,使用HttpURLConnection或OkHttp库进行文件下载。

Python Flask代码:

from flask import Flask, send_file

app = Flask(__name__)

@app.route('/get_pcd')
def get_pcd():
    return send_file('path/to/pcd', attachment_filename='pcd.pcd', as_attachment=True)

Android Java代码:

URL url = new URL("http://10.0.2.2:5000/get_pcd");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream("path/to/local/pcd.pcd");

byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
    outputStream.write(buffer, 0, len);
}

outputStream.close();
inputStream.close();
connection.disconnect();
  1. 在android(java)中利用彩色图和深度图生成三维点云

可以使用OpenCV库和Open3D库进行处理。首先,将彩色图片和深度图转换为点云。然后使用Java OpenGL ES对点云进行渲染。

Java代码:

// 读取彩色图片和深度图
Mat colorImage = Imgcodecs.imread("path/to/color/image", Imgcodecs.IMREAD_COLOR);
Mat depthImage = Imgcodecs.imread("path/to/depth/image", Imgcodecs.IMREAD_ANYDEPTH);

// 将深度图转换为点云
MatOfPoint3f point3D = new MatOfPoint3f();
MatOfPoint2f point2D = new MatOfPoint2f();
MatOfFloat cameraMatrix = new MatOfFloat( // 相机内参
        fx, 0, cx,
        0, fy, cy,
        0, 0, 1);
MatOfFloat distCoeffs = new MatOfFloat(k1, k2, p1, p2);
Imgproc.depthTo3d(depthImage, cameraMatrix, point3D);

// 将点云转换为Open3D的PointCloud格式
float[] pointArray = new float[(int) (point3D.total() * point3D.channels())];
point3D.get(0, 0, pointArray);
List<Point3d> points = new ArrayList<>();
for (int i = 0; i < pointArray.length; i += 3) {
    points.add(new Point3d(pointArray[i], pointArray[i + 1], pointArray[i + 2]));
}
PointCloud pointCloud = new PointCloud();
pointCloud.points = new Vector3dVector(points);

// 渲染点云
GLSurfaceView glView = findViewById(R.id.gl_view);
glView.setRenderer(new PointCloudRenderer(pointCloud));

其中,PointCloudRenderer是自定义的OpenGL渲染器,继承自GLSurfaceView.Renderer。它的实现可以参考Open3D库中的gl_draw_geometry.cpp文件。
如果我的回答解决了您的问题,请采纳!