首页 > 其他分享 >(五)焊缝检测之--测量间距并用ROS消息包发送

(五)焊缝检测之--测量间距并用ROS消息包发送

时间:2024-08-27 09:21:44浏览次数:16  
标签:焊缝 point -- cv2 point0 dispoint msg ROS distance

前言

在上一小节记录了矩形参照物的检测。这一小节将介绍基于识别到的圆形焊缝和矩形参照物的坐标,读出两点之间在x和y方向上的间距,并通过话题通信的方式发送初期


一、测量圆心和焊缝间距

在之前小节中已经分别通过霍夫圆检测拿到了圆心坐标和矩形参照物角点坐标,分别将其记作(point0[0],point0[1]),(point1[0],point1[1])。在这里需要读出的是两点之间在x轴方向和y轴方向上的间距,后期发送给机械臂让其沿着这两端间距移动到焊缝的位置。因此,直接将两点在同轴上的坐标作差并取绝对值即可。

distance1 = abs(point0[0] - point1[0])
distance2 = abs(point0[1] - point1[1])   #对距离取绝对值
 print(distance1, distance2)

在这里,矩形角点坐标由order_points(pts)函数计算,从2x4的数组rect中读出;圆心坐标由霍夫圆检测输出的数组circle读出。代码和注释在之前博客里都有详细介绍。最终读取出的效果如下 :

在这里插入图片描述
这里有一个小细节,就是支撑圆形焊缝的底座也是个矩形框,在识别的时候也会被识别进去。因此对实际读取到的距离需要做一个范围上的取值,过滤掉底座矩形的取值,剩下的才是我们需要的值

二、制作ROS消息包并发送

1.下载ROS驱动包

网上有已经提供好的基于海康MVS相机的ROS驱动接口,直接下载放到创建的工作空间下编译即可。这一步参考博客《海康威视工业相机在ROS下驱动》来进行的
https://blog.csdn.net/weixin_60003973/article/details/135824902
ROS包下载链接:
https://github.com/luckyluckydadada/HIKROBOT-MVS-CAMERA-ROS
编译通过后运行指令

 roslaunch hikrobot_camera hikrobot_camera.launch  

最终成功导入包的效果如下:

在这里插入图片描述

2.制作ROS消息包并发送距离

制作ROS消息包并发送全过程的包括:
1.创建并初始化ROS节点
2.创建发布者并指明对象格式
3.制作消息包和获取数据
4.整合数据并发送

代码如下:

# 初始化ros节点
    rospy.init_node("cv_bridge_test")  
    rospy.loginfo("Starting cv_bridge_test node")  

# 创建距离发布者,并指明对象格式为string
    distance_pub = rospy.Publisher("distance", String, queue_size=10)

    msg = String()
    msg_front = "两点的距离是"
    msg_middle = "  "   

   # 整合发布的数据并发送
   try:
          msg.data = msg_front + str(distance1) + msg_middle + str(distance2)
          if distance2>500:
               distance_pub.publish(msg)
               ospy.loginfo("发布的数据是%s", msg.data)
           except rospy.is_shutdown():
                print("Shutting down cv_bridge_test node.")
                cv2.destroyAllWindows()

效果如下:
在这里插入图片描述

3.自定义数据格式发送坐标和距离

在上一步中发送的是距离信息,但在实际情况下距离以及圆心和矩形框角点坐标都要发送给机械臂,并且是以浮点数而非数组的形式发送。因此,需要自定义数据格式,从数组中提取出各个数据,再一并发送。
创建dispoint.msg文件,自定义数据格式如下:

float32 distance_1      #两点在x轴方向间距
float32 distance_2      #两点在y轴方向间距
float32 point_1            #矩形角点x轴坐标
float32 point_2            #圆心x轴坐标
float32 point_3            #矩形角点y轴坐标
float32 point_4            #圆心y轴坐标

之后的流程和第二步里的一样,在发送数据前将获取到的数据赋给自定义数据格式,再发送即可:

# 整合发布的数据并发送
                try:
                    dispoint_msg.distance_1 = distance1
                    dispoint_msg.distance_2 = distance2   #注意自定义消息格式里的数据命名不能和工程里的变量重名
                    dispoint_msg.point_1 = point0[0]
                    dispoint_msg.point_2 = point1[0]
                    dispoint_msg.point_3 = point0[1]
                    dispoint_msg.point_4 = point1[1]
                    #msg.data = msg_front + str(distance1) + msg_middle + str(distance2)
                    if distance2>500.0:
                        # distance_pub.publish(msg)
                        # rospy.loginfo("发布的数据是%s", msg.data)
                        dispoint_pub.publish(dispoint_msg)
                        rospy.loginfo("发布的数据是[%s, %s, %s, %s, %s, %s]", dispoint_msg.distance_1,dispoint_msg.distance_2,dispoint_msg.point_1,dispoint_msg.point_2,dispoint_msg.point_3,dispoint_msg.point_4)
                except rospy.is_shutdown():
                    print("Shutting down cv_bridge_test node.")
                    cv2.destroyAllWindows()

最终的效果如下:

在这里插入图片描述

三.完整代码

这里整合从第三节霍夫圆检测到这一节共三节的完整代码,结合前两届海康SDK的基本框架,便可实现如上功能。

# 获取矩形四点原始点坐标
def order_points(pts):
    # 进行初始化点的位置,左上、右上、左下、右下
    rect = np.zeros((4, 2), dtype="float32")   #rect为二维数组,第一维是不同坐标,第二维是坐标上的x和y,circle同理
    # 采取四个点的x+y的和,以最小的和为左上的点,x+y最大为右下的点
    s = pts.sum(axis=2)  # axis为标,防止溢出
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    # 定义一左下点和右上点的位置,用|x-y|表示,小的为右上,大的为左下
    diff = np.diff(pts, axis=2)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    point0[0] = rect[0,0]
    point0[1] = rect[0,1]
    #print(point0)
    print(rect[0,0],rect[0,1])   #矩形左上角角点坐标
    #print(rect)


# 显示图像
def image_show(image, name):
    # 创建距离发布者,并指明对象格式为string
    dispoint_pub = rospy.Publisher("dispoint", dispoint, queue_size=10)
    msg = String()
    dispoint_msg = dispoint()
    msg_front = "两点的距离是"
    msg_middle = "  "
    image = cv2.resize(image, (1440, 1080), interpolation=cv2.INTER_AREA)
    name = str(name)

    gay_img = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)

    # 进行矩形边缘检测
    edges = cv2.Canny(gay_img, 50, 150)
    img_circle = cv2.medianBlur(gay_img, 7)  # 进行中值模糊,去噪点



    # 寻找矩形轮廓
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 霍夫圆检测
    circles = cv2.HoughCircles(img_circle, cv2.HOUGH_GRADIENT, 1, 100,
                               param1=70, param2=90, minRadius=0,
                               maxRadius=10000)  # 根据识别圆形效果差异,调整参数param2(圆形密集则加大param2)

    # 遍历轮廓,筛选矩形轮廓
    rectangles = []
    if contours is not None and circles is not None:
        circles = np.uint16(np.around(circles))   #确保 circles 数组中的圆形坐标和半径是整数类型
        #print(circles)
        #P = circles[0]
        for i in circles[0, :]:  # 遍历矩阵每一行的数据
            cv2.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2)
            cv2.circle(image, (i[0], i[1]), 2, (0, 0, 255), 3)   #circle本身为opencv自带的库函数
            point1 = [i[0], i[1]]
            print(point1)   #圆心坐标,不含半径
            # cv2.imshow("gay_img", image)

        for contour in contours:
            # 计算轮廓的面积
            area = cv2.contourArea(contour)
            # 计算轮廓的周长
            perimeter = cv2.arcLength(contour, True)
            # 近似轮廓,用于逼近多边形曲线
            approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)

            # 如果近似轮廓有四个顶点,则认为它是一个矩形
            if len(approx) == 4 and area > 50000 and area < 1000000:  # 添加面积限制
                # 获取矩形的边界框
                x, y, w, h = cv2.boundingRect(approx)
                aspect_ratio = float(w) / h
                #获得矩形四点坐标
                order_points(approx)
                # 添加长宽比限制
                if aspect_ratio > 0.1 and aspect_ratio < 100.0:
                    # 绘制矩形
                    cv2.drawContours(image, [approx], 0, (0, 255, 0), 2)
                # 使用欧几里得距离公式计算两点之间的距离
                #distance = (pow(point0[0] - point1[0], 2) + pow(point0[1] - point1[1], 2))**0.5
                distance1 = abs(point0[0] - point1[0])
                distance2 = abs(point0[1] - point1[1])   #对距离取绝对值
                print(distance1, distance2)
                # 整合发布的数据并发送
                try:
                    dispoint_msg.distance_1 = distance1
                    dispoint_msg.distance_2 = distance2   #注意自定义消息格式里的数据命名不能和工程里的变量重名
                    dispoint_msg.point_1 = point0[0]
                    dispoint_msg.point_2 = point1[0]
                    dispoint_msg.point_3 = point0[1]
                    dispoint_msg.point_4 = point1[1]
                    #msg.data = msg_front + str(distance1) + msg_middle + str(distance2)
                    if distance2>500.0:
                        # distance_pub.publish(msg)
                        # rospy.loginfo("发布的数据是%s", msg.data)
                        dispoint_pub.publish(dispoint_msg)
                        rospy.loginfo("发布的数据是[%s, %s, %s, %s, %s, %s]", dispoint_msg.distance_1,dispoint_msg.distance_2,dispoint_msg.point_1,dispoint_msg.point_2,dispoint_msg.point_3,dispoint_msg.point_4)
                except rospy.is_shutdown():
                    print("Shutting down cv_bridge_test node.")
                    cv2.destroyAllWindows()
                cv2.imshow("image_rectangle", image)

    else:
        print('x: None y: None')

    # 显示图像
    cv2.imshow("image", image)
    #image_publish(image)
    k = cv2.waitKey(1) & 0xff


四.总结

以上就是本小节的全部内容,结合前几节,焊缝识别的基本功能框架已经实现,准备在下一节再做个颜色识别的博客,以应对不同环境下的干扰。然后就是焊缝检测部分的重难点,标定以及坐标变换,估计到时候更新的速度会变慢,但只要有收获就会继续更新下去。万里长征才刚刚起步,未来任重道远,道阻且长。

五.参考链接

海康威视工业相机在ROS下驱动
https://blog.csdn.net/weixin_60003973/article/details/135824902
海康Camera MVS Linux SDK二次开发封装ROS packge过程记录(c++)
https://blog.csdn.net/weixin_41965898/article/details/116801491
赵虚左ROS课程:话题通信
https://www.bilibili.com/video/BV1Ci4y1L7ZZ?p=47&vd_source=c4f360981aa4bb15debb8ab108d9956d

标签:焊缝,point,--,cv2,point0,dispoint,msg,ROS,distance
From: https://blog.csdn.net/qq_44621315/article/details/141571383

相关文章

  • json格式化com.alibaba.fastjson.JSONException: not match : - =, info :错误
    com.alibaba.fastjson.JSONException:notmatch:-=,info:pos6,line1,column7{intro=全刚的大铁锤,name=巨大铁锤,stock=666}   atcom.alibaba.fastjson.parser.JSONLexerBase.nextTokenWithChar(JSONLexerBase.java:398)   atcom.alibaba.fastjson.......
  • 零基础学习人工智能—Python—Pytorch学习(九)
    前言本文主要介绍卷积神经网络的使用的下半部分。另外,上篇文章增加了一点代码注释,主要是解释(w-f+2p)/s+1这个公式的使用。所以,要是这篇文章的代码看不太懂,可以翻一下上篇文章。代码实现之前,我们已经学习了概念,在结合我们以前学习的知识,我们可以直接阅读下面代码了。代码里使......
  • AdaBoost
    提升方法提升方法就是从弱学习算法出发,反复学习,得到一系列弱分类器(又称为基本分类器),然后组合这些弱分类器,构成一个强分类器。大多数的提升方法都是改变训练数据的概率分布(训练数据的权值分布),针对不同的训练数据分布调用弱学习算法学习一系列弱分类器。在每一轮如何改变训练数......
  • 归一化
    参考资料:https://paddlepedia.readthedocs.io/en/latest/tutorials/deep_learning/normalization/basic_normalization.html。下文仅为复制无任何改动。归一化基础知识点1.什么是归一化归一化是一种数据处理方式,能将数据经过处理后限制在某个固定范围内。归一化存在两种形式,......
  • BatchNorm & LayerNorm
    BatchNorm&LayerNorm目录BatchNorm&LayerNormBatchNorm过程LayerNormNormalization作用:1.缓解内部协变量偏移。在深度神经网络中,随着网络层数的加深,每一层的参数更新都可能导致后续层的输入分布发生变化,这种现象被称为内部协变量偏移(InternalCovariateShift,ICS)。ICS......
  • 推荐
    DIN假设\(V_i^{shop},V_i^{good},V_i^{cate}\)分别表示历史第\(i\)次点击的shop_id,good_id,cate_id,\(V_a^{shop},V_a^{good},V_a^{cate}\)分别表示候选商品的shop_id,good_id,cate_id,则两个不同版本用户兴趣表达\(V_u\)计算方式如下\[\begin{align}g\left(V_i^{shop},......
  • CF865D Buy Low Sell High
    CF865DBuyLowSellHighBuyLowSellHigh题目已知接下来N天的股票价格,每天你可以买进一股股票,卖出一股股票,或者什么也不做.N天之后你拥有的股票应为0,当然,希望这N天内能够赚足够多的钱.分析假如我们当前这个\(a_j\)作为某天卖出,那么一定是和前面的还没有用的最小的\(......
  • Java中方法重写的学习
    方法重写目录方法重写方法重写的规则方法重载的规则方法重写的规则在Java中,方法重写(Overriding)是面向对象编程中的一个核心概念,它允许子类提供一个与父类相同名称、相同参数列表的方法,以实现或修改父类方法的行为。方法重写必须遵循一定的规则,以确保程序的正确性和可维护性。......
  • C#上位机开发——多线程启动停止暂停继续
    引用:上位机开发——多线程启动停止暂停继续-哔哩哔哩(bilibili.com)前言初学者学习编程时,很容易因为多线程出现各种问题,导致不敢使用多线程。但是多线程技术在做开发中,是不可忽视的一个技术,基本上我们实际应用中,每个项目都会使用多线程,所以多线程技术必须掌握。为什么要用多......
  • Re正则库整理
    re库整理Python语言专门提供了re模块,用于实现正则表达式的操作。在实现时,可以使用re模块提供的方法(如search()、match()、findall()等)进行字符串处理,也可以先使用re模块的compile()方法将模式字符串转换为正则表达式对象,然后再使用该正则表达式对象的相关方法来操作字符......