aikit 2023 3D与机械臂结合!

news2024/9/28 19:17:32

引言

今天我们主要了解3D摄像头是如何跟机械臂应用相结合的。我们最近准备推出一款新的机械臂套装AI Kit 2023 3D,熟悉我们的老用户应该知道,我们之前的AI Kit 2023套装使用的是2D摄像头。

随着技术进步,市场需求和领域的扩大,2D的摄像头已经不能够满足很多场景。3D摄像头也在近些年间火了起来。随着我们的步伐,一起来认识一下3D摄像头带给我们的应用。

产品介绍

RealSence-Depth camera

我们今天涉及到的3D摄像头是RealSence是Intel公司开发的一种深度感知摄像头。可以从图片中看出来,这个相机有四个镜头,它们分别是一个红外激光投影仪,两个红外摄像头和一个彩色摄像头。这几个镜头具体有啥作用:

红外激光投影仪:

投射一个红外光点网格到场景中,然后这些光点被红外摄像头捕获。因为投影仪和摄像头的位置是固定的,所以通过计算光点在摄像头中的位置偏移,可以推算出每个光点对应的物体距离摄像头的距离,从而得到场景的深度信息。

红外摄像头:

红外摄像头是一种能够捕获红外光谱的摄像头。红外光谱是电磁谱中的一部分,其波长长于可见光,但短于微波。红外摄像头的主要作用是能够在无可见光照明的条件下进行成像,因为许多物体会发射、反射或透过红外光。

彩色摄像头:

通常用于捕获场景的常规视觉信息,而其他的摄像头则用于捕获额外的信息,如场景的深度信息或在低光照条件下的图像。这些信息可以与彩色摄像头捕获的图像相结合,以提供更丰富的视觉数据,支持更高级的功能,如面部识别、增强现实或3D建模等。

结合这四个摄像头的功能,能够获取一个物体的三维信息,这种技术可以用于人脸识别、手势识别、物体识别、测量物体的深度等多种应用。

Artificial Intelligence Kit 3D

人工智能3D套装是机械臂应用人工智能,机器视觉的入门款套装。套装使用了四种识别算法,颜色识别,形状识别,yolov8等,适配可视化的操作界面,使用3D摄像头解决了2D摄像头需要标志定位的短板,开源代码基于python平台,可通过开发软件实现机械臂的控制

该套装是搭配机械臂(myCobot,mechArm,myArm)进行使用,仿工业场景的构造。

myCobot 280

myCobot 280 M5是一款由Elephant Robotics和M5Stack联合开发的最小和最轻的六轴协作机器人。它采用集成模块化设计,重量仅为850克,非常轻巧,搭载6个高性能伺服电机,具有快速响应,惯性小和平滑旋转的特点。

3D摄像头应用领域

如果在同一个应用领域中,用2D摄像头和3D摄像头它们的表型性能会怎样。从我们身边常见的来了解:

从图标中可以知道,2D摄像头需要通过特定的算法来得到一些参数,而3D摄像头能够直接获取较多的信息,在同一应用领域下的性能更加精准。在未来的,3D摄像头的趋势必然是飞速增长的!

这也是我们推出3D人工智能套装的原因之一,跟上时代的步伐。

算法介绍

机械臂视觉识别,一定会涉及手眼标定。虽然两种版本的手眼标定的流程是一样的,但是他们在计算中还是会有一些差别,我们先看它们的识别区。

从中间的是被区域可以看到,3D版本已经没有了二维码的标识,在2D版本上二维码的标识的主要功能是确定识别的区域,以及提供一个固定高度的值。在获取了三维数据之后,就不需要用到二维码进行标识了,可以直接获取到相机距离平面高度的值。

这一点体现了3D摄像头能够直接获取深度的信息。

如何使用 realsence 在python中

environment build
operate system:window10/11
program language:python 3.9+
libraries:
from typing import Tuple, Optional
import pyrealsense2 as rs
import numpy as np
import cv2
import time


class RealSenseCamera:
    def __init__(self):
        super().__init__()

        # Configure depth and color streams
        self.pipeline = rs.pipeline()
        self.config = rs.config()
        self.config.enable_stream(rs.stream.color, 1920, 1080, rs.format.bgr8, 30)
        # Is the camera mirror image reversed
        self.flip_h = False
        self.flip_v = False

        # Get device product line for setting a supporting resolution
        pipeline_wrapper = rs.pipeline_wrapper(self.pipeline)
        pipeline_profile = self.config.resolve(pipeline_wrapper)
        # set auto exposure
        color = pipeline_profile.get_device().query_sensors()[0]
        color.set_option(rs.option.enable_auto_exposure, True)

        device = pipeline_profile.get_device()

        sensor_infos = list(
            map(lambda x: x.get_info(rs.camera_info.name), device.sensors)
        )

        # set resolution
        self.config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
        self.config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

        align_to = rs.stream.color
        self.align = rs.align(align_to)

    def capture(self):
        # Start streaming
        self.pipeline.start(self.config)

        # warm up
        for i in range(60):
            pipeline = self.pipeline
            frames = pipeline.wait_for_frames()

    def release(self):
        self.pipeline.stop()

    def update_frame(self) -> None:
        pipeline = self.pipeline
        frames = pipeline.wait_for_frames()
        aligned_frames = self.align.process(frames)
        self.curr_frame = aligned_frames
        self.curr_frame_time = time.time_ns()

    def color_frame(self) -> Optional[np.ndarray]:
        frame = self.curr_frame.get_color_frame()
        if not frame:
            return None
        frame = np.asanyarray(frame.get_data())
        if self.flip_h:
            frame = cv2.flip(frame, 1)
        if self.flip_v:
            frame = cv2.flip(frame, 0)
        return frame

    def depth_frame(self) -> Optional[np.ndarray]:
        frame = self.curr_frame.get_depth_frame()
        if not frame:
            return None
        frame = np.asanyarray(frame.get_data())
        if self.flip_h:
            frame = cv2.flip(frame, 1)
        if self.flip_v:
            frame = cv2.flip(frame, 0)
        return frame

颜色识别和形状识别都是基于openCV提供的算法来识别物体抓取物体。只需要简单的做一个hsv的检测的算法就能够检测出来颜色。

# 初始化要识别的颜色
    def __init__(self) -> None:
        self.area_low_threshold = 15000
        self.detected_name = None
        self.hsv_range = {
            "green": ((40, 50, 50), (90, 256, 256)),
            # "blueA": ((91, 100, 100), (105, 256, 256)),
            # "yellow": ((20, 240, 170), (30, 256, 256)),
            "yellow": ((15, 46, 43), (30, 256, 256)),
            "redA": ((0, 100, 100), (6, 256, 256)),
            "redB": ((170, 100, 100), (179, 256, 256)),
            # "orange": ((8, 100, 100), (15, 256, 256)),
            "blue": ((100, 43, 46), (124, 256, 256)),
        }
        
# 对图像的处理
result = []
        for color, (hsv_low, hsv_high) in self.hsv_range.items():
            hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
            in_range = cv2.inRange(hsv_frame, hsv_low, hsv_high)

            # 对颜色区域进行膨胀和腐蚀
            kernel = np.ones((5, 5), np.uint8)
            in_range = cv2.morphologyEx(in_range, cv2.MORPH_CLOSE, kernel)
            in_range = cv2.morphologyEx(in_range, cv2.MORPH_OPEN, kernel)

            contours, hierarchy = cv2.findContours(
                in_range, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
            )

            contours = list(
                filter(lambda x: cv2.contourArea(x) > self.area_low_threshold, contours)
            )

            rects = list(map(cv2.minAreaRect, contours))
            boxes = list(map(cv2.boxPoints, rects))
            boxes = list(map(np.int32, boxes))

            if len(boxes) != 0:
                if color.startswith("red"):
                    color = "red"
                for box in boxes:
                    result.append(ColorDetector.DetectResult(color, box))
                    # self.detected_name = result
                    self.detected_name = result[0].color
        return result

YOLOv8 和拆码垛

 我们在这个套装里面还使用到了目前比较火的一款识别模型YOLOv8,此模型还涉及到深度学习和模型训练等功能。

YOLOv8是一种目标检测算法,它是基于深度学习的YOLO(You Only Look Once)系列算法的最新版本。YOLO算法是一种实时目标检测算法,其特点是能够在一次前向传播中同时完成目标检测和定位,速度非常快。Home - Ultralytics YOLOv8 Docs

主要特点:

  • 高性能:YOLOv8在目标检测任务中具有较高的准确性和速度。它能够在实时或接近实时的速度下进行目标检测,适用于各种应用场景。
  • 简单而有效的设计:YOLOv8采用了简单而有效的设计,通过使用更深的网络结构和更多的特征层来提高检测性能。它还使用了一种自适应的训练策略,可以在不同的目标检测任务上进行快速训练和调整。
  • 多种规模的检测:YOLOv8提供了不同的模型大小,包括小型、中型和大型模型,以满足不同场景下的需求。这些模型可以在不同的硬件设备上进行部署和使用。
  • 开源和易用性:YOLOv8是开源的,代码和预训练模型都可以在GitHub上获得。它还提供了简单易用的API,使得用户可以方便地进行模型训练、推理和部署。

要使用YOLOv8是需要进行自定义训练模型的,在进行目标检测任务是,根据具体应用场景和需求,通过在自定义数据集上进行训练得到模型。

为什么要训练模型呢?训练模型的目的是让计算机能够自动识别和定位图像或视频中的目标物体。通过训练模型,我们可以让计算机学会如何识别不同种类的物体,并且能够准确地定位它们的位置。这对于许多应用场景非常重要,比如自动驾驶、安防监控、智能交通等。

对此我们的源码文件中已经包含了我们自己训练的模型,如果你对YOLOv8的技术很熟练了,你可以自己对识别物体进行训练。

下面的代码是程序中使用的代码

class YOLODetector:
    DetectResult = List[ultralytics.engine.results.Results]

    def __init__(self) -> None:
        """
        init YOLO model。
        """
        self.model_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/resources/yolo/best.pt'
        self.model = YOLO(self.model_path)
        self.predict_args = {"conf": 0.2}

        self.detected_name = None

    def get_radian(self, res: DetectResult):
        return 0

    def detect(self, frame: np.ndarray):
        """
        Perform object detection on input images.

        Args:
            frame (np.ndarray): Input image frame.

        Returns:
            List[DetectResult]: A list containing the detection results.
        """
        res = self.model.predict(frame, **self.predict_args)
        res = list(filter(lambda x: len(x.boxes) != 0, res))
        if len(res) == 0:
            return None
        else:
            names = self.get_names(res)
            self.detected_name = names
            return res

    def draw_result(self, frame: np.ndarray, res: List[DetectResult]):
        """
        Draws the bounding box of the detection results on the image.

        Args:
             frame (np.ndarray): Input image frame.
             res (List[DetectResult]): List of detection results.
        """
        res = list(filter(lambda x: len(x.boxes) != 0, res))
        for r in res:
            boxes = r.boxes.xyxy.numpy()
            for box in boxes:
                x1, y1, x2, y2 = box.astype(int)
                cv2.rectangle(frame, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=1)
                cv2.putText(frame, "Name: " + str(self.detected_name), (20, 80),
                            cv2.FONT_HERSHEY_COMPLEX_SMALL, 1,
                            (0, 0, 255))
            # x1, y1, x2, y2 = np.squeeze(r.boxes.xyxy.numpy()).astype(int)
            # cv2.rectangle(frame, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=1)

    def target_position(self, res: DetectResult) -> Tuple[int, int]:
        """
        Extract the location information of the target from the detection results.

         Args:
             res (DetectResult): detection result.

         Returns:
             Tuple[int, int]: The position coordinates (x, y) of the target.
        """
        boxes = res.boxes.xywh.numpy()
        boxs_list = []
        for box in boxes:
            x, y, w, h = box.astype(int)
            boxs_list.append((x, y))
        boxs_list = tuple(boxs_list)
        return boxs_list

    def get_rect(self, res: DetectResult):
        """
        Obtain the bounding box coordinate information of the target from the detection result.

        Args:
             res (DetectResult): detection result.

         Returns:
             List[Tuple[int, int]]: The bounding box coordinate information of the target, including four vertex coordinates.
        """
        boxes = res.boxes.xywh.numpy()
        box_list = []
        for box in boxes:
            x, y, w, h = box.astype(int)
            size = 3
            rect = [
                [x - size, y - size],
                [x + size, y - size],
                [x + size, y + size],
                [x - size, y + size],
            ]
            box_list.append(rect)
        return box_list

    def get_names(self, res: DetectResult):
        """
        Get the category name in the detection results

        Args:
             res (DetectResult): detection result.

         Returns:
             List[names]: A list category names.
        """
        names_dict = {
            0: 'jeep', 1: 'apple', 2: 'banana1', 3: 'bed', 4: 'grape',
            5: 'laptop', 6: 'microwave', 7: 'orange', 8: 'pear',
            9: 'refrigerator1', 10: 'refrigerator2', 11: 'sofa', 12: 'sofa2',
            13: 'tv', 14: 'washing machine1'
        }

        ids = [int(cls) for cls in res[0].boxes.cls.numpy()]  # Assuming you have only one result in the list
        names = [names_dict.get(id, 'Unknown') for id in ids]

        return names

搭配上3D摄像头的特性,获取被识别的物体的高度实现拆码垛的demo,能够将他们像拆积木一样拆除。

总结

我们的机械臂和深度摄像头套装不仅是一款产品,更是一个开启学习之门的机会。这个套装以用户友好的方式,提供了一个理想的平台,让初学者可以在实践中探索和学习机械臂操作和机器视觉的知识,更重要的是,它提供了一个独特的机会,让用户能够深入理解和掌握3D相机算法。

随着科技的进步,3D摄像头的应用正在迅速扩展到多个领域,包括但不限于制造、安全、娱乐和医疗。我们坚信,通过使用我们的套装,用户将能够把握这一技术趋势,为自己的未来学习和职业生涯奠定坚实的基础。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3 + element-plus + ts el-table封装

vue3 element-plus ts el-table封装 博客参考https://blog.csdn.net/weixin_45291937/article/details/125523244 1. 文件位置&#xff08;根据自己的需求&#xff09; 2. 在 custom 文件夹下面 创建 mytable 文件夹 3. 直接上代码 // index.vue<template><div …

centos7搭建 PXE 服务安装 window10/11 系统

最近想搭建之前基于 window server 的 window 批量安装&#xff0c;但想想装 window server 真的太麻烦了&#xff0c;我只是为了 PXE 安装系统而已&#xff0c;这些装一个极度消耗资源的系统真是相当麻烦呀&#xff0c;之前装的 server 不维护的话&#xff0c;不是被挖矿盯上就…

Linux新加磁盘的完整步骤

目录 新加磁盘的完整步骤磁盘分区磁盘文件命名经典分区方案fdiskparted 分区格式化挂载分区 新加磁盘的完整步骤 物理连接 --> 分区 --> 格式化 --> 挂载 --> 更新/etc/fstab文件实现永久挂载 磁盘分区 主分区primary用来安装操作系统、存放数据&#xff0c;可以…

历时三个月,我发布了一款领取外卖红包小程序

近几年&#xff0c;推广外卖红包爆火&#xff0c;各种推广外卖红包的公众号层出不穷。于是&#xff0c;我就在想外卖红包究竟是怎么一回事。就这样&#xff0c;我带着问题开始了关于外卖红包的研究。 在研究的过程中&#xff0c;我开始了解隐藏优惠券、cps等一系列相关的术语。…

UCP通信

一&#xff0c;概括 二 &#xff0c;常用方法 三&#xff0c;实现步骤&#xff08;一发一收&#xff09; 四&#xff0c;案例&#xff08;一发一收&#xff09; &#xff08;1&#xff09;&#xff1a;客户端 &#xff08;2&#xff09;&#xff1a;服务端 &#xff08;3&…

解决:ModuleNotFoundError: No module named ‘PyQt5‘

解决&#xff1a;ModuleNotFoundError: No module named ‘PyQt5’ 文章目录 解决&#xff1a;ModuleNotFoundError: No module named PyQt5背景报错问题报错翻译报错位置代码报错原因解决方法安装PyQt5在PyCharm中配置PyQt5对于新项目对于已有项目 今天的分享就到此结束了 背景…

NX二次开发UF_CURVE_convert_conic_to_gen 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_convert_conic_to_gen Defined in: uf_curve.h int UF_CURVE_convert_conic_to_gen(UF_CURVE_conic_p_t conic_data, UF_CURVE_genconic_t * gen_conic_data ) overview 概…

309.最佳卖股票的时机包含冷冻期

一、题目分析 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&#xff0c;你无法在第二…

NX二次开发UF_CURVE_convert_conic_to_std 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_convert_conic_to_std Defined in: uf_curve.h int UF_CURVE_convert_conic_to_std(UF_CURVE_genconic_p_t gen_conic_data, UF_CURVE_conic_t * conic_data, logical * se…

python炒股自动化(1),量化交易接口区别

要实现股票量化程序化自动化&#xff0c;就需要券商提供的API接口&#xff0c;重点是个人账户小散户可以申请开通&#xff0c;上手要简单&#xff0c;接口要足够全面&#xff0c;功能完善&#xff0c;首先&#xff0c;第一步就是要找对渠道和方法&#xff0c;这里我们不讨论量化…

关于Unity中字典在Inspector的显示

字典在Inspector的显示 方法一&#xff1a;实现ISerializationCallbackReceiver接口 《unity3D游戏开发第二版》记录 在编辑面板中可以利用序列化监听接口特性对字典进行序列化。 主要继承ISerializationCallbackReceiver接口 实现OnAfterDeserialize() OnBeforeSerialize() …

二十章 多线程

线程简介 在 Java 中&#xff0c;并发机制非常重要。在以往的程序设计中&#xff0c;我们都是一个任务完成后再进行下一个任务&#xff0c;这样下一个任务的开始必须等待前一个任务的结束。Java 语言提供了并发机制&#xff0c;程序员可以在程序中执行多个线程&#xff0c;每一…

上门预约互联网干洗店洗鞋店小程序开发

很多时候可能大家的衣服鞋子需要干洗&#xff0c;但又不想出门送去店里&#xff0c;大家就可以使用手机线上下单预约取货&#xff0c;会有专门的人上门来取衣服&#xff0c;让你能够轻松的进行洗护。 闪站侠洗衣洗鞋小程序&#xff0c;提供了足不出户就能预约人员上门去 衣送洗…

【刷题笔记】匹配字符串||KMP||动图解析||符合思维方式

找出字符串中第一个匹配项的下标 1 题目描述 https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/ 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开…

Swift下如何使用#if条件编译

一、OC使用条件编译 OC中可以使用宏定义&#xff0c;再使用条件编译 #define USER_CUSTOM使用 #if USER_CUSTOM //其他代码 #endif二、Swift使用条件编译 Swift 不像ObjectC一样&#xff0c;通过定义一个变量&#xff0c;然后使用**#if #endif** 方法。swift需要设置一下才能…

SpringBoot错误处理机制(ControllerAdvice+ExceptionHandler自定义错误处理、默认机制源码分析、错误处理实战)

目录 1. SpringBoot自己对错误进行处理1.1 给一个Controller进行错误处理1.2 使用ControllerAdvice统一处理错误 2. 默认机制源码解析3. 错误处理机制实战 1. SpringBoot自己对错误进行处理 1.1 给一个Controller进行错误处理 使用ExceptionHandler&#xff0c;处理一个Conto…

【电源芯片】ZTP7193

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评百大…

销售流程中如何有效开发客户

在销售的海洋中&#xff0c;如何游刃有余地开发客户是一大关键。这需要深入了解你的目标客户&#xff0c;制定一份精细的销售计划&#xff0c;选择最合适的沟通方式&#xff0c;建立信任和信誉&#xff0c;并持续不断地跟进。 每一个潜在的客户都是一颗璀璨的星辰&#xff0c;…

地理坐标系转换

1.EPSG代码 搜索地理坐标系对应的EPSG代码 https://epsg.io/ 常用的地理坐标系EPSG代码&#xff1a; 2. 坐标系转换 转换网址&#xff1a; https://epsg.io/transform &#xff08;1&#xff09;修改 input coordinate system 和 output coordinate system&#xff0c; 可以…

【开源】基于Vue.js的农村物流配送系统的设计和实现

项目编号&#xff1a; S 024 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S024&#xff0c;文末获取源码。} 项目编号&#xff1a;S024&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2…