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

一 图像可行驶区域方案

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角对距离的影响度

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

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

相关文章

Python | Leetcode Python题解之第222题完全二叉树的节点个数

题目&#xff1a; 题解&#xff1a; # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right class Solution:def countNodes(self,…

基于字典学习的地震数据降噪(MATLAB R2021B)

稀疏表示基于研究者们提出了许多变换基函数的方法逐渐成型&#xff0c;比如小波域&#xff0c;曲波域&#xff0c;dreamlet 域等&#xff0c;其原理是利用地震信号在变换域内的稀疏性和可分离性以去除噪声。继 Donoho发表非线性去噪方法-小波阈值萎缩方法&#xff0c;在后续的研…

汉中茗茶小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;茶叶管理&#xff0c;论坛管理&#xff0c;公告管理&#xff0c;茗茶历史管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;茗茶信息&#xf…

阶段三:项目开发---搭建项目前后端系统基础架构:任务9:导入空管基础数据

任务描述 本阶段任务是导入项目的基础数据&#xff0c;包括空管基础数据和离线的实时飞行数据&#xff08;已经脱敏&#xff09;。 任务指导 本阶段任务需要导入两种数据&#xff1a; 1、在MySQL中导入空管基础数据 kongguan.sql空管基础数据表说明&#xff1a; 1告警信息…

JVM原理(二二):JVM虚拟机线程调度与状态转换

1. Java线程调度 Java的线程是被映射到系统的原生线程上实现的 线程调度是指系统为线程分配处理器使用权的过程&#xff0c;调度主要方式有两种&#xff0c;分别是协同式线程调度和抢占式线程调度。 协同式线程调度&#xff1a;如果使用协同式调度的多线程系统&#xff0c;线…

Cortex-A510——内核及汇编

Cortex-A510——内核及汇编 小狼http://blog.csdn.net/xiaolangyangyang 1、异常等级 2、异常等级切换 同步异常&#xff1a; 1、SVC/HVC/SMC&#xff1b; 2、MMU引发的异常&#xff08;内核态EL1发生&#xff0c;发生后不会进行异常等级切换…

Java基础-内部类与异常处理

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 一、Java 内部类 什么是内部类&#xff1f; 使用内部类的优点 访问局部变量的限制 内部类和继承 内部…

java 闭锁(CountDownLatch)

闭锁&#xff08;CountDownLatch&#xff09;是Java中的一个同步辅助类&#xff0c;用于协调多个线程之间的协作。它允许一个或多个线程等待&#xff0c;直到在其他线程中执行的一组操作完成。闭锁非常适用于需要等待一组事件发生之后再执行某些操作的场景。 import java.uti…

maxwell启动报错:Could not find first log file name in binary log index file

出现该问题是因为&#xff1a;maxwell 读取的是 mysql 的 binlog 日志&#xff0c;而配置文件中的两个值与 binlog 的最新值没有保持一致导致 1. 切换到maxwell的库 show master status;记住图片中的 FIle 和 Position 2. 修改maxwell的配置 SELECT * from positions p ;将…

生物墨水:3D组织生物打印的基石

生物墨水是3D组织生物打印技术的核心组成部分。生物墨水通常由生物材料&#xff08;如水凝胶聚合物&#xff09;与所需的细胞和/或其他生物大分子&#xff08;例如生长因子&#xff09;混合而成。为了成功地进行组织生物打印&#xff0c;生物墨水必须满足以下要求&#xff1a; …

利用面向AWS的Thales Sovereign解决方案保护AI之旅

亚马逊网络服务(AWS)是全球最大的云服务提供商。众所周知&#xff0c;他们致力于提供工具、解决方案和最佳实践&#xff0c;使其客户能够安全地利用AWS上的生成式人工智能 (GenAI) 工作负载。组织正在迅速使用GenAI为企业带来更高的生产力和创造力。在GenAI的几乎所有用途中&am…

昇思MindSpore 25天学习打卡营|day18

DCGAN生成漫画头像 在下面的教程中&#xff0c;我们将通过示例代码说明DCGAN网络如何设置网络、优化器、如何计算损失函数以及如何初始化模型权重。在本教程中&#xff0c;使用的动漫头像数据集共有70,171张动漫头像图片&#xff0c;图片大小均为96*96。 GAN基础原理 这部分原…

C#——多态详情

多态 多态: 是同一个行为&#xff0c;具有多个不同表现形式或形态的能力 多态分为两种 : 静态性多态: 函数重载&#xff0c;符号重载动态性多态: 虚方法&#xff0c;抽象类&#xff0c;接口 静态多态 在编译时&#xff0c;函数和对象的连接机制被称为早期绑定&#xff0c;…

如何恢复已删除的音频文件

设备中文件被意外删除并不是什么新鲜事。但是&#xff0c;如果文件是你最喜欢的 MP3 歌曲&#xff0c;那就太令人沮丧了。但你知道吗&#xff0c;有一种方法可以从 Windows 机器中恢复已删除的音乐文件。尝试奇客数据恢复并检索已删除的音频文件。虽然产品名称听起来不像可以帮…

【C语言】C语言编译链接和Win32API简单介绍

目录 翻译环境和运行环境翻译环境编译器预处理&#xff08;预编译&#xff09;编译链接 执行环境 Win32API是什么控制台程序控制台获取坐标COORDGetStdHandle函数GetConsoleCursorinfo函数CONSOLE_CURSOR_INFOSetConsoleCursorInfo函数SetConsoleCursorPostion函数GetAsyncKeyS…

如何在Spring Boot中实现分布式任务调度?

文章目录 引言一、分布式任务调度的基本原理二、Spring Boot与分布式任务调度1. 使用Quartz实现分布式任务调度2. 使用Elastic-Job实现分布式任务调度 三、常见问题与解决方案结论 &#x1f389;欢迎来到SpringBoot框架学习专栏~ ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;…

世优科技获新锐商业价值奖,数字人阿央入选北京市元宇宙“名人”

2024全球经济大会元宇宙创新发展论坛暨2024第九届“创客中国”元宇宙中小企业创新创业大赛&#xff0c;由工业和信息化部网络安全产业发展中心、北京市经济和信息化局、石景山区人民政府、首钢集团有限公司主办&#xff0c;围绕元宇宙底层技术端和产业应用端两个方向&#xff0…

Polar Si9000软件详细使用教程

Polar Si9000软件是一款简单易用的阻抗计算神器&#xff0c;文本详细介绍该软件的使用。 一、安装 网上很多安装包&#xff0c;这里不赘述&#xff0c;需要注意的是&#xff0c;如果要希望使用中文版&#xff0c;需要在如下路径中放入简体中文配置文件&#xff08;PJ包一般会有…

C++和Python蚂蚁搬食和蚊虫趋光性和浮标机群行为算法神经网络

&#x1f3af;要点 &#x1f3af;机器人群行为配置和C行为实现&#xff1a;&#x1f58a;脚底机器人狭隘空间导航避让障碍物行为 | &#x1f58a;脚底机器人使用摄像头耦合共振&#xff0c;实现同步动作 | &#x1f58a;脚底机器群使用相机&#xff0c;计算彼此间“分子间势能…

数据库性能优化系统设计

设计一个数据库性能优化系统&#xff0c;目标是监测、诊断并改善数据库的运行效率&#xff0c;确保系统能够高效稳定地处理大量数据请求。以下是一个概要设计&#xff0c;包括关键模块、功能和实现思路&#xff1a; 1. 系统架构 分布式监控中心&#xff1a;采用分布式架构收集…