评测 香橙派OrangePi在智能交通上的应用

1、OrangePi应用场景

关于 Orange Pi AI Pro 开发板是香橙派联合华为精心打造的高性能 AI 开发板,其搭载了昇腾 AI 处理器,可提供 8TOPS INT8 的计算能力,内存提供了 8GB 和 16GB两种版本。可以实现图像、视频等多种数据分析与推理计算,可广泛用于教育、机器人、无人机等场景。此次我将测评板卡在智能交通上的应用。处理四路视觉检测、追踪,且完成多摄像头追踪。通常我们将该结构化数据后叫全息路口。
由于简单的开机,远程以及硬件等测评都较为简单,跑通官方demo即可,此处我们移植比较复杂的算法,将该算力压榨干净,以证明其强大的处理能力。硬件接口图如下

img

1.1 智能交通的全息路口介绍

近年来,国内城镇化迅速发展,城市交通出行需求增长迅速,给城市道路交通秩序与安全管控带来较大压力。路口作为城市道路的重要节点,需要具备精准的数字化感知能力,才能有效提升道路精细化治理能力。

而传统路口的信息感知不精准,交管部门无法根据路口排队车辆多少、有无事故车辆、有无车辆溢出等关键信息来指挥交通。

全息路网通过融合视频和雷达数据,结合高精地图、边缘计算等技术,可全天候精准采集路口车道级流量、排队长度、车辆速度、行车轨迹、停车次数、事故等信息,彻底解决路口绿灯空放问题,可大大缩短了红灯等待时间。某地交管部门在东二环路南北路段应用线性绿波带后。高峰期内,行程时间压缩了20%左右,平峰期行程时间平均压缩了30%,停车次数降低了2次以上。

全息路网也可快速发现路网的异常事件及违法行为,将事件视频、事件地址与辅助判罚报告通知指挥中心,形成接处警快速闭环机制,实现远程处理擦碰事故,有效缓解拥堵,避免二次事故。这里放出一张结果图吧,方便大家了解。使用视觉感知算法,将十字路口所有交通参与者识别、追踪、定位,孪生在高精地图上

img

1.2 Orange Pi AI Pro 开发板与相机连接图

总的来说就是用Orange Pi AI Pro处理四路摄像头数据,将四路摄像头接入交换机,再将Orange Pi AI Pro的网口也接入交换机,这样Orange Pi AI Pro就可以拉到四路相机的视频流了,示意图如下

img

首先我们在十字路口安装四个枪机,照射车辆去向,当然也可以复用交警的电警杆,路口安装示意图如下所示

img

2、Orange Pi AI Pro处理相机rtsp流

由于路口枪机均是网络相机,视觉算法的处理流程如下图所示

img

2.1 Orange Pi AI Pro解析rtsp视频流

用海康威视的摄像实时读取视频,读取视频的格式是YV12格式,摄像机进行压缩算法处理后的H264视频流通过RTSP协议传向网络应用层,用户拿到的数据是H265格式,需要使用ACLLite接口完成视频解码,将H265文件的前十帧并解码为YUV图片硬解码,得到原来的YV12格式的图像视频,最后经过opencv处理得到RGB格式显示到屏幕或者直接使用ACLLite进行颜色空间转换进行预处理。
官方给出了如何将H265编码视频如何解析成H265文件,具体可参考

https://gitee.com/ascend/EdgeAndRobotics/blob/master/Samples/VideoDecode/src/main.cpp
也可以参考这个案例

https://gitee.com/ascend/samples/tree/master/inference/modelInference/sampleResnetRtsp/cpp

但是并未给出如何解析rtsp流到H265的步骤,这里我们使用AclLite库,使用海康rtsp流作为样例的输入数据,使能Acllite解码rtsp,缩放图片。
直接贴代码

#include <dirent.h>
#include <opencv2/opencv.hpp>
#include "AclLiteUtils.h"
#include "AclLiteImageProc.h"
#include "AclLiteVideoProc.h"
#include "AclLiteResource.h"
#include "AclLiteError.h"
#include "AclLiteModel.h"
//#include "label.h"using namespace std;
using namespace cv;
typedef enum Result {SUCCESS = 0,FAILED = 1
} Result;aclrtRunMode runMode_;
ImageData resizedImage_;
int32_t modelWidth_;
int32_t modelHeight_;Result ProcessInput(string testImgPath)
{// read image from fileImageData image;AclLiteError ret = ReadJpeg(image, testImgPath);if (ret == FAILED) {ACLLITE_LOG_ERROR("ReadJpeg failed, errorCode is %d", ret);return FAILED;}// copy image from host to dvppImageData imageDevice;ret = CopyImageToDevice(imageDevice, image, runMode_, MEMORY_DVPP);if (ret == FAILED) {ACLLITE_LOG_ERROR("CopyImageToDevice failed, errorCode is %d", ret);return FAILED;}AclLiteImageProc imageProcess_;// image decoded from JPEG format to YUVImageData yuvImage;ret = imageProcess_.JpegD(yuvImage, imageDevice);if (ret == FAILED) {ACLLITE_LOG_ERROR("Convert jpeg to yuv failed, errorCode is %d", ret);return FAILED;}// zoom image to modelWidth_ * modelHeight_ret = imageProcess_.Resize(resizedImage_, yuvImage, modelWidth_, modelHeight_);if (ret == FAILED) {ACLLITE_LOG_ERROR("Resize image failed, errorCode is %d", ret);return FAILED;}return SUCCESS;
}int main(int argc, char *argv[]) 
{int argNum = 2;if ((argc < argNum)) {ACLLITE_LOG_ERROR("Please input: ./main rtsp address");return FAILED;}AclLiteError ret = aclrtGetRunMode(&runMode_);if (ret == FAILED) {ACLLITE_LOG_ERROR("get runMode failed, errorCode is %d", ret);return FAILED;}std::string inputDataPath =  string(argv[1]);if (ret) {ACLLITE_LOG_ERROR("Init resource failed, error %d", ret);return FAILED;}// open cameraint device = 0;AclLiteVideoProc cap = AclLiteVideoProc(inputDataPath, device);if (!cap.IsOpened()) {ACLLITE_LOG_ERROR("Open camera failed");return FAILED;}// read frame from camera and inferencewhile (true) {ImageData image;AclLiteError ret = cap.Read(image);if (ret) {break;}ACLLITE_LOG_INFO("Execute sample success");return SUCCESS;}
}

解码后可使用opencv将yuv转成RGB进行屏幕输出如图

img

同时拉四路相机流效果如下:

img

2.2 Orange Pi AI Pro yolo 推理

通过上面解码之后,我们已经得到YUV图,接下来以YOLOV7网络模型,需要使用Acllite对图片进行预处理,并通过模型转换使能静态AIPP功能,使能AIPP功能后,YUV420SP_U8格式图片转化为RGB,然后减均值和归一化操作,并将该信息固化到转换后的离线模型中,对YOLOV7网络执行推理,对图片进行物体检测和分类,并给出标定框和类别置信度。
图片物体检测,并且在图片上给出物体标注框,类别以及置信度。
模型训练与 转换直接参考官网

https://gitee.com/ascend/samples/tree/master/inference/modelInference/sampleYOLOV7

此处我贴出代码与效果


#include <dirent.h>
#include <opencv2/opencv.hpp>
#include "AclLiteUtils.h"
#include "AclLiteImageProc.h"
#include "AclLiteResource.h"
#include "AclLiteError.h"
#include "AclLiteModel.h"
#include "label.h"using namespace std;
using namespace cv;
typedef enum Result {SUCCESS = 0,FAILED = 1
} Result;typedef struct BoundBox {float x;float y;float width;float height;float score;size_t classIndex;size_t index;
} BoundBox;bool sortScore(BoundBox box1, BoundBox box2)
{return box1.score > box2.score;
}class SampleYOLOV7 {public:SampleYOLOV7(const char *modelPath, const int32_t modelWidth, const int32_t modelHeight);Result InitResource();Result ProcessInput(string testImgPath);Result Inference(std::vector<InferenceOutput>& inferOutputs);Result GetResult(std::vector<InferenceOutput>& inferOutputs, string imagePath, size_t imageIndex, bool release);~SampleYOLOV7();private:void ReleaseResource();AclLiteResource aclResource_;AclLiteImageProc imageProcess_;AclLiteModel model_;aclrtRunMode runMode_;ImageData resizedImage_;const char *modelPath_;int32_t modelWidth_;int32_t modelHeight_;
};SampleYOLOV7::SampleYOLOV7(const char *modelPath, const int32_t modelWidth, const int32_t modelHeight) :modelPath_(modelPath), modelWidth_(modelWidth), modelHeight_(modelHeight)
{
}SampleYOLOV7::~SampleYOLOV7()
{ReleaseResource();
}Result SampleYOLOV7::InitResource()
{// init acl resourceAclLiteError ret = aclResource_.Init();if (ret == FAILED) {ACLLITE_LOG_ERROR("resource init failed, errorCode is %d", ret);return FAILED;}ret = aclrtGetRunMode(&runMode_);if (ret == FAILED) {ACLLITE_LOG_ERROR("get runMode failed, errorCode is %d", ret);return FAILED;}// init dvpp resourceret = imageProcess_.Init();if (ret == FAILED) {ACLLITE_LOG_ERROR("imageProcess init failed, errorCode is %d", ret);return FAILED;}// load model from fileret = model_.Init(modelPath_);if (ret == FAILED) {ACLLITE_LOG_ERROR("model init failed, errorCode is %d", ret);return FAILED;}return SUCCESS;
}Result SampleYOLOV7::ProcessInput(string testImgPath)
{// read image from fileImageData image;AclLiteError ret = ReadJpeg(image, testImgPath);if (ret == FAILED) {ACLLITE_LOG_ERROR("ReadJpeg failed, errorCode is %d", ret);return FAILED;}// copy image from host to dvppImageData imageDevice;ret = CopyImageToDevice(imageDevice, image, runMode_, MEMORY_DVPP);if (ret == FAILED) {ACLLITE_LOG_ERROR("CopyImageToDevice failed, errorCode is %d", ret);return FAILED;}// image decoded from JPEG format to YUVImageData yuvImage;ret = imageProcess_.JpegD(yuvImage, imageDevice);if (ret == FAILED) {ACLLITE_LOG_ERROR("Convert jpeg to yuv failed, errorCode is %d", ret);return FAILED;}// zoom image to modelWidth_ * modelHeight_ret = imageProcess_.Resize(resizedImage_, yuvImage, modelWidth_, modelHeight_);if (ret == FAILED) {ACLLITE_LOG_ERROR("Resize image failed, errorCode is %d", ret);return FAILED;}return SUCCESS;
}Result SampleYOLOV7::Inference(std::vector<InferenceOutput>& inferOutputs)
{// create input data set of modelAclLiteError ret = model_.CreateInput(static_cast<void *>(resizedImage_.data.get()), resizedImage_.size);if (ret == FAILED) {ACLLITE_LOG_ERROR("CreateInput failed, errorCode is %d", ret);return FAILED;}// inferenceret = model_.Execute(inferOutputs);if (ret != ACL_SUCCESS) {ACLLITE_LOG_ERROR("execute model failed, errorCode is %d", ret);return FAILED;}return SUCCESS;
}Result SampleYOLOV7::GetResult(std::vector<InferenceOutput>& inferOutputs,string imagePath, size_t imageIndex, bool release)
{uint32_t outputDataBufId = 0;float *classBuff = static_cast<float *>(inferOutputs[outputDataBufId].data.get());// confidence thresholdfloat confidenceThreshold = 0.25;// class numbersize_t classNum = 80;// number of (x, y, width, hight, confidence)size_t offset = 5;// total number = class number + (x, y, width, hight, confidence)size_t totalNumber = classNum + offset;// total number of boxssize_t modelOutputBoxNum = 25200;// top 5 indexes correspond (x, y, width, hight, confidence),// and 5~85 indexes correspond object's confidencesize_t startIndex = 5;// read source image from filecv::Mat srcImage = cv::imread(imagePath);int srcWidth = srcImage.cols;int srcHeight = srcImage.rows;// filter boxes by confidence thresholdvector <BoundBox> boxes;size_t yIndex = 1;size_t widthIndex = 2;size_t heightIndex = 3;size_t classConfidenceIndex = 4;for (size_t i = 0; i < modelOutputBoxNum; ++i) {float maxValue = 0;float maxIndex = 0;for (size_t j = startIndex; j < totalNumber; ++j) {float value = classBuff[i * totalNumber + j] * classBuff[i * totalNumber + classConfidenceIndex];if (value > maxValue) {// index of classmaxIndex = j - startIndex;maxValue = value;}}float classConfidence = classBuff[i * totalNumber + classConfidenceIndex];if (classConfidence >= confidenceThreshold) {// index of object's confidencesize_t index = i * totalNumber + maxIndex + startIndex;// finalConfidence = class confidence * object's confidencefloat finalConfidence =  classConfidence * classBuff[index];BoundBox box;box.x = classBuff[i * totalNumber] * srcWidth / modelWidth_;box.y = classBuff[i * totalNumber + yIndex] * srcHeight / modelHeight_;box.width = classBuff[i * totalNumber + widthIndex] * srcWidth/modelWidth_;box.height = classBuff[i * totalNumber + heightIndex] * srcHeight / modelHeight_;box.score = finalConfidence;box.classIndex = maxIndex;box.index = i;if (maxIndex < classNum) {boxes.push_back(box);}}}// filter boxes by NMSvector <BoundBox> result;result.clear();float NMSThreshold = 0.45;int32_t maxLength = modelWidth_ > modelHeight_ ? modelWidth_ : modelHeight_;std::sort(boxes.begin(), boxes.end(), sortScore);BoundBox boxMax;BoundBox boxCompare;while (boxes.size() != 0) {size_t index = 1;result.push_back(boxes[0]);while (boxes.size() > index) {boxMax.score = boxes[0].score;boxMax.classIndex = boxes[0].classIndex;boxMax.index = boxes[0].index;// translate point by maxLength * boxes[0].classIndex to// avoid bumping into two boxes of different classesboxMax.x = boxes[0].x + maxLength * boxes[0].classIndex;boxMax.y = boxes[0].y + maxLength * boxes[0].classIndex;boxMax.width = boxes[0].width;boxMax.height = boxes[0].height;boxCompare.score = boxes[index].score;boxCompare.classIndex = boxes[index].classIndex;boxCompare.index = boxes[index].index;// translate point by maxLength * boxes[0].classIndex to// avoid bumping into two boxes of different classesboxCompare.x = boxes[index].x + boxes[index].classIndex * maxLength;boxCompare.y = boxes[index].y + boxes[index].classIndex * maxLength;boxCompare.width = boxes[index].width;boxCompare.height = boxes[index].height;// the overlapping part of the two boxesfloat xLeft = max(boxMax.x, boxCompare.x);float yTop = max(boxMax.y, boxCompare.y);float xRight = min(boxMax.x + boxMax.width, boxCompare.x + boxCompare.width);float yBottom = min(boxMax.y + boxMax.height, boxCompare.y + boxCompare.height);float width = max(0.0f, xRight - xLeft);float hight = max(0.0f, yBottom - yTop);float area = width * hight;float iou =  area / (boxMax.width * boxMax.height + boxCompare.width * boxCompare.height - area);// filter boxes by NMS thresholdif (iou > NMSThreshold) {boxes.erase(boxes.begin() + index);continue;}++index;}boxes.erase(boxes.begin());}// opencv draw label paramsconst double fountScale = 0.5;const uint32_t lineSolid = 2;const uint32_t labelOffset = 11;const cv::Scalar fountColor(0, 0, 255);const vector <cv::Scalar> colors{cv::Scalar(237, 149, 100), cv::Scalar(0, 215, 255),cv::Scalar(50, 205, 50), cv::Scalar(139, 85, 26)};int half = 2;for (size_t i = 0; i < result.size(); ++i) {cv::Point leftUpPoint, rightBottomPoint;leftUpPoint.x = result[i].x - result[i].width / half;leftUpPoint.y = result[i].y - result[i].height / half;rightBottomPoint.x = result[i].x + result[i].width / half;rightBottomPoint.y = result[i].y + result[i].height / half;cv::rectangle(srcImage, leftUpPoint, rightBottomPoint, colors[i % colors.size()], lineSolid);string className = label[result[i].classIndex];string markString = to_string(result[i].score) + ":" + className;cv::putText(srcImage, markString, cv::Point(leftUpPoint.x, leftUpPoint.y + labelOffset),cv::FONT_HERSHEY_COMPLEX, fountScale, fountColor);}string savePath = "out_" + to_string(imageIndex) + ".jpg";cv::imwrite(savePath, srcImage);if (release){free(classBuff);classBuff = nullptr;}return SUCCESS;
}void SampleYOLOV7::ReleaseResource()
{model_.DestroyResource();imageProcess_.DestroyResource();aclResource_.Release();
}int main()
{const char* modelPath = "../model/yolov7x.om";const string imagePath = "../data";const int32_t modelWidth = 640;const int32_t modelHeight = 640;// all images in dirDIR *dir = opendir(imagePath.c_str());if (dir == nullptr){ACLLITE_LOG_ERROR("file folder does no exist, please create folder %s", imagePath.c_str());return FAILED;}vector<string> allPath;struct dirent *entry;while ((entry = readdir(dir)) != nullptr){if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0|| strcmp(entry->d_name, ".keep") == 0){continue;}else{string name = entry->d_name;string imgDir = imagePath +"/"+ name;allPath.push_back(imgDir);}}closedir(dir);if (allPath.size() == 0){ACLLITE_LOG_ERROR("the directory is empty, please download image to %s", imagePath.c_str());return FAILED;}// inferencestring fileName;bool release = false;SampleYOLOV7 sampleYOLO(modelPath, modelWidth, modelHeight);Result ret = sampleYOLO.InitResource();if (ret == FAILED) {ACLLITE_LOG_ERROR("InitResource failed, errorCode is %d", ret);return FAILED;}for (size_t i = 0; i < allPath.size(); i++){if (allPath.size() == i){release = true;}std::vector<InferenceOutput> inferOutputs;fileName = allPath.at(i).c_str();ret = sampleYOLO.ProcessInput(fileName);if (ret == FAILED) {ACLLITE_LOG_ERROR("ProcessInput image failed, errorCode is %d", ret);return FAILED;}ret = sampleYOLO.Inference(inferOutputs);if (ret == FAILED) {ACLLITE_LOG_ERROR("Inference failed, errorCode is %d", ret);return FAILED;}ret = sampleYOLO.GetResult(inferOutputs, fileName, i, release);if (ret == FAILED) {ACLLITE_LOG_ERROR("GetResult failed, errorCode is %d", ret);return FAILED;}}return SUCCESS;
}

这里我还加上了车牌识别的功能

img

2.3 Orange Pi AI Pro目标追踪与定位

目标追踪的思路如下:
将检测框按置信度分成两类,高分框与低分框。先用高分框与追踪轨迹进行第一次匹配。第二次匹配使用低分框与未匹配的轨迹进行匹配对于得分高于阈值但未匹配的目标框,为其新建追踪轨迹.追踪代码完全基于Bytetrack且是跑在CPU上,大家直接去官方整合即可,这里介绍下定位
在用OpenCV中的函数,通过4对对应的点的坐标计算两个图像之间单应矩阵H,然后调用射影变换函数,将一幅图像变换到另一幅图像的视角中。当时只是知道通过单应矩阵,能够将图像1中的像素坐标(u1,v1))变换到图像2中对应的位置上(u2,v2)。

单应(Homography)是射影几何中的概念,又称为射影变换。它把一个射影平面上的点(三维齐次矢量)映射到另一个射影平面上,并且把直线映射为直线,具有保线性质。总的来说,单应是关于三维齐次矢量的一种线性变换,可以用一个3x3的非奇异矩阵H表示这是一个齐次坐标的等式,

 x1=H * x2

在这里H是一个3×3的齐次矩阵,具有8个未知量。假设已经取得了两图像之间的单应,则可单应矩阵H可以将两幅图像关联起来。这有了很多实际的应用,例如图像的校正、对齐以及在SLAM中估计两个相机间的运动。此处我用作做为联合标定。首先我们将是地面平面假设为一个二维水平面,忽略其坡度。
即可得
地面平面上点p1(x1,y1),与图像上点p2(x2,y2)是一对匹配得点对,其单应性矩阵为H,则有

img

接下来我们求解这个矩阵
在真实的应用场景中,我们计算的点对中都会包含噪声。比如点的位置偏差几个像素,甚至出现特征点对误匹配的现象,如果只使用4个点对来计算单应矩阵,那会出现很大的误差。因此,为了使得计算更精确,一般都会使用远大于4个点对来计算单应矩阵。另外上述方程组采用直接线性解法通常很难得到最优解,所以实际使用中一般会用其他优化方法,如奇异值分解、Levenberg-Marquarat(LM)算法等进行求解。

cv::Mat oHomoMat_inv= cv::findHomography(m_vo2dPt, m_vo3dPt, 0, 0);

本工程里使用了四种方法,分别为直接解方程组,最小二乘法,ransac方法,基于PROSAC的鲁棒算法,具体解法可自行百度。标定之后的结果以及换算结果如图

img

3、多相机追踪

(a)融合单个杆件上相机与枪机的检测结果
首先需要将单个相机单元的结果进行初步筛选整合,虽然鱼眼的作用是对枪机进行补盲,但不能直接对两者的结果进行简单相加,因为可能会有由于处于鱼眼和枪机的重叠区域而被重复检测的目标,因此需要剔除可能存在的重复检测结果:

选择遍历枪机的检测结果,按照GPS的距离的每个目标的进行比,找出可能重复识别的目标, 之后将这些初步选出的枪机检测结果的GPS坐标使用相机的单应性矩阵映射到图像坐标系上,此时枪机的GPS坐标变为鱼眼图像上的一个像素点,再与检测框对比计算IOU,经过该轮比对,如IOU超过阈值,能够关联成功即可视为一个重复检测的目标,在这里删除重复检测在枪机下的结果,再将去除后的结果进行合并,即为一个相机单元的检测结果,包括每个目标的类型,在图像坐标的位置(可能是枪机或鱼眼),在GPS坐标的位置,速度,航向角等信息。
(b) 目标三级关联算法
在本步骤中,为了保证重合区域能够关联匹配,首次提出目标三级关联算法完成多杆件目标去重,以及目标跨杆件仍能被追踪。具体实施如下:根据步骤1-5得到各路相机单元的结构化数据,目标ID,目标速度,目标位置、目标航向角、目标车牌,目标时间戳等。
(1)首先分别接收多路相机单元数据,存在独立相机单元的缓冲区,单个相机单元的数据由1-5步骤生成,得到单个目标重要属性attrobj
其中id表示为目标单杆件唯一ID,lat, lon为目标的经纬度,heading为目标与正北方向夹角,len, width, height为目标的长宽高,timestamp为目标出现的时间戳,x,y表示在该相机下的像素坐标。同时该杆件相机数据由多个目标组成,且有个 发送时间戳TimeStamp与杆件名称deviceID,单个杆件数据组成为

(2)多相机追踪根据单杆件相机发送的数据perceptroni 中的目标时间戳timestamp的先后顺序初始化多杆件追踪目标列表tracker,即按照timestamp的顺序对perceptron集合进行排序,将最早出现的perceptron所有目标作为路口多杆件全息目标的集合,记为tracker,且赋予该目标一个全局ID。

全局ID是用来表示该目标在整个路口的唯一性,attri表示该目标的位置相关属性,deviceID则表示该目标由某一个杆件摄像机创建而来。
(3) a) 将接收到的其他杆件相机数据依次按照deviceID,从整个路口目标列表里查询当前目标ID上一帧由哪一个单相机列表维护,若查询到则依然由那个相机进行属性维护,即若新收到的perceptron数据中deviceID相同,则直接对比attr中的id是否相同,若相同则直接更新目标的位置,时间戳等信息; 使用单个相机ID预关联的方案,可以大大降低计算量,节省资源 b)若不同,则将该相机下percptroni的该目标的经纬度(lat,long)通过H矩阵的逆重投影到当前tracker维护的列表目标所在相机的图像坐标系中得到pixel(x,y)进行一一计算1-IOU。

c)关联的相机的图像坐标进行Dioumn = 1-IOU交并比关联,即将perceptroni中的目标属性atti(lat,lon)通过计算转换为单相机下的图像坐标x,y进行计算交并比,其中转换后的图像坐标宽高使用tracker关联目标的宽高。 d)若步骤仍关联不上, 则构建一个代价矩阵cost_matrix,使用距离关联,首先构建一个M x N的全为0的矩阵,其中M为tracker中目标的个数,N为上一步iou未关联上的单杆件perceptron目标个数。
距离计算方法为:

其中R为地球半径,(lat1,lon1) 为tracker目标经纬度, (lat2,lon2) 为未关联的单杆件目标经纬度。接下里根据距离构建代价矩阵cos_matrix

使用匈牙利匹配算法对关联矩阵进行匹配,完成所有目标的关联。
(4)将所有关联上的相机属性进行更新整个路口的目标追踪列表,即使用perceptron中的目标属性更新tracker目标中的属性,从而得到整个路口的目标数据tracker,为了进行下一帧关联准确度更高,保证空间一致性,这里对所有tracker中的经纬度根据当前速度进行预测,使用匀速直线运动模型对所有目标经纬度进行预测。
目标纬度预测:

目标经度预测:

其中arc为地球的平均半径,v为当前tracker目标速度,T为关联时间戳之差。

(4)整合路口目标列表,由于目标各个相机中目标视野不一致,所得到的位置有区别,考虑到相机和目标距离越远,产生误差的可能性越大,采用均值滤波对tracker中的目标位置数据进行处理不够稳健,由于距离目标过远的相机产生的误差会造成平均值的位置产生偏差,因此我们采取加权平均,首先获取到路口目标列表内每个目标的距离每个杆件单元的距离,直接根据目标经纬度以及杆件上的摄像机安装经纬度便可得到,假设目标距离四个杆件的距离分别为,则在加权平均时的权重分别为对距离进行归一化的结果,即

进而求出结合了四个杆件信息获得的最终坐标,形成完整路侧感知数据。

img

由于篇幅有限,后续我再将展开续更。。。。。。。。。。。。

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

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

相关文章

OpenMV的VisionBoard视觉识别开发板学习记录

此篇博客仅用于对VisionBoard的开发板的学习研究记录&#xff0c;没有教学内容。 一、资料来源 开发板资料链接 开发板环境搭建手册 开发板视频教程 板子的资料网站 openmv官方的网站 目录 一、资料来源二、针对 VisionBoard的目标识别和定位总结1. 目标识别功能1.1 物体检测…

芯片原厂驱动开发工程师:初学到精通,如何快速成长?

01 前言 大家好&#xff0c;我是XX&#xff0c;来自湖南XX学院&#xff0c;电子信息18级&#xff0c;也曾在创新基地控制组学习过两三年&#xff0c;毕业后就职于一家芯片原厂的解决方案部&#xff0c;担任驱动工程师的职位&#xff0c;算上实习期&#xff0c;我的工作时长已有…

htb-Mailing

因为做windows服务器渗透较少&#xff0c;不妥的地方还请师傅们指出 可先看思路&#xff0c;实在不行再看writeup 任意文件下载拿pop3登录邮箱——》利用邮件服务器漏洞拿下NTLM——》利用组件版本漏洞拿下 拿shell 端口扫描开放服务 Host is up (0.91s latency). Not shown:…

CSS学习笔记:rem实现移动端适配的原理——媒体查询

移动端适配 移动端即手机端&#xff0c;也称M端 移动端适配&#xff1a;同一套移动端页面在不同屏幕尺寸的手机上可以实现宽度和高度的自适应&#xff0c;也就是页面中元素的宽度和高度可以根据屏幕尺寸的变化等比缩放 rem配合媒体查询可实现移动端适配 rem单位 媒体查询 …

SpringAdminClient如何将Httpbasic账号密码告知SpringAdminServer

场景&#xff0c;因为Config Service开了权限校验&#xff0c;注册到eureka之后&#xff0c;SpringAdmin查看信息会报错401&#xff0c;如果想在SpringAdmin中正确的看到Config Service的actuator信息则需要将账号密码告知给SpringAdmin&#xff0c;磁力用的是Eureka作为发现服…

javaIO流知识点概况

一、前言&#xff1a; 1.1.流的概念: java将输入与输出比喻为"流"&#xff0c;英文:Stream. 就像生活中的"电流","水流"一样,它是以同一个方向顺序移动的过程.只不过这里流动的是字节(2进制数据).所以在IO中有输入流和输出流之分,我们理解他们…

单点11.2.0.3备份恢复到单点11.2.0.4

保命法则&#xff1a;先备份再操作&#xff0c;磁盘空间紧张无法备份就让满足&#xff0c;给自己留退路。 场景说明&#xff1a; 1.本文档的环境为同平台、不同版本&#xff08;操作系统版本可以不同&#xff0c;数据库小版本不同&#xff09;&#xff0c;源机器和目标机器部…

swiftui基础组件Image加载图片,以及记载gif动图示例

想要在swiftui中展示图片&#xff0c;可以使用Image这个组件&#xff0c;这个组件可以加载本地图片和网络图片&#xff0c;也可以调整图片大小等设置。先大概看一下Image的方法有哪些可以用。 常用的Image属性 1.调整图像尺寸&#xff1a; 使用 resizable() 方法使图像可调整…

量子密钥分发系统基础器件(一):光纤干涉仪

干涉仪的基本原理是利用波的叠加来获得波的相位信息&#xff0c;从而获取实验中所关心的物理量。光纤干涉仪是由光学干涉仪发展而来的&#xff0c;利用光纤实现光的干涉&#xff0c;由于光纤取代透镜系统构成的光路具有柔软、形状可随意变化、传输距离远等特点&#xff0c;当前…

【Linux】23. 线程封装

如何理解C11中的多线程(了解) #include <iostream> #include <unistd.h> #include <thread>void thread_run() {while (true){std::cout << "我是新线程..." << std::endl;sleep(1);} } int main() {// 任何语言需要在Linux上实现多线…

解决IDEA菜单栏找不到VCS的问题,且使用IDEA推送新项目到托管仓库

问题描述&#xff1a; 在idea软件中使用git推送项目&#xff0c;idea页面顶部菜单栏无VCS 解决方案&#xff1a; 一&#xff1a;File->Settings->Version Control-> 点击 ->选择项目->VCS:->点击ok&#xff1a; 二&#xff1a;托管平台创建一个Git仓库来保…

Mysql 8.0 主从复制及读写分离搭建记录

前言 搭建参考&#xff1a;搭建Mysql主从复制 为什么要做主从复制&#xff1f; 做数据的热备&#xff0c;作为后备数据库&#xff0c;主数据库服务器故障后&#xff0c;可切换到从数据库继续工作&#xff0c;避免数据丢失。架构的扩展。业务量越来越大&#xff0c;I/O访问频…

6月来得及!考研数学120分复习规划:660/880/1000/1800怎么刷?

首先&#xff0c;120分是个什么概念&#xff1f; 如果目标120&#xff0c;历年真题就要135以上。这是因为&#xff1a; 1. 习题册里都是历年真题改编&#xff0c;很多题型见过了&#xff1b; 2. 考场发挥有不确定因素&#xff0c;所以需要安全边界。 总体规划 那么&#xff…

[java基础揉碎]文件IO流

目录 文件 什么是文件 文件流​编辑 常用的文件操作 创建文件方式一 创建文件方式二 创建文件方式三 tip:为什么new file 了还有执行createNewFile?new File的时候其实是在内存中创建了文件对象, 还没有在磁盘中, 当执行createNewFile的时候才是往磁盘中写入​编辑 …

WWW24因果论文(1/8) | 利用强化学习(智能体)进行因果问答

【摘要】因果问题询问不同事件或现象之间的因果关系。它们对于各种用例都很重要&#xff0c;包括虚拟助手和搜索引擎。然而&#xff0c;许多当前的因果问答方法无法为其答案提供解释或证据。因此&#xff0c;在本文中&#xff0c;我们旨在使用因果关系图来回答因果问题&#xf…

【Flutter】显式动画

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Flutter学习 &#x1f320; 首发时间&#xff1a;2024年5月29日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e; 目…

微服务项目搭建之技术选型

1、什么是微服务 Java微服务是一种架构风格&#xff0c;通过将单个Spring Boot应用程序拆分为一组小型、独立的Spring Boot服务来构建分布式系统。每个微服务都运行在自己的进程中&#xff0c;并使用轻量级通信机制&#xff08;如HTTP或消息队列&#xff09;来进行相互之间的通…

【C++】从零开始构建红黑树 —— 节点设计,插入函数的处理 ,旋转的设计

送给大家一句话&#xff1a; 日子没劲&#xff0c;就过得特别慢&#xff0c;但凡有那么一点劲&#xff0c;就哗哗的跟瀑布似的拦不住。 – 巫哲 《撒野》 &#x1f30b;&#x1f30b;&#x1f30b;&#x1f30b;&#x1f30b;&#x1f30b;&#x1f30b;&#x1f30b; ⛰️⛰️…

在豆包这事上,字节看得很明白

大数据产业创新服务媒体 ——聚焦数据 改变商业 导语&#xff1a; 1.基于豆包的话炉/猫箱APP市场反响一般 2.价格战对于豆包来说是副产物 3.价格战对大模型市场是良性的 4.豆包接下来会推广至国际社会 因为宣称价格比行业便宜99.3%&#xff0c;豆包成功出圈了。根据火山引擎公…

笔试强训week6

day1 Q1 难度⭐⭐ 小红的口罩_牛客小白月赛41 (nowcoder.com) 题目&#xff1a; 疫情来了&#xff0c;小红网购了 n 个口罩。 众所周知&#xff0c;戴口罩是很不舒服的。小红每个口罩戴一天的初始不舒适度为 ai​。 小红有时候会将口罩重复使用&#xff08;注&#xff1a;…