1传输的数据
1-1数据格式说明
1 两路视频图像Mat
图像 图像数据(Mat)+图像头信息(ImgInf)
//图像的宽、高、类型信息 typedef struct { int width; //4个字节 int height; int type; }ImgInf;
2 单个TrackBox
(假设单个目标检测框)
typedef struct { int x; int y; int width; int height; int flag; }TrackBox; //20个字节
3 每路视频得 vector<TrackBox> VTrackBox; (所有目标检测框集合)
1-2数据分配位置
//--------------------------------共享内存大小确定-------------------------------------- //1-1为BOX分配的空间 #define BOX_SIZE sizeof(TrackBox) // TrackBox结构体大小 //1-2为BOX数组分配 #define MAT_BOXVEC_NUMBER 2 //几路视频就有多少对应的检测数组 #define MAT_BOX_NUMBER 100 // 一个容器里假设最大有100个TrackBox(20个字节) 2000个字节 #define MAT_BOX_VECTOR MAT_BOX_NUMBER*BOX_SIZE //1-3为图片分配的空间 #define FRAME_NUMBER 2 // 图像输入路数 #define FRAME_W_H 1920*1080 // 图像分辨率 #define FRAME_SIZE FRAME_W_H*sizeof(unsigned char)*3+sizeof(ImgInf) // 图像彩色图(三通道)+ 图像信息结构体 //--------------------------------共享内存位置分配-------------------------------------- //各路图像所在共享内存位置 #define MAT_DATA1 FRAME_SIZE*0 //存MAT_DATA1 pBuf+FRAME_SIZE*1 - pBuf+FRAME_SIZE*1+sizeof(Mat) #define MAT_DATA2 FRAME_SIZE*1 //存MAT_DATA1 pBuf+FRAME_SIZE*2 - pBuf+FRAME_SIZE*1+sizeof(Mat) #define MAT_DATA1_BOX FRAME_SIZE*2 #define MAT_DATA2_BOX FRAME_SIZE*2+MAT_BOX_VECTOR //BOX_DATA所在共享内存位置 #define BOX_DATA FRAME_SIZE*FRAME_NUMBER + MAT_BOX_VECTOR*MAT_BOXVEC_NUMBER //数据存储的起始位置 存BOX_DATA pBuf+FRAME_SIZE*0 - pBuf+FRAME_SIZE*0+sizeof(TrackBox) //总空间大小 #define MEMORY_SIZE FRAME_SIZE*FRAME_NUMBER+MAT_BOX_VECTOR*MAT_BOXVEC_NUMBER+BOX_SIZE
缺陷,没有加入标志位,用来同步两个节点的存取
2工程文件
2-1发送端
main.cpp
#pragma once #ifndef MAIN #define MAIN /* 1包含文件 */ //1.1 系统 必选 #include<iostream> #include<Windows.h> #include "../Include/ShareMemray.h" //1.2 opencv 可选 #include <opencv2/opencv.hpp> using namespace cv; using namespace std; TrackBox BOX1; vector<TrackBox> VTrackBox1; /* 4 测试 鼠标点击输出 x y 存入共享内存 */ //4.1 鼠标事件 void onMouse(int event, int x, int y, int flags, void* param) { //cout << "flag =" << flag << endl; Mat *im = reinterpret_cast<Mat*>(param); switch (event) { case CV_EVENT_LBUTTONDOWN: //鼠标左键按下响应:返回坐标和灰度 BOX1.x = x; BOX1.y = y; BOX1.flag = flags; break; } } // 4.2 读取视频 int imge_test(SHAREDMEMORY sharesend) { VideoCapture capture(0); if (!capture.isOpened()) { return -1; } Mat frame; capture.set(CV_CAP_PROP_FRAME_WIDTH, 1920); capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1080); bool stop = false; while (1) { //flag = 0; capture >> frame; cvNamedWindow("当前视频", 0); resize(frame, frame, Size(1920, 1080)); //Sleep(10); cvSetMouseCallback("当前视频", onMouse, &frame); imshow("当前视频", frame); waitKey(1); if (BOX1.flag == 1) { // 1发送单个BOX1 sharesend.SendBox(BOX1); cout << "at(" << BOX1.x << "," << BOX1.y << ")" << "flag =" << BOX1.flag <<" h "<< BOX1.height<< " w "<< BOX1.width << endl; // 2发送多个BOX(容器) VTrackBox1.clear(); // 不能加resize 否则不出图 for (int i = 0; i <MAT_BOX_NUMBER; i++) { BOX1.width = i; BOX1.height = i; VTrackBox1.push_back(BOX1); } sharesend.SendVectorBox(VTrackBox1); BOX1.flag = 0; } // 3发送图片 sharesend.SendMat(frame,MAT_DATA1); } } int main() { //共享内存初始化 SHAREDMEMORY sharesend; sharesend.intShareroom(); //共享内存发送信息 imge_test(sharesend); //共享内存释放 sharesend.stop(); return 0; } #endif
2-2接收端
#include <windows.h> #include<iostream> #include "../Include/ShareMemray.h" using namespace std; TrackBox recBOX; void main() { SHAREDMEMORY sharerec; sharerec.intShareroom(); while (true) { //1 接收单个box sharerec.RecBox(recBOX); if (recBOX.flag != 0) // 标志位判断数据是否有效 { //2 接受多个box(容器) vector<TrackBox> VTrackBoxrec; // 必须resize 否则没有空间无法储存 VTrackBoxrec.resize(MAT_BOX_NUMBER); sharerec.RecieveVectorBox(VTrackBoxrec); for (auto &i : VTrackBoxrec) { cout << "x " << i.x << " y " << i.y << " h " << i.height << " w " << i.width << endl; } } Mat frame=sharerec.RecieveMat(MAT_DATA1); if (!frame.empty()) { namedWindow("show", 0); imshow("show", frame); waitKey(1); } } sharerec.stop(); }
2-2接收端
#include <windows.h> #include<iostream> #include "../Include/ShareMemray.h" using namespace std; TrackBox recBOX; void main() { SHAREDMEMORY sharerec; sharerec.intShareroom(); while (true) { //1 接收单个box sharerec.RecBox(recBOX); if (recBOX.flag != 0) // 标志位判断数据是否有效 { //2 接受多个box(容器) vector<TrackBox> VTrackBoxrec; // 必须resize 否则没有空间无法储存 VTrackBoxrec.resize(MAT_BOX_NUMBER); sharerec.RecieveVectorBox(VTrackBoxrec); for (auto &i : VTrackBoxrec) { cout << "x " << i.x << " y " << i.y << " h " << i.height << " w " << i.width << endl; } } Mat frame=sharerec.RecieveMat(MAT_DATA1); if (!frame.empty()) { namedWindow("show", 0); imshow("show", frame); waitKey(1); } } sharerec.stop(); }
2-3 共享内存文件
使用过程
配置过程
0-0工程包含这个两个文件
0-1给共享内存取个名字
0-2根据发送的数据,开辟总空间大小,分配各个数据在总空间得存储位置
1 共享内存初始化
SHAREDMEMORY sharesend; sharesend.intShareroom();
2 发送和接收数据,给例程给了三种数据的收发
3 应该加入同步策略,通过一个标志位来决定什么时候收发。
4 最后释放共享内内存
工程文件
ShareMemray.h
#pragma once #ifndef ShareMemray_H #define ShareMemray_H #include<iostream> #include<Windows.h> #include <stdio.h> #include <cstdio> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; //--------------------------------共享内存数据类型-------------------------------------- //目标检测的上下顶点; typedef struct { int x; int y; int width; int height; int flag; }TrackBox; //20个字节 //图像的宽、高、类型信息 typedef struct { int width; //4个字节 int height; int type; }ImgInf; //图像的数据信息 单通道和三通道 //Mat //--------------------------------共享内存大小确定-------------------------------------- //1-1为BOX分配的空间 #define BOX_SIZE sizeof(TrackBox) // TrackBox结构体大小 //1-2为BOX数组分配 #define MAT_BOXVEC_NUMBER 2 //几路视频就有多少对应的检测数组 #define MAT_BOX_NUMBER 100 // 一个容器里假设最大有100个TrackBox(20个字节) 2000个字节 #define MAT_BOX_VECTOR MAT_BOX_NUMBER*BOX_SIZE //1-3为图片分配的空间 #define FRAME_NUMBER 2 // 图像输入路数 #define FRAME_W_H 1920*1080 // 图像分辨率 #define FRAME_SIZE FRAME_W_H*sizeof(unsigned char)*3+sizeof(ImgInf) // 图像彩色图(三通道)+ 图像信息结构体 //--------------------------------共享内存位置分配-------------------------------------- //各路图像所在共享内存位置 #define MAT_DATA1 FRAME_SIZE*0 //存MAT_DATA1 pBuf+FRAME_SIZE*1 - pBuf+FRAME_SIZE*1+sizeof(Mat) #define MAT_DATA2 FRAME_SIZE*1 //存MAT_DATA1 pBuf+FRAME_SIZE*2 - pBuf+FRAME_SIZE*1+sizeof(Mat) #define MAT_DATA1_BOX FRAME_SIZE*2 #define MAT_DATA2_BOX FRAME_SIZE*2+MAT_BOX_VECTOR //BOX_DATA所在共享内存位置 #define BOX_DATA FRAME_SIZE*FRAME_NUMBER + MAT_BOX_VECTOR*MAT_BOXVEC_NUMBER //数据存储的起始位置 存BOX_DATA pBuf+FRAME_SIZE*0 - pBuf+FRAME_SIZE*0+sizeof(TrackBox) //总空间大小 #define MEMORY_SIZE FRAME_SIZE*FRAME_NUMBER+MAT_BOX_VECTOR*MAT_BOXVEC_NUMBER+BOX_SIZE class SHAREDMEMORY { public: HANDLE hMapFile; LPCTSTR pBuf; TCHAR szName[30] = TEXT("Local\FHY_SYSTEM_0"); //指向同一块共享内存的名字 //TrackBox BOX; //vector<TrackBox> VTrackBox; //为了共享内存传输,必须开始初始化最大 public: //1 初始化 int intShareroom(); void SendBox(TrackBox &BOX); void RecBox(TrackBox &BOX); void SendVectorBox(vector<TrackBox> &VTrackBox); void RecieveVectorBox(vector<TrackBox> &VTrackBox); void SendMat(cv::Mat img, char indexAddress); Mat RecieveMat(char indexAddress); void stop(); }; #endif //SHAREDMEMORY_HPP
ShareMemray.cpp
#pragma once #ifndef ShareMemray_CPP #define ShareMemray_CPP #include "ShareMemray.h" //3.2 初始化 int SHAREDMEMORY::intShareroom() { hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMORY_SIZE ,szName); if (hMapFile == NULL) { cout <<"Could not create file mapping object" << GetLastError() << endl; return 1; } pBuf = (LPTSTR)MapViewOfFile(hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, MEMORY_SIZE); if (pBuf == NULL) { cout << "Could not map view of file" << GetLastError() << endl; CloseHandle(hMapFile); return 1; } // 容器初始化 //VTrackBox.resize(MAT_BOX_NUMBER); } /************************************************** 功能: 发送单个结构体 输入: TrackBox &BOX 1结构体 (char*)pBuf+ BOX_DATA 2结构体存在的位置 sizeof(TrackBox) 3结构体大小() ***************************************************/ void SHAREDMEMORY::SendBox(TrackBox &BOX) { memcpy((char*)pBuf+ BOX_DATA, &BOX, sizeof(TrackBox)); } /************************************************** 功能: 接收单个结构体 输入: TrackBox &BOX 1结构体 (char*)pBuf+ BOX_DATA 2结构体存在的位置 sizeof(TrackBox) 3结构体大小() ***************************************************/ void SHAREDMEMORY::RecBox(TrackBox &BOX) { memcpy(&BOX, (char*)pBuf+ BOX_DATA, sizeof(TrackBox)); } /************************************************** *name :void SendVectorBox(vector<TrackBox> VTrackBox) *function :发送容器,结构体序列序列 输入: vector<TrackBox> VTrackBox 1要存得容器 (char*)pBuf + MAT_DATA1_BOX 2结构体序列得起始位置 number*sizeof(TrackBox) 3每一个结构体依次往后递增存储位置 sizeof(TrackBox) 4单个结构体大小 输出: 无 说明: 1每次调用前清空容器 2采用auto &i : VTrackBox 访问容器,确保容器提前resize足够固定空间,否则无法存 VTrackBox.resize(MAT_BOX_NUMBER); 即使这样,循环访问索引还是会出错,最好固定数目MAT_BOX_NUMBER 而非用 VTrackBox.size() 正确 for (int i = 0; i <100; i++) 出问题 for (int i = 0; i <VTrackBox.size(); i++) **************************************************/ void SHAREDMEMORY::SendVectorBox(vector<TrackBox> &VTrackBox) { int number = 0; for (auto &i : VTrackBox) { //cout << number << " "<< i.x <<endl; memcpy((char*)pBuf + MAT_DATA1_BOX + number*sizeof(TrackBox), &i, sizeof(TrackBox)); number++; } //VTrackBox.clear(); //VTrackBox.resize(MAT_BOX_NUMBER); } /************************************************** *name :void RecieveVectorBox(vector<TrackBox> VTrackBox) *function :接受容器序列 输入: vector<TrackBox> VTrackBox 要接受的容器 输出: 无 **************************************************/ void SHAREDMEMORY::RecieveVectorBox(vector<TrackBox> &VTrackBox) { //VTrackBox.clear(); //VTrackBox.resize(MAT_BOX_NUMBER); int number = 0; for (auto &i : VTrackBox) { memcpy(&i ,(char*)pBuf + MAT_DATA1_BOX + number*sizeof(TrackBox), sizeof(TrackBox)); number++; } } /************************************************** *name :int SharedMemory::sendMat(Mat img, int index) *function :发送Mat图像 输入: Mat img 要存得图像 char indexAddress 图像要存得位置 输出: 无 **************************************************/ void SHAREDMEMORY::SendMat(cv::Mat img, char indexAddress) { ImgInf ImgHead; ImgHead.width = img.cols; ImgHead.height = img.rows; ImgHead.type = img.type(); if (ImgHead.type == CV_64FC1) { memcpy((char*)pBuf + indexAddress, &ImgHead, sizeof(ImgInf)); memcpy((char*)pBuf + indexAddress + sizeof(ImgInf), img.data, img.cols * img.rows * img.channels() * sizeof(double)); } else { memcpy((char*)pBuf + indexAddress, &ImgHead, sizeof(ImgInf)); memcpy((char*)pBuf + indexAddress + sizeof(ImgInf), img.data, img.cols * img.rows * img.channels()); } } /************************************************** *name :int SharedMemory::recieveMat(int index) *function :接收Mat图像 *参数: 输入:char indexAddress 要取得图像首地址 输出: Mat 类型图像 **************************************************/ cv::Mat SHAREDMEMORY::RecieveMat(char indexAddress) { ImgInf ImgHead; cv::Mat img; memcpy(&ImgHead, (char*)pBuf+indexAddress, sizeof(ImgInf)); img.create(ImgHead.height, ImgHead.width, ImgHead.type); if (ImgHead.type == CV_64FC1) { memcpy(img.data, (char*)pBuf+indexAddress + sizeof(ImgInf), img.cols * img.rows * img.channels() * sizeof(double)); } else { memcpy(img.data, (char*)pBuf+indexAddress + sizeof(ImgInf), img.cols * img.rows * img.channels()); } return img; } void SHAREDMEMORY::stop() { UnmapViewOfFile(pBuf); //释放; CloseHandle(hMapFile); } #endif