【点云】做一个爱心点云


前言

闲着没事,逛csdn,看到之前很火的李峋的c语言爱心代码很火,试试能不能做一个三维的爱心。
前提:
pip install open3d

心形函数

老规矩,查找wiki百科心形函数,发现三维的有个函数如下:
在这里插入图片描述
也没找到这个函数是怎么得出来的,姑且,直接套用。

有一个点需要注意一下:当z=0时x2+9y2/4=1,是个椭圆,也就是说中间那块是个椭圆。然后x=0和y=0时,参照下图应该也是个心形。
在这里插入图片描述

绘制

点云的简单绘制步骤

点云的格式为numpy下的[[1,2,3],[4,5,6],[7,8,9]]

# 创建一个空的点云列表
points = []
# 将点云列表转换为 numpy 数组
points = np.array(points)
# 创建 open3d 点云对象
pcd = o3d.geometry.PointCloud()
# 更新点云的坐标
pcd.points = o3d.utility.Vector3dVector(points)
# 改变点云的颜色
pcd.paint_uniform_color([1, 0, 0])
# 可视化点云
o3d.visualization.draw_geometries([pcd])
# 保存点云
o3d.io.write_point_cloud("heart.pcd", pcd)

代码

# 导入 numpy 和 open3d 库
import numpy as np
import open3d as o3d

# 定义满足式子的函数
def f(x, y, z):
    return (x**2 + 9*y**2/4 + z**2 - 1)**3 - x**2*z**3 - 9*y**2*z**3/200

# 生成 x, y, z 的值
# 生成随机数
np.random.seed(0)
# 生成 x, y, z 的值
x = np.random.uniform(-1.2, 1.2, 200) # 
y = np.random.uniform(-0.7, 0.7, 200)
z = np.random.uniform(-0.98, 1.24, 200)
# x = np.linspace(-1.1, 1.1, 200)
# y = np.linspace(-0.7, 0.7, 200)
# z = np.linspace(-0.98, 1.24, 200)

# 创建一个空的点云列表
points = []

# 遍历 x, y, z 的值,找出满足式子的点
for i in x:
    for j in y:
        for k in z:
            # 如果 f(i, j, k) 接近于 0,说明该点满足式子
            if abs(f(i, j, k)) < 1e-4:
                # 将该点的坐标添加到点云列表中
                points.append([i, j, k])

# 将点云列表转换为 numpy 数组
points = np.array(points)


# 创建 open3d 点云对象
pcd = o3d.geometry.PointCloud()
# 更新点云的坐标
pcd.points = o3d.utility.Vector3dVector(points)
# 改变点云的颜色
pcd.paint_uniform_color([1, 0, 0])

voxel_size = 0.2
downpcd = pcd.voxel_down_sample(voxel_size)

# 坐标轴
coord = o3d.geometry.TriangleMesh.create_coordinate_frame(size=1, origin=[0, 0, 0])#x红色,y绿色,z蓝色
# 可视化点云
# 设置视角的参数
lookat = [0, 0, 0] # 相机的观察点,设为原点
up = [0, 0, 1] # 相机的上方向,
front = [0, 1, 0] # 相机的前方向,
zoom = 1 # 相机的缩放比例,
o3d.visualization.draw_geometries([downpcd], window_name='Point Cloud', width=800, height=600,lookat=lookat, up=up, front=front, zoom=zoom)


# 保存点云
o3d.io.write_point_cloud("heart.pcd", pcd)


结果展示:

在这里插入图片描述

遇到的问题

1、范围问题:一开始 x = np.linspace(-2, 2, 200),发现好多点分布不均匀,且密度很小。

解决方法1、使用np.random.uniform() 从均匀分布中随机生成一些数来解决分布不均问题。
2、打印points的各个轴(points[:,0])的最大最小值,让密度更大。

2、接近问题:由于函数是=0,但实际上很多点是满足不了的,(如果点增加太多,循环执行很慢)所以找到一个还算可以的极限值1e-4,点也不少,中间那个椭圆形也会不明显一点。

3、z=0时,椭圆形明显问题导致爱心中间突出一块,很丑,所以选择了点云的下采样,选择了一个合适的值,保留了爱心原有的特征。
不进行下采样,那个突出的椭圆上的点真的很难看。
下采样前:
在这里插入图片描述
可能的解决方法,当点够多时,三循环的速度更快时,更接近函数=0时或许就不用下采样了。
有厉害的大佬可以评论区评论下。
后来想了半天,也没有适合的,找到这篇如何画心形函数?或许在定义心形函数上的参数有些启发,最后改成如下:(让椭圆里的b小一些)
在这里插入图片描述
还算稍微好了些。
或许总该有残缺才算完美。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值