yolov8 tracking编码为web 和 rtsp流输出

1 基础工作

打开cmd
输入 conda env list
输入 conda activate py38
查看 nvidia-smi
查看 nvcc,如下图所示 cuda为11.7 ,为确认可以查看program files 下面的cuda 安装,看到11.7 就行了,读者可以自行确认自己的版本。
在这里插入图片描述
查看nvidia-smi
在这里插入图片描述
打开yolov8 track以后,发现速度超级慢, 打开cpu占用率奇高,gpu为零, 打开cmd
import torch
torch.cuda.is_available()
为false
确认pytorch安装的为cpu版本,重新安装pytorch cuda 版本,去pytorch网站,点开后复制安装命令,把cuda版本改成自己本机的版本。

在这里插入图片描述
输入命令
python yolo\v8\detect\detect_and_trk.py model=yolov8s.pt source=“d:\test.mp4” show=True
在这里插入图片描述
gpu占用率上升到40% 左右。
在这里插入图片描述

2 输出到web

接下来我们要做的工作为rtsp server 编码上传, 为了让其他机器得到结果,我们必须编程并且得到图像结果,让后使用实时传输协议直接转成rtp 流,让本机成为rtsp server,使用vlc 等工具,可以直接拉取到编码后的流。
修改代码,上传结果,先把命令修改成为
python yolo\v8\detect\detect_and_trk.py model=yolov8s.pt source=“d:\test.mp4”
然后在代码里面自己用opencv 来show,也就是增加两行代码

        cv2.imshow("qbshow",im0)cv2.waitKey(3)

没问题show 出来了,也就是im0 是我们在增加了选框的地方,在show 代码的基础上把图片发送出去就行,我们选择使用websocket 发送,或者socket 直接发送都行,这样我们需要一个客户端还是服务端的选择,我们选择让python成为服务端,目的是为了不让python需要断线重连,python 成为服务端有很多好处,
1 是可以直接给web传送图片
2 是可以直接给

    def write_results(self, idx, preds, batch):p, im, im0 = batchlog_string = ""if len(im.shape) == 3:im = im[None]  # expand for batch dimself.seen += 1im0 = im0.copy()if self.webcam:  # batch_size >= 1log_string += f'{idx}: 'frame = self.dataset.countelse:frame = getattr(self.dataset, 'frame', 0)# trackerself.data_path = psave_path = str(self.save_dir / p.name)  # im.jpgself.txt_path = str(self.save_dir / 'labels' / p.stem) + ('' if self.dataset.mode == 'image' else f'_{frame}')log_string += '%gx%g ' % im.shape[2:]  # print stringself.annotator = self.get_annotator(im0)det = preds[idx]self.all_outputs.append(det)if len(det) == 0:return log_stringfor c in det[:, 5].unique():n = (det[:, 5] == c).sum()  # detections per classlog_string += f"{n} {self.model.names[int(c)]}{'s' * (n > 1)}, "# #..................USE TRACK FUNCTION....................dets_to_sort = np.empty((0,6))for x1,y1,x2,y2,conf,detclass in det.cpu().detach().numpy():dets_to_sort = np.vstack((dets_to_sort, np.array([x1, y1, x2, y2, conf, detclass])))tracked_dets = tracker.update(dets_to_sort)tracks =tracker.getTrackers()for track in tracks:[cv2.line(im0, (int(track.centroidarr[i][0]),int(track.centroidarr[i][1])), (int(track.centroidarr[i+1][0]),int(track.centroidarr[i+1][1])),rand_color_list[track.id], thickness=3) for i,_ in  enumerate(track.centroidarr) if i < len(track.centroidarr)-1 ] if len(tracked_dets)>0:bbox_xyxy = tracked_dets[:,:4]identities = tracked_dets[:, 8]categories = tracked_dets[:, 4]draw_boxes(im0, bbox_xyxy, identities, categories, self.model.names)gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwhcv2.imshow("qbshow",im0)cv2.waitKey(3)return log_string

2.1 web中显示

在python中加上websocket server的代码,以下是一个示例代码,读者可以自己测试,但是要应用到python 的图像处理server中,我们要做一些修改

import asyncio
import threading
import websockets
import time
CONNECTIONS = set()async def server_recv(websocket):while True:try:recv_text = await websocket.recv()print("recv:", recv_text)except websockets.ConnectionClosed as e:# 客户端关闭连接,跳出对客户端的读取,结束函数print(e.code)await asyncio.sleep(0.01)breakasync def server_hands(websocket):CONNECTIONS.add(websocket)print(CONNECTIONS)try:await websocket.wait_closed()finally:CONNECTIONS.remove(websocket) def message_all(message):websockets.broadcast(CONNECTIONS, message)   async def handler(websocket, path):# 处理新的 WebSocket 连接print("New WebSocket route is ",path)try:await server_hands(websocket) # 握手加入队列await server_recv(websocket)  # 接收客户端消息并处理except websockets.exceptions.ConnectionClosedError as e:print(f"Connection closed unexpectedly: {e}")finally:pass# 处理完毕,关闭 WebSocket 连接print("WebSocket connection closed")async def sockrun():async with websockets.serve(handler, "", 9090):await asyncio.Future()  # run foreverdef main_thread(): print("main")asyncio.run(sockrun())

在这里插入图片描述

2.2 修改

修改的地方为我们不能让websocket 阻塞主线程,虽然websocket为协程处理,但是依然要放到线程里面

def predict(cfg):init_tracker()random_color_list()cfg.model = cfg.model or "yolov8n.pt"cfg.imgsz = check_imgsz(cfg.imgsz, min_dim=2)  # check image sizecfg.source = cfg.source if cfg.source is not None else ROOT / "assets"predictor = DetectionPredictor(cfg)predictor()if __name__ == "__main__":thread = threading.Thread(target=main_thread)thread.start()predict()

值得注意的地方是:
很多人喜欢把编码做成base64 ,这样没有必要, 服务程序里面把二进制编码成base64, 消耗了cpu, 然后发送还大了很多,实际上我们直接发送二进制就行了,发送时

   cv2.waitKey(3)_, encimg = cv2.imencode('.jpg', im0)bys = np.array(encimg).tobytes()message_all(bys)

web端测试代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>websocket</title></head>
<body><div><button onclick="connecteClient()">开始接收</button></div><br><div><img src="" id="python_img" alt="websock" style="text-align:left; width: 640px; height: 360px;"> </div><script>function connecteClient() {var ws = new WebSocket("ws://127.0.0.1:9090");ws.onopen = function () {console.log("WebSocket 连接成功");};ws.onmessage = function (evt) {var received_msg = evt.data;blobToDataURI(received_msg, function (result) {document.getElementById("python_img").src = result;})};ws.onclose = function () {console.log("连接关闭...");};}function blobToDataURI(blob, callback) {var reader = new FileReader();reader.readAsDataURL(blob);reader.onload = function (e) {callback(e.target.result);}}</script>
</body>
</html>

其中接收到二进制完成以后直接显示,不用服务端编码成base64,下图表明web端可以正常拿到jpg图片显示

在这里插入图片描述

其中message_all 是广播,只要是websocket client 我们就给他发一份,这样做,不但可以发送给web,也可以发送给rtsp server,我们让rtsp server 链接上来,取到jpg后,解码成为rgb24,然后编码成为h264,让vlc 可以链接rtsp server取到rtsp 流

3 rtsp server 编码h264 输出

我们的rtsp server 端使用c++ 编写,为了加快速度,使用了内存共享,而没有使用websocket client,当然是可以的,考虑到这里要解码,又要编码输出,还有可能需要使用硬件编码,为了提高效率,就这么做了,而且还简单,缺点就是这样多了一个问题,rtspserve只能启动在本机上。先编写一个h264Frame, h265 是一样的道理,后面再更改,暂时运行在windows上,等完成了再修改。注意以下代码只能运行在windows上

class H264Frame :public TThreadRunable
{const wchar_t*  sharedMemoryMutex = L"shared_memory_mutex";const wchar_t*  sharedMemoryName = L"shared_memory";LPVOID v_lpBase = NULL;HANDLE v_hMapFile = NULL;HANDLE 	m_shareMutex = NULL;std::shared_ptr<xop::RtspServer> v_server;std::string v_livename;std::wstring v_pathname;std::wstring v_pathmutex_name;int v_fps = 10;Encoder v_encoder;xop::MediaSessionId v_id;int v_init = 0;int v_quality = 28;
public:H264Frame(std::shared_ptr<xop::RtspServer> s, const char* livename, const wchar_t* pathname, xop::MediaSessionId session_id){v_server = s;v_livename = livename;v_pathname = pathname;if (pathname != NULL){v_pathmutex_name = pathname;v_pathmutex_name += L"_mutex";}v_id = session_id;}~H264Frame() {}bool Open(){if (v_pathname.empty())v_hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, NULL, sharedMemoryName);elsev_hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, NULL, v_pathname.c_str());if (v_hMapFile == NULL){//printf(" Waiting shared memory creation......\n");return false;}return true;}void Close(){if (m_shareMutex != NULL)ReleaseMutex(m_shareMutex);if (v_hMapFile != NULL)CloseHandle(v_hMapFile);}bool IsOpened() const{return (v_hMapFile != NULL);}void sendFrame(uint8_t* data ,int size, int sessionid){xop::AVFrame videoFrame = { 0 };videoFrame.type = 0;videoFrame.size = size;// sizeofdata;// frame_size;videoFrame.timestamp = xop::H264Source::GetTimestamp();//videoFrame.notcopy = data;videoFrame.buffer.reset(new uint8_t[videoFrame.size]);std::memcpy(videoFrame.buffer.get(), data, videoFrame.size);v_server->PushFrame(sessionid, xop::channel_0, videoFrame);}int ReadFrame(int sessionid){if (v_hMapFile){v_lpBase = MapViewOfFile(v_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);unsigned char* pMemory = (unsigned char*)v_lpBase;int w = 0, h = 0;int frame_size = 0;std::memcpy(&w, pMemory, 4);std::memcpy(&h, pMemory + 4, 4);std::memcpy(&frame_size, pMemory + 8, 4);//printf("read the width %d height %d framesize %d\n", imageWidth,imageHeight, frame_size);uint8_t* rgb = pMemory + 12;if (v_init == 0){v_encoder.Encoder_Open(v_fps, w, h, w, h, v_quality);v_init = 1;}v_encoder.RGB2YUV(rgb, w, h);AVPacket * pkt = v_encoder.EncodeVideo();//while (!*framebuf++);if (pkt!=NULL) {uint8_t* framebuf = pkt->data;frame_size = pkt->size;uint8_t* spsStart = NULL;int spsLen = 0;uint8_t* ppsStart = NULL;int ppsLen = 0;uint8_t* seStart = NULL;int seLen = 0;uint8_t* frameStart = 0;//非关键帧地址或者关键帧地址int frameLen = 0;AnalyseNalu_no0x((const uint8_t*)framebuf, frame_size, &spsStart, spsLen, &ppsStart, ppsLen, &seStart, seLen, &frameStart, frameLen);if (spsStart != NULL && ppsStart!=NULL){sendFrame(spsStart, spsLen, sessionid);sendFrame(ppsStart, ppsLen, sessionid);}if (frameStart != NULL){sendFrame(frameStart, frameLen, sessionid);}av_packet_free(&pkt);}UnmapViewOfFile(pMemory);}return -1;}void Run(){m_shareMutex = CreateMutexW(NULL, false, sharedMemoryMutex/*v_pathmutex_name.c_str()*/);		v_encoder.Encoder_Open(10, 4096, 1080, 4096, 1080, 27);while (1){if (Open() == true){break;}else{printf("can not open share mem error\n");Sleep(3000);}}printf("wait ok\n");//检查是否改变参数//重新开始int64_t m_start_clock = 0;float delay = 1000000.0f / (float)(v_fps);//微妙//合并的rgbuint8_t * rgb = NULL;uint8_t * cam = NULL;int64_t start_timestamp = av_gettime_relative();//  GetTimestamp32();while (1){if (IsStop())break;//获取一帧//rgb = if (v_hMapFile){//printf("start to lock sharemutex\n");WaitForSingleObject(m_shareMutex, INFINITE);//printf("read frame\n");ReadFrame(v_id);ReleaseMutex(m_shareMutex);}else{printf("Shared memory handle error\n");break;}int64_t tnow = av_gettime_relative();// GetTimestamp32();int64_t total = tnow - start_timestamp; //總共花費的時間int64_t fix_consume = ++m_start_clock * delay;if (total < fix_consume) {int64_t diff = fix_consume - total;if (diff > 0) { //相差5000微妙以上std::this_thread::sleep_for(std::chrono::microseconds(diff));}}}if (v_init == 0){v_encoder.Encoder_Close();v_init = 1;}}};int main(int argc, char **argv)
{	std::string suffix = "live";std::string ip = "127.0.0.1";std::string port = "8554";std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;std::shared_ptr<xop::EventLoop> event_loop(new xop::EventLoop());std::shared_ptr<xop::RtspServer> server = xop::RtspServer::Create(event_loop.get());if (!server->Start("0.0.0.0", atoi(port.c_str()))) {printf("RTSP Server listen on %s failed.\n", port.c_str());return 0;}#ifdef AUTH_CONFIGserver->SetAuthConfig("-_-", "admin", "12345");
#endifxop::MediaSession *session = xop::MediaSession::CreateNew("live"); session->AddSource(xop::channel_0, xop::H264Source::CreateNew()); //session->StartMulticast(); session->AddNotifyConnectedCallback([] (xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port){printf("RTSP client connect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);});session->AddNotifyDisconnectedCallback([](xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port) {printf("RTSP client disconnect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);});xop::MediaSessionId session_id = server->AddSession(session);H264Frame h264frame(server, suffix.c_str(), L"shared_memory",session_id);//std::thread t1(SendFrameThread, server.get(), session_id, &h264_file);//t1.detach(); std::cout << "Play URL: " << rtsp_url << std::endl;h264frame.Start();while (1) {xop::Timer::Sleep(100);}h264frame.Join();getchar();return 0;
}

完成以后,打开python 服务端,打开rtsp服务端,最后打开vlc查看
在这里插入图片描述
这样就完成了python端使用pytorch ,yolo 等等共享给c++ 的内存

其中python端的内存共享示例使用如下

import mmap
import contextlib
import timewhile True:with contextlib.closing(mmap.mmap(-1, 25, tagname='test', access=mmap.ACCESS_READ)) as m:s = m.read(1024)#.replace('\x00', '')print(s)time.sleep(1)

读者可自行完成剩余的代码

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

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

相关文章

【基础】【Python网络爬虫】【2.请求与响应】常用请求报头和常用响应方法

Python网络爬虫基础 爬虫基础请求与相应HTTP/HTTPS 协议HTTP/HTTPS的优缺点HTTP 的缺点HTTPS的优点 请求与响应概述请求请求目标&#xff08;url&#xff09;请求体&#xff08;response&#xff09;常用的请求报头查看请求体&#xff08;requests 模块&#xff09; 响应HTTP响…

PS实现圆角矩形选取

在我们日常的工作当中,经常需要做圆角矩形的图片,因为圆角的图片给人的感觉比较圆润,漂亮,但是PS在这方面显然比较弱智,因此如何做圆角矩形选择,这里给出了两个方法,希望能帮到大家。 进入正题(方法一): 第一步-PS 右上角-打开一张图片 第二步-左列-选择矩形-选择目…

2024新年快乐

今天就不讲题解了&#xff0c;2024年&#xff0c;祝所有博客身体健康&#xff0c;粉丝越多&#xff0c;点赞越高&#xff01;&#xff01;&#xff01; #include<bits/stdc.h> using namespace std; int main(){cout<<"新年快乐!!";return 0&#xff1b;…

【小沐学Python】Python实现免费天气预报获取(OpenWeatherMap)

文章目录 1、简介1.1 工具简介1.2 费用1.3 注册1.4 申请key 2、接口说明2.1 One Call 3.02.2 Current Weather and Forecasts collection2.2.1 API 调用2.2.2 API 参数 2.3 Historical Weather collection2.4 Weather Maps collection2.5 Other weather APIs 3、接口测试3.1 例…

JavaFX:MVC模式学习01-使用PropertyValueFactory将模型与视图绑定

PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下&#xff1a; TableColumn<Person,String> firstNameCol new TableColumn<Person,String>("First Name");firstNameCol.setCellValueFactory(new PropertyVal…

IIS服务器发布PHP网站

IIS服务器&#xff0c;相信开发者都不会陌生&#xff0c;它的英文全称是Internet Information Services&#xff0c;是由微软公司提供的基于运行Microsoft Windows的互联网基本服务&#xff0c;常用于Windows系统的Web项目部署&#xff0c;本篇以PHP项目为例&#xff0c;讲解如…

R_handbook_作图专题

ggplot基本作图 1 条形图 library(ggplot2) ggplot(biopics) geom_histogram(aes(x year_release),binwidth1,fill"gray") 2 堆砌柱状图 ggplot(biopics, aes(xyear_release)) geom_bar(aes(fillsubject_sex)) 3 堆砌比例柱状图 ggplot(biopics, aes(xyear_rele…

idea 出现Cannot resolve symbol ‘springframework‘解决方法

Maven手动重新加载 1&#xff09;File–>Invalidate Caches / Restart… 清理缓存&#xff0c;重启idea客户端 2&#xff09;File–>Maven–>Reload project重新从maven中加载工程依赖的组件

51单片机项目(24)——基于51单片机的温控风扇protues仿真

1.功能设计 使用传感器测量温度&#xff0c;并将温度显示在LCD1602上。如果温度超过阈值&#xff0c;那么就打开风扇&#xff0c;否则风扇不打开。&#xff08;仿真的时候&#xff0c;用直流电机模拟风扇&#xff09;。 仿真截图如下&#xff1a; 此时温度是27度&#xff0c;我…

FA组件详解

1、了解FA核心组件以及功能 &#xff08;1&#xff09;TC&#xff08;Thin Client&#xff1a;瘦终端&#xff09;&#xff1a;就是类似于机顶盒的一个小盒子&#xff0c;里面有CPU、内存、USB、MIC、HDMI等接口&#xff0c;可以理解为小型电脑&#xff0c;但是它里面是没有操作…

python使用openpyxl操作excel

文章目录 前提读取已有excel创建一个excel工作簿对象创建excel工作簿中的工作表获取工作表第一种&#xff1a;.active 方法第二种&#xff1a;通过工作表名获取指定工作表​​​​​​第三种&#xff1a;.get_sheet_name() 修改工作表的名称数据操作写入数据按单元格写入通过指…

深信服AF防火墙配置SSL VPN

防火墙版本&#xff1a;8.0.85 需提前确认防火墙是是否有SSL VPN的授权&#xff0c;确认授权用户数量 1、确认内外网接口划分 2、网络→SSL VPN&#xff0c;选择内外网接口地址 3、SSL VPN→用户管理→新增一个SSL VPN的用户 4、新增L3VPN资源&#xff0c;类型选择Other&…

【基础】【Python网络爬虫】【1.认识爬虫】什么是爬虫,爬虫分类,爬虫可以做什么

Python网络爬虫基础 认识爬虫1.什么是爬虫2.爬虫可以做什么3.为什么用 Ptyhon 爬虫4.爬虫的分类通用爬虫聚焦爬虫功能爬虫增量式爬虫分布式爬虫 5.爬虫的矛与盾&#xff08;重点&#xff09;6.盗亦有道的君子协议robots7.爬虫合法性探究 认识爬虫 1.什么是爬虫 网络爬虫&…

第5课 使用openCV捕获摄像头并实现预览功能

这节课我们开始利用ffmpeg和opencv来实现一个rtmp推流端。推流端的最基本功能其实就两个:预览画面并将画面和声音合并后推送到rtmp服务器。 一、FFmpeg API 推流的一般过程 1.引入ffmpeg库&#xff1a;在代码中引入ffmpeg库&#xff0c;以便使用其提供的功能。 2.捕获摄像头…

MongoDB的基本使用

MongoDB的引出 使用Redis技术可以有效的提高数据访问速度&#xff0c;但是由于Redis的数据格式单一性&#xff0c;无法操作结构化数据&#xff0c;当操作对象型的数据时&#xff0c;Redis就显得捉襟见肘。在保障访问速度的情况下&#xff0c;如果想操作结构化数据&#xff0c;…

Spark中的数据加载与保存

Apache Spark是一个强大的分布式计算框架&#xff0c;用于处理大规模数据。在Spark中&#xff0c;数据加载与保存是数据处理流程的关键步骤之一。本文将深入探讨Spark中数据加载与保存的基本概念和常见操作&#xff0c;包括加载不同数据源、保存数据到不同格式以及性能优化等方…

20231231_小米音箱接入GPT

参考资料&#xff1a; GitHub - yihong0618/xiaogpt: Play ChatGPT and other LLM with Xiaomi AI Speaker *.设置运行脚本权限 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned *.配置小米音箱 ()pip install miservice_fork -i https://pypi.tuna.tsinghua.edu.cn/sim…

算法逆袭之路(1)

11.29 开始跟进算法题进度! 每天刷4题左右 ,一周之内一定要是统一类型 而且一定稍作总结, 了解他们的内在思路究竟是怎样的!! 12.24 一定要每天早中晚都要复习一下 早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义 12.26/27&#xff1a; 斐波那契数 爬…

机器学习:贝叶斯估计在新闻分类任务中的应用

文章摘要 随着互联网的普及和发展&#xff0c;大量的新闻信息涌入我们的生活。然而&#xff0c;这些新闻信息的质量参差不齐&#xff0c;有些甚至包含虚假或误导性的内容。因此&#xff0c;对新闻进行有效的分类和筛选&#xff0c;以便用户能够快速获取真实、有价值的信息&…

【完整思路】2023 年中国高校大数据挑战赛 赛题 B DNA 存储中的序列聚类与比对

2023 年中国高校大数据挑战赛 赛题 B DNA 存储中的序列聚类与比对 任务 1.错误率和拷贝数分析&#xff1a;分析“train_reads.txt”和“train_reference.txt”数据集中的错误率&#xff08;插入、删除、替换、链断裂&#xff09;和序列拷贝数。 2.聚类模型开发&#xff1a;开发…