graspnet+Astra2相机实现部署

graspnet+Astra2相机实现部署

🚀 环境配置 🚀

  • ubuntu 20.04
  • Astra2相机
  • cuda 11.0.1
  • cudnn v8.9.7
  • python 3.8.19
  • pytorch 1.7.0
  • numpy 1.23.5

1. graspnet的复现

具体的复现流程可以参考这篇文章:Ubuntu20.04下GraspNet复现流程

这里就不再详细介绍了

2. Astra2的Python API

以下内容都是参考官方文档:Orbbec SDK for Python 使用手册

我们首先确认输入到网络中的数据为一个点云数据,再一个我们需要一个rgb图像用来给点云上色,graspnetAPI帮我们写好了从深度图转换到点云的函数create_point_cloud_from_depth_image,所以我们只需要写好从相机的视频流获取深度图片和rgb图片的部分就好了,特别注意的是,大多数相机的rgb的fov是要大于深度图的fov所以我们要对两者进行对齐操作,对齐操作的本质就是在深度图中填充0,使得深度图和rgb图的大小一致。大多数的相机厂商已经提供了具体的示例来演示如何进行对齐,这里就不再赘述。

这里我直接给出我写的astra2.py,用于获取相机的深度图和rgb图的代码,大家可以参考一下思路

astra2.py

from pyorbbecsdk import *
import numpy as np
import cv2
import os
import open3d as o3d

class Camera:
    def __init__(self, width=1280, height=720,fps=15):
        self.im_width = width
        self.im_height = height
        self.fps = fps
        self.intrinsic = None
        self.scale = None

        # 连接相机
        # self.connect()
    
    def connect(self):
        """用于连接相机"""
        self.pipeline = Pipeline()
        config = Config()

        # color config
        profile_list = self.pipeline.get_stream_profile_list(OBSensorType.COLOR_SENSOR)
        color_profile = profile_list.get_default_video_stream_profile()
        config.enable_stream(color_profile)
        # depth config
        profile_list = self.pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR)
        assert profile_list is not None
        depth_profile = profile_list.get_default_video_stream_profile()
        assert depth_profile is not None
        print("color profile : {}x{}@{}_{}".format(color_profile.get_width(),
                                                   color_profile.get_height(),
                                                   color_profile.get_fps(),
                                                   color_profile.get_format()))
        print("depth profile : {}x{}@{}_{}".format(depth_profile.get_width(),
                                                   depth_profile.get_height(),
                                                   depth_profile.get_fps(),
                                                   depth_profile.get_format()))
        config.enable_stream(depth_profile)
        # set synchronize for depth img and color img
        config.set_align_mode(OBAlignMode.SW_MODE)
        self.pipeline.enable_frame_sync()
        # start config
        self.pipeline.start(config)

        # get intrinsic
        self.intrinsic = self.get_intrinsic()
    
    def disconnect(self):
        """用于断开相机"""
        self.pipeline.stop()
    

    def get_frame(self):
        """通过流来获取color frame和depth frame"""
        while True:
            frames: FrameSet = self.pipeline.wait_for_frames(200)
            if frames is None:
                continue
            color_frame = frames.get_color_frame()
            if color_frame is None:
                continue
            depth_frame = frames.get_depth_frame()
            if depth_frame is None:
                continue
            if color_frame != None and depth_frame != None:
                break
        
        return color_frame, depth_frame

    def frame2data(self, color_frame, depth_frame):
        """暂时没用"""
        width = depth_frame.get_width()
        height = depth_frame.get_height()
        scale = depth_frame.get_depth_scale()
        depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16)
        depth_data = depth_data.reshape((height, width))

        width = color_frame.get_width()
        height = color_frame.get_height()
        color_data = np.asanyarray(color_frame.get_data(), dtype=np.uint16)
        # color_data = color_data.reshape((height, width, 3))
        return color_data.astype(np.float32), depth_data.astype(np.float32)
    
    def get_data(self):
        """通过流来获取color data和depth data"""

        # 连接相机
        self.connect()
        color_frame, depth_frame = self.get_frame()

        width = color_frame.get_width()
        height = color_frame.get_height()
        color_format = color_frame.get_format()
        data = np.asanyarray(color_frame.get_data())
        color_data = cv2.imdecode(data, cv2.IMREAD_COLOR)
        color_data.astype(np.float32)

        print('color_image.shape: ', color_data.shape)
        # print("===width: {}===".format(width))
        # print("===height: {}===".format(height))
        width = depth_frame.get_width()
        height = depth_frame.get_height()
        scale = depth_frame.get_depth_scale()
        print("===width: {}===".format(width))
        print("===height: {}===".format(height))
        print("===scale: {}===".format(scale))
        save_dir = os.path.join(os.getcwd(), "real/intrinsic")
        if not os.path.exists(save_dir):
            os.mkdir(save_dir)
        filename = save_dir + "/camera_depth_scale.txt"
        save = np.array([scale])
        np.savetxt(filename, save, delimiter=' ')

        depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16)
        depth_data = depth_data.reshape((height, width))
        depth_data = depth_data.astype(np.float32) * scale
        print('depth_image.shape: ', depth_data.shape)

        depth_data = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_16U)
        
        # 断开相机
        self.disconnect()

        return color_data, depth_data

    def get_data_saved(self):
        color_data, depth_data = self.get_data()
        
        # depth_image = depth_data_normalized.astype(np.uint8)

        save_image_dir = os.path.join(os.getcwd(), "real/images")
        if not os.path.exists(save_image_dir):
            os.mkdir(save_image_dir)
        depth_filename = save_image_dir + "/depth_{}x{}.png".format(depth_data.shape[0], depth_data.shape[1])
        color_filename = save_image_dir + "/color_{}x{}.png".format(color_data.shape[0], color_data.shape[1])
        cv2.imwrite(color_filename, color_data)
        # depth_data.tofile(depth_filename)
        cv2.imwrite(depth_filename, depth_data)

        return color_data, depth_data
        

    def get_intrinsic(self):
        """获取内参"""
        # get intrinsic
        itsc = self.pipeline.get_camera_param()
        raw_intrinsic = itsc.depth_intrinsic

        intrinsic = np.array([raw_intrinsic.fx, 0, raw_intrinsic.cx, 
                                0, raw_intrinsic.fy, raw_intrinsic.cy,
                                0, 0, 1]).reshape(3,3)
        print("intrinsic: ", itsc)
        print('depth intrinsic: ', raw_intrinsic)
        print("intrinsic matrix", intrinsic)
        save_dir = os.path.join(os.getcwd(), "real/intrinsic")
        if not os.path.exists(save_dir):
            os.mkdir(save_dir)
        filename = save_dir + "/camera_itcs.txt"

        np.savetxt(filename, intrinsic, delimiter=' ')

        return intrinsic
    
    # for test
    def visualize(self):
        """显示rgbd图像"""
        color_data, depth_data = self.get_data()
        depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
        depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
        # overlay color image on depth image
        depth_image = cv2.addWeighted(color_data, 0.5, depth_image, 0.5, 0)
        cv2.imshow("Depth with Color", depth_image)
        cv2.waitKey(500)
    
    

if __name__ == '__main__':
    camera = Camera()
    camera.visualize()
    color, depth = camera.get_data()
    print("depth.shape: ", depth.shape)

测试相机是否实现对齐,结果如下

Image

表明了相机确实实现了对齐操作

3. 修改demo.py

我们使用get_data()函数就能够让相机进行一次拍摄,然后得到color_datadepth_data供我们进行后续的处理。然后可以修改一下demo.py,将从文件读取数据改为直接从相机进行读取

demo.py

...
from astra2 import Camera()
astra2 = Camera()

...

def get_and_process_data():

    # 使用相机获取一次数据
    color, depth = astra2.get_data()
    color = color / 255.0
    ...

然后别的部分可以保持不变或者以后再修改。这里一定要使用官方提供的checkpoint-rs.tar,如果使用checkpoint-kn.tar,会出现异常,暂时我也没有找到原因。

最后处理的效果如下

Image

可以看到出现了许多我们不希望存在的抓取框,这个可以通过调整workspace_mask来进行过滤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/635361.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++容器之映射(std::map)

目录 1 概述2 使用实例3 接口使用3.1 construct3.2 assigns3.3 iterators3.4 capacity3.5 access3.6 insert3.7 erase3.8 swap3.9 clear3.10 emplace3.11 emplace_hint3.12 key_comp3.13 value_comp3.14 find/count3.15 upper_bound/upper_bound/equal_range3.16 get_allocator…

数据结构和算法|堆排序系列问题(一)|堆、建堆和Top-K问题

在这里不再描述大顶堆和小顶堆的含义,只剖析原理层面。 主要内容来自:Hello算法 文章目录 1.堆的实现1.1 堆的存储与表示过程1.2 访问堆顶元素1.4元素出堆 2.⭐️建堆2.1 方法一:借助入堆操作实现2.2 ⭐️方法二:通过遍历堆化实现…

Java 多线程抢红包

问题需求 一个人在群里发了1个100元的红包,被分成了8个,群里有10个人一起来抢红包,有抢到的金额随机分配。 红包功能需要满足哪些具体规则呢? 1、被分的人数抢到的金额之和要等于红包金额,不能多也不能少。 2、每个人至少抢到1元…

Ubuntu Nerfstudio安装

https://blog.csdn.net/qq_30565883/article/details/133778529 https://blog.csdn.net/weixin_52581013/article/details/137982846 https://zhuanlan.zhihu.com/p/654394767 1. 结论 因为需要安装tiny-cuda-nn,然而 所以我之前的在笔记本上安装就白费了&#xf…

基于python的k-means聚类分析算法,对文本、数据等进行聚类,有轮廓系数和手肘法检验

K-means算法是一种常见的聚类算法,用于将数据点分成不同的组(簇),使同一组内的数据点彼此相似,不同组之间的数据点相对较远。以下是K-means算法的基本工作原理和步骤: 工作原理: 初始化&#x…

QT C++ QTableWidget 演示

本文演示了 QTableWidget的初始化以及单元格值改变时响应槽函数,打印单元格。 并且,最后列不一样,是combobox ,此列的槽函数用lambda函数。 在QT6.2.4 MSVC2019 调试通过。 1.界面效果 2.头文件 #ifndef MAINWINDOW_H #define MAINWINDOW…

使用API有效率地管理Dynadot域名,进行域名邮箱的默认邮件转发设置

关于Dynadot Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮…

【四数之和】python,排序+双指针

四层循环?(doge) 和【三数之和】题目很类似 class Solution:def fourSum(self, nums: List[int], target: int) -> List[List[int]]:nums.sort()#a,b,c,d四个数,先固定两个数,那就是双指针问题了,令ba1&#xff…

【数据结构】【C语言】堆~动画超详细解读!

目录 1 什么是堆1.1 堆的逻辑结构和物理结构1.2 堆的访问1.3 堆为什么物理结构上要用数组?1.4 堆数据上的特点 2 堆的实现2.1 堆类型定义2.2 需要实现的接口2.3 初始化堆2.4 销毁堆2.5 堆判空2.6 交换函数2.7 向上调整(小堆)2.8 向下调整(小堆)2.9 堆插入2.10 堆删除2.11 //堆…

若依解决使用https上传文件返回http路径问题

若依通过HTTPS请求进行文件上传时却返回HTTP的文件链接地址,主要原因是使用了 request.getRequestURL 获取链接地址。 解决办法: 在nginx配置文件location处加上:proxy_set_header X-Forwarded-Scheme $scheme; 然后代码通过request.getHea…

【跳坑日记】暴力解决Ubuntu SSH报错: Failed to start OpenBSD Secure Shell server

报错环境说明: 服务器环境:Ubuntu 20.04 错误内容 最近服务器突然报错,提示如下图信息: 搜素了各种问答,国内的回答大多数是用 ssh-keygen -A命令来解决,但最终也无法登录服务器。 最终搜索到ask ubun…

比较kube-proxy模式:iptables还是IPVS?

kube-proxy是任何 Kubernetes 部署中的关键组件。它的作用是将流向服务(通过集群 IP 和节点端口)的流量负载均衡到正确的后端pod。kube-proxy可以运行在三种模式之一,每种模式都使用不同的数据平面技术来实现:userspace、iptables…

go-zero 实战(3)

引入 Redis 在之前的 user 微服务中引入 redis。 1. 修改 user/internal/config/config.go package configimport ("github.com/zeromicro/go-zero/core/stores/cache""github.com/zeromicro/go-zero/zrpc" )type Config struct {zrpc.RpcServerConfMys…

代码随想录算法训练营第36期DAY35

DAY35 122买卖股票的最佳时机ii 很巧妙&#xff0c;也很难想到&#xff1a;计算每天的利润&#xff08;今天卖出&#xff0c;昨天买入的利润&#xff09;&#xff0c;只取正数相加。 class Solution {public: int maxProfit(vector<int>& prices) { int…

【机器学习300问】93、到底什么是优化器optimizer?

本文是对之前我写的梯度下降优化算法相关内容进行一次简要总结。在学习PyTorch框架的过程中&#xff0c;会遇到“优化器”&#xff08;optimizer&#xff09;这个概念。我想用通俗易懂的方式&#xff0c;说说优化器到底是个什么东西&#xff0c;并在此基础上&#xff0c;将前文…

Qt代码初识

文章目录 Qt代码初识1. Qt Hello World 程序1.1 使⽤ "按钮" 实现1.1.1 纯代码⽅式实现1.1.2 可视化操作实现 1.2 使⽤ "标签" 实现1.2.1 纯代码⽅式实现1.2.2 可视化操作实现 2. 项⽬⽂件解析2.1 .pro ⽂件解析2.2 widget.h ⽂件解析2.3 main.cpp ⽂件解析…

SwanLab入门深度学习:BERT IMDB文本情感分类

基于BERT模型的IMDB电影评论情感分类&#xff0c;是NLP经典的Hello World任务之一。 这篇文章我将带大家使用SwanLab、transformers、datasets三个开源工具&#xff0c;完成从数据集准备、代码编写、可视化训练的全过程。 观察了一下&#xff0c;中文互联网上似乎很少有能直接…

Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645)

漏洞复现环境搭建请参考 http://t.csdnimg.cn/MxmId 漏洞版本 Apache Log4j 2.8.2之前的2.x版本 漏洞验证 &#xff08;1&#xff09;开放端口4712 漏洞利用 &#xff08;1&#xff09;ysoserial工具获取 wget https://github.com/frohoff/ysoserial/releases/download/v0…

强化学习算法

从上图看出&#xff0c;强化学习可以分成价值/策略、随机策略/确定策略、在线策略/离线策略、蒙特卡洛/时间差分这四个维度。这里分析了基础算法中除了在线策略/离线策略以外的其他维度。 &#xff08;一&#xff09;基础知识 一、基础概念 重点概念&#xff1a;状态S、动作A、…

浏览器自动化~插件推荐Automa

引言 作为一款现代浏览器&#xff0c;得自动化吧&#xff0c;自主完成那些日复一日的重复性任务&#xff0c;开启音乐啥的不在话下~。而你则可以专注于其他更有意义的事情&#xff0c;如享受音乐带来的愉悦。但如果你对编写脚本一窍不通&#xff0c;又该如何实现这一愿景呢&am…