基于轨迹信息的图像近距离可行驶区域方案验证

news2025/1/16 13:47:04

一 图像可行驶区域方案

1.1 标定场景

标定场地

1.2 标定步骤

  1. 设计一定间距标定场,在标定场固定位置设置摄像头标定标识点。
  2. 主车开到标定场固定位置
  3. 录制主车在该位置各个摄像头数据,通过摄像头捕获图像获取图像上关键点坐标pts-2d
  4. 基于标定场设计,计算图像关键点对应车体坐标系中的3d坐标pts-3d
  5. 通过cv2.findHomography(obj_points, img_points, cv2.RANSAC, 5.0) 获取相机坐标系到地面的单应性变换矩阵H

1.3 实车使用

实时获取车辆行进过程中的固定纵向距离的轨迹点信息,使用单应性变换矩阵H反向计算轨迹信息在图像中的投影位置,从而获取到图像中检测目标的距离区间。

二 初步验证结果

'''
Author: XIEXINYAN “1532642675@qq.com”
Date: 2024-07-01 04:52:07
LastEditors: XIEXINYAN “1532642675@qq.com”
LastEditTime: 2024-07-03 05:40:06
FilePath: /202407/hom_matrix.py
Description: 

Copyright (c) 2024 by 1532642675@qq.com, All Rights Reserved. 
'''
import cv2  
import numpy as np  
import os
import argparse

class Counter:
    cnt = 0
    def __init__(self):
        Counter.cnt +=1
    @classmethod
    def get_counter(cls):
        return cls.cnt 
class Calibrate:
    def __init__(self, pattern_size, real_square_size, offset_x, offset_y):
        self.pattern_size = pattern_size
        self.real_square_size = real_square_size
        self.offset_x = offset_x
        self.offset_y = offset_y
    # 1. 检测棋格板角点  
    def find_chessboard_corners(self, image, color=(0, 255, 0), vis=False,  save=False, calib=False): 
        self.image = image.copy()
        image_painted = image.copy()
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  
        ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)  
        if ret:  
            criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)  
            #按照pattern_size[0]的个数排序,绘制的第一组数据个数=pattern_size[0]的个数
            self.corner = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
            
            if self.corner is not None:
                '''
                0  3  6          2  5  8           6  3  0            8  5  2
              1  4  7          1  4  7            7  4  1            7  4  1    
            2  5  8          0  3  6            8  5  2            6  3  0  
                '''
                if vis:
                    #判断corners排序顺序
                    index_list = []
                    if (self.corner[0][0][1]<self.corner[1][0][1] 
                        and self.corner[0][0][0]<self.corner[np.prod(self.pattern_size)-1][0][0]):
                        print("mode A")
                    elif (self.corner[0][0][1]>self.corner[1][0][1] 
                        and self.corner[0][0][0]<self.corner[np.prod(self.pattern_size)-1][0][0]):
                        print("mode B")
                        for j in range(pattern_size[1]):
                            for i in range(pattern_size[0]):
                                index_list.append(pattern_size[0]-1-i+j*pattern_size[0])
                    elif (self.corner[0][0][1]<self.corner[1][0][1] 
                        and self.corner[0][0][0]>self.corner[np.prod(self.pattern_size)-1][0][0]):
                        print("mode C")
                        index_list = []
                        for j in range(pattern_size[1]):
                            for i in range(pattern_size[0]):
                                index_list.append(i+(pattern_size[1]-1-j)*pattern_size[0])
                        print(index_list)
                    elif (self.corner[0][0][1]>self.corner[1][0][1] 
                        and self.corner[0][0][0]>self.corner[np.prod(self.pattern_size)-1][0][0]):
                        print("mode D")
                        index_list = []
                        for j in range(pattern_size[1]):
                            for i in range(pattern_size[0]):
                                index_list.append(i+(pattern_size[1]-1-j)*pattern_size[0])
                        print(index_list)
                    else:
                        print("horizonal mode")
                    self.corner = self.corner[index_list]
                    cv2.circle(image_painted, (int(self.corner[0][0][0]), int(self.corner[0][0][1])), 25, (0, 255, 255), -1)  
                    cv2.circle(image_painted, (int(self.corner[1][0][0]), int(self.corner[1][0][1])), 25, (0, 0, 255), -1) 
                    for corner in self.corner:
                        cv2.circle(image_painted, (int(corner[0][0]), int(corner[0][1])), 5, (0, 0, 255), -1)  
                    cv2.drawChessboardCorners(image_painted, pattern_size, self.corner, True)  
                    cv2.imshow("chess",image_painted)
                if save:
                    instance=Counter()
                    cv2.imwrite(str(instance.get_counter())+".jpg", image)
                if calib:
                    self.find_hom_matrix(vis=True, save=True)
                return True
        return False
    
    def world_chess_board_loc(self):
        # 初始化obj_points数组,注意使用齐次坐标(即每个点都是[x, y, 1])  
        obj_points = np.zeros((np.prod(self.pattern_size), 3), dtype=np.float32)  
        # x_start是每行开始的x坐标  # y_start是每行开始的y坐标 
        # # 填充obj_points数组  
        '''
        从左上角开始
        0  3  6  9  
        1  4  7  10
        2  5  8  11
        '''
        # obj_points =np.array([
        #     [  0.,   0.,   1.],[  0.,  60.,   1.],[  0., 120.,   1.],
        #     [ 60.,   0.,   1.],[ 60.,  60.,   1.],[ 60., 120.,   1.],
        #     [120.,   0.,   1.],[120.,  60.,   1.],[120., 120.,   1.],
        #     [180.,  0.,   1.],[180.,  60.,   1.],[180., 120.,   1.]], dtype=np.float32)
        index = 0 
        for i in range(pattern_size[1]):  
            for j in range(pattern_size[0]):  
                # 计算x和y坐标  
                x = i * self.real_square_size 
                y = j * self.real_square_size  
                # 将点添加到obj_points数组中,注意使用齐次坐标形式  
                obj_points[index, :] = [x, y, 1.0]  
                index += 1  
        return obj_points
    '''
    将世界坐标系下点转化为wraped图像上点
    '''
    def world_transation(self):
        obj_points = self.world_chess_board_loc()
        obj_points_t = obj_points.copy()
        obj_points_t[:,0] += self.offset_x
        obj_points_t[:,1] += self.offset_y
        obj_points_t[:,:2] *= 1000
        return obj_points_t
    
    def world_to_image(self, img, vis=False, save=False):
        # obj_points 是世界坐标系下的点,需要是齐次坐标形式 

        obj_points_t = self.world_transation()
        # 使用np.dot进行矩阵乘法,并计算归一化的图像坐标  
        img_points_homogeneous = np.dot(self.H, obj_points_t.T).T  
        img_points = img_points_homogeneous[:, :2] / img_points_homogeneous[:, 2:].reshape(-1, 1) 
        for pt_2d in img_points:
            cv2.circle(img, (int(pt_2d[0]), int(pt_2d[1])), 5, (0, 0, 255), -1) 
        if vis:
            cv2.imshow("eval image", img)
        if save:
            counter = Counter()
            cv2.imwrite("eval_"+str(counter.get_counter())+".jpg",img)
        return

    
    def find_hom_matrix(self, vis=False, save=False):
        # 世界坐标值 【横,纵,高】
        obj_points = self.world_chess_board_loc() 
        # 偏移到某个坐标系
        obj_points[:,0] += self.offset_x 
        obj_points[:,1] += self.offset_y
        obj_points[:,:2] *= 1000
        # print(obj_points)
        # 3. 计算单应性矩阵  
        img_points = self.corner.reshape(-1, 1, 2).astype(np.float32)  
        self.H, _ = cv2.findHomography(obj_points, img_points, cv2.RANSAC, 5.0)  
        warped_image = cv2.warpPerspective(self.image, self.H,  (self.image.shape[1], self.image.shape[0]))
        if vis:
            cv2.imshow("wrapped image",warped_image)
            cv2.waitKey()
        if save:
            cv2.imwrite("wrapped_"+str(Counter.cnt)+".jpg", warped_image)
        return 
        

def find_qrcode_corners(image, vis=False):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  
        # 二值化  
        _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  
        # # 查找轮廓  
        # contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # 查找轮廓(OpenCV 4.x) 
        contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  
        #打印轮廓信息  
        print("总轮廓数:", len(contours))
        # 筛选和排序轮廓(这里我们假设二维码是最大的轮廓)  
        contours = sorted(contours, key=cv2.contourArea, reverse=True)  
        qrcode_contour = contours[0]  
        # 多边形近似  
        epsilon = 0.02 * cv2.arcLength(qrcode_contour, True)  
        approx = cv2.approxPolyDP(qrcode_contour, epsilon, True)  
        image_out = image.copy()
        # 提取角点坐标  
        corners = approx.reshape((-1, 2))  
        # 在原图上绘制角点  
        if len(corners) == 4:
            for corner in corners:  
                cv2.circle(image_out, (int(corner[0]), int(corner[1])), 25, (0, 0, 255), -1)  
                # 显示图像  
                cv2.imshow('QRCode Corners', image_out)  
            
        cv2.drawContours(image_out, qrcode_contour, -1, (0, 255, 0), 3)  
        cv2.imshow('Corners', image_out)  
        cv2.waitKey(1)   
    



def argParser():
    parser = argparse.ArgumentParser()
    parser.add_argument('--rows', type=int, default=3,help='chess board raw num')
    parser.add_argument('--cols', type=int, default=4,help='chess board col num')
    parser.add_argument('--online',type=bool, default=False, help='online camera calib')
    opt = parser.parse_args()
    return opt

if __name__ == '__main__':
    opt = argParser()
    pattern_size = (opt.rows, opt.cols)
    calib = Calibrate(pattern_size, 0.06, 0.3, 0.7)

    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        exit()
    print(" now start calib %d\n",opt.online)
    if opt.online:
        while True:
            ret, frame = cap.read()
            flag = calib.find_chessboard_corners(frame, vis=True, save=True, calib=True) 
            cv2.waitKey(1)  
            if flag:
                break
    else:
        path = "img"
        image_list = os.listdir(path)
        for img in image_list:
            img_path = os.path.join(path,img)
            if os.path.isfile(img_path):
                frame = cv2.imread(img_path)
            else:
                continue
            print("image path is: ",img_path)
            flag = calib.find_chessboard_corners(frame, vis=True, save=False, calib=True)
            cv2.waitKey(1)
            if flag:
                break
    print(calib.H)
    print(" now start eval \n")
    if opt.online:
        while True:
            ret, frame = cap.read()
            # 如果正确读取帧,ret为True
            if not ret:
                print("无法接收帧,请退出")
                break       
            calib.world_to_image(frame,True, False)
            # 显示实时画面
            cv2.imshow('raw', frame)
            # 按 'q' 键退出循环
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        # 释放摄像头资源并关闭所有窗口
        cap.release()
    else:
        path = "img"
        image_list = os.listdir(path)
        for img in image_list:
            img_path = os.path.join(path,img)
            if os.path.isfile(img_path):
                frame = cv2.imread(img_path)
            else:
                continue
            calib.world_to_image(frame, True, True)
            # 显示实时画面
            cv2.imshow('raw', frame)
            # 按 'q' 键退出循环
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

cv2.destroyAllWindows()

三 存在问题

  1. 本方案在设计标定场过程中需要精确计算每个相机的FOV,与地面的交点,设计地面标志物,使得每个相机可以准确有效的提取地面标志物
  2. 会受到道路坡度和车辆pitch角影响,需要模拟分析pitch角对距离的影响度

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

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

相关文章

Windows上使用Navicat连接ubuntu上的mysql8报错:10061和1130

问题一&#xff1a;can’t connect to mysql server on ‘192.168.xxx.xxx’(10061) 解决&#xff1a; sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf&#xff0c;bind-address绑定了登陆的IP&#xff0c;把这两行代码注释掉&#xff0c;然后重启mysql。 问题二&#xff1a;1…

WMS系统对小型海外仓有哪些好处?规模不大有必要用吗?

作为一家想持续发展的海外仓&#xff0c;虽然目前的规模还不大&#xff0c;但是也需要不断优化仓库的作业效率。实施海外仓WMS系统是个不错的选择。 海外仓WMS系统的实施&#xff0c;不仅可以提升库存管理水平和一件代发等核心业务的效率&#xff0c;还能提升工人的生产效率&a…

智能本质:马毅教授对大模型和白盒理论的观点

引言 在人工智能的快速发展中&#xff0c;我们见证了从简单的自动化工具到复杂的智能系统的演变。随着深度学习技术的突破&#xff0c;大模型如GPT系列已经能够执行从文本生成到图像识别等多样化任务。然而&#xff0c;这些模型虽然在功能上取得了显著进展&#xff0c;但其内部…

洛谷 P1011 [NOIP1998 提高组] 车站

题目描述 火车从始发站&#xff08;称为第 1 站&#xff09;开出&#xff0c;在始发站上车的人数为 a&#xff0c;然后到达第 2 站&#xff0c;在第 2 站有人上、下车&#xff0c;但上、下车的人数相同&#xff0c;因此在第 2 站开出时&#xff08;即在到达第 3 站之前&#x…

存储器类型介绍

存储器 ROM 我们一般把手机和电脑的硬盘当作ROM。ROM的全称是&#xff1a;Read Only Memery&#xff0c;只读存储器&#xff0c;就是只能读不能写的存储器。但是现在的ROM不仅可以读&#xff0c;还可以写数据&#xff0c;比如给手机下载APP&#xff0c;就是给手机上的ROM写数据…

闲鱼商品搜索关键词优化攻略

一、闲鱼商品详情关键词搜索概述 闲鱼作为国内最大的二手交易平台之一&#xff0c;其商品搜索功能对于买家和卖家来说至关重要。商品详情页中的关键词搜索功能&#xff0c;可以帮助买家更快速地找到心仪的商品&#xff0c;也可以帮助卖家提高商品的曝光度&#xff0c;从而促进…

半导体制造企业 文件共享存储应用

用户背景&#xff1a;半导体设备&#xff08;上海&#xff09;股份有限公司是一家以中国为基地、面向全球的微观加工高端设备公司&#xff0c;为集成电路和泛半导体行业提供具竞争力的高端设备和高质量的服务。 挑战&#xff1a;芯片的行业在国内迅猛发展&#xff0c;用户在上海…

版本控制系统:Git 纯应用(持续更新);

基本操作 ctrl上行键&#xff1a;上次代码 本地仓库&#xff1a;Git init 新建文件&#xff1a;touch xxxx.xxx 查看状态&#xff1a;Git status 文件从工作区——暂存区&#xff1a;Git add ./文件名(.是通配符代表所有) 暂存区——仓库&#xff1a;Git commit -m &…

shark云原生-日志体系-filebeat高级配置(适用于生产)

文章目录 1. filebeat.inputs 静态日志收集器2. filebeat.autodiscover 自动发现2.1. autodiscover 和 inputs2.2. 如何配置1.2.1. Providers 提供者1.2.2. Providers kubernetes templates1.2.3. 基于提示&#xff08;hints&#xff09;的自动发现支持的 **hints**的完整列表&…

2024年07月03日 Redis部署方式和持久化

Redis持久化方式&#xff1a;RDB和AOF&#xff0c;和混合式 RDB&#xff1a;周期备份模式&#xff0c;每隔一段时间备份一份快照文件&#xff0c;从主线程Fork一个备份线程出来备份&#xff0c;缺点是会造成数据的丢失。 AOF&#xff1a;日志模式&#xff0c;每条命令都以操作…

【操作与配置】VSCode配置C/C++及远程开发

MINGW环境配置 进入网站&#xff0c;如下图下载&#xff1a;MinGW Distro - nuwen.net 运行安装包&#xff0c;使其安装在你指定的位置 将MinGW的bin目录添加到系统的环境变量PATH中 使用 winx 选择进入“系统”点击“高级系统设置”在“系统属性&#xff1a;高级”窗口中&am…

6 矩阵相关案例

矩阵计算在CUDA中的应用是并行计算领域的典型场景 &#xff1b; 矩阵算法题通常涉及线性代数的基础知识&#xff0c;以及对数据结构和算法的深入理解。解决这类问题时&#xff0c;掌握一些核心思想和技巧会非常有帮助。以下是一些常见的矩阵算法题解题思想&#xff1a; 动态规划…

解析MySQL核心技术:视图的实用指南与实践案例

在数据库管理中&#xff0c;MySQL视图&#xff08;View&#xff09;是一种强大的功能&#xff0c;利用它可以简化复杂查询、提高数据安全性以及增强代码的可维护性。本篇文章将详细介绍MySQL视图的相关知识&#xff0c;包括视图的创建、修改、删除、使用场景以及常见的最佳实践…

Build a Large Language Model (From Scratch)附录D(gpt-4o翻译版)

来源&#xff1a;https://github.com/rasbt/LLMs-from-scratch?tabreadme-ov-file https://www.manning.com/books/build-a-large-language-model-from-scratch

五.核心动画 - 图层的变换(平移,缩放,旋转,3D变化)

引言 在上一篇博客中&#xff0c;我们研究了一些视觉效果&#xff0c;在本篇博客中我们将要来讨论一下图层的旋转&#xff0c;平移&#xff0c;缩放&#xff0c;以及可以将扁平物体转换成三维空间对象的CATransform3D。 图层变换 图层的仿射变换 在视图中有一个transform属…

[ C++ ] 深入理解模板( 进 阶 )

目录 非类型模板参数 类模板没有实例化的情况 模板的特化 注意函数特化中遇到的问题 建议&#xff1a;&#xff08;直接使用函数重载&#xff09; 类模板特化 全特化 偏特化 偏特化有以下两种表现方式&#xff1a; 部分特化&#xff08;将模板参数类表中的一部分参数特化…

路由的高级用法

多级路由 1.新建一个Mian组件 <template><div> <h1>我是Msg的子组件</h1></div> </template><script> export default {name: "Mian", } </script><style> </style> 2.在router中msg小新建一个路由 imp…

利用运放设计简单有源滤波器(低通、高通、带通)

本文旨在帮助刚接触模电的同学快速设计一个实用可靠的有源滤波器&#xff0c;故我将不会说一些晦涩难懂的原理&#xff0c;只给出仿真电路图。 低通滤波器 图1 低通滤波器 图1所示的是一个截止频率约为1KHz的低通滤波器。 图2 200Hz的情况 图3 2KHz的情况 设计步骤为&#x…

【京存】AI人工智能时代的分布式存储

如今&#xff0c;AI人工智能的浪潮席卷全球&#xff0c;数据以前所未有的速度增长与积累。如何高效存储、管理和利用海量数据&#xff0c;成为推动AI发展的关键。 今日&#xff0c;我们将为您深度剖析AI人工智能分布式存储方案&#xff0c;伴随AI技术在图像识别、自然语言处理…

收购北京1000万投资集团公司要求和收购费用

收购北京投资集团公司执照多少钱&#xff0c;投资集团公司注册代理投资、金融类公司已经全国停止注册&#xff0c;目前唯一还可以注册的就是金武汉南京投资公司&#xff0c;但是政策也是越来越紧、限制越来越多有的地区已经不让核名了&#xff0c;说不好哪天也就停止注册了&…