本文主要用於python和c++相互通信,通過共享內存相互傳遞數據,圖像,數組,結構體。
python優勢在於開發快速方便,有很多擴展庫可用,且深度學習很多都是python寫的。
c++底層速度快,但是開發慢,尤其是很多SLAM和圖像處理的只有c++版本。
為了調試開發方便,有時候需要嫁接兩個工程,根據自己實際需要決定。
大概思路
1 c++編譯動態庫完成各種共享內存的實際操作。
2 python端調用c++動態庫進行共享內存數據交互。
3 c++端調用c++動態庫進行共享內存數據交互。
主要用的的是ctypes
資料
https://blog.csdn.net/koibiki/article/details/89478458
https://docs.python.org/3/library/ctypes.html
共享內存
在 Linux 實現內存共享的函數主要有 shmget、shmat、shmdt、shmctl 這么四個。
1、shmget 得到或者創建 一個共享內存對象
int shmget(key_t key, size_t size, int shmflg)
其中 key_t key 的值為一個IPC鍵值,可以通過IPC_PRIVATE 建立一個新的鍵值為0的共享對象 ,但這並不能保證與IPC對象的對應關系,不同進程之間需要同一個且不會重復的IPC鍵值來完成通信,一般此參數使用ftok函數來進行創建IPC鍵值。
size_t size 是映射共享內存的大小,單位為字節 (Byte),但在創建時這里的最小分配單位是一頁,大致為4KB,當你超過4KB但是小於8KB時會主動分配兩頁,也就是不足一頁(4KB)的按照一頁計算。
int shmflg 參數是需要注明的操作模式。
- 0:取鍵值對應的共享內存,若此鍵值相應的共享內存不存在就報錯。
- IPC_CREAT:存在與鍵值對應的共享內存則返回標識符,若不存在則創建共享內存返回標識符。
- IPC_CREAT|IPC_EXCL:不存在相應鍵值的共享內存則創建此共享內存,若存在則報錯
返回值:成功返回共享內存的標識符,失敗返回-1。
2、shmat 獲得共享內存的地址(與進程建立映射)
void *shmat(int shmid, const void *shmaddr, int shmflg)
int shmid 接收一個共享內存標識符參數,通常由 shmget 返回。
const void *shmaddr 共享內存地址映射到進程哪塊內存地址,若設 NULL 則讓內核決定。
int shmflg 選擇操作模式,設 SHM_RDONLY 為只讀共享內存,其他或0為可讀寫。
返回值:成功返回映射完成的內存地址,失敗返回-1。
3、shmdt 與進程斷開映射關系
int shmdt(const void *shmaddr)
const void *shmaddr 在進程中用於映射內存地址的指針。
返回值:成功返回0,失敗返回-1。
4、shmctl 管理共享內存(釋放共享內存)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
int shmid 接收一個共享內存標識符參數,通常由 shmget 返回。
int cmd 是需要注明的操作模式。
- IPC_STAT:獲取共享內存狀態,將共享內存的 shmid_ds 信息拷貝到 shmid_ds *buf 中。
- IPC_SET:更改共享內存狀態,將 shmid_ds *buf 所指內容拷貝到共享內存 shmid_ds 中。
- IPC_RMID:刪除釋放這塊共享內存。
struct shmid_ds *buf 內存管理結構體,這個結構在 shm.h 中定義,網上能查到信息。
返回值:成功返回0,失敗返回-1。
簡單實例
#include <stdio.h>
#include <string.h>
//共享內存
#include <sys/shm.h>
//掛起進程
#include <unistd.h>
int main(void)
{
//分配內存標志
int segment_id;
//要映射的地址
char* text;
//共享內存結構
struct shmid_ds shmbuffer;
//創建共享內存
segment_id = shmget((key_t)1234567, 1, IPC_CREAT);
//映射共享地址
text = (char*)shmat(segment_id, NULL, 0);
while (1)
{
//映射共享地址
//text = (char*)shmat(segment_id, NULL, 0); //斷開映射前,不能重復映射否則內存泄露
//拷入共享地址
memcpy(text, "A", 2);
//10000微妙,10毫秒
usleep(10000);
//輸出當前共享內存區域地址
printf("%s\n", text);
}
//斷開映射
shmdt(text);
//釋放共享內存塊
shmctl(segment_id, IPC_RMID, 0);
return 0;
}
問題注意
共享內存使用完,例如每次更新一張圖像后.
1每次程序要映射同一個地址的時候,要斷開先前的映射,不然在映射的時候會認為地址被占用,重新隨機映射分配新地址,造成共享內存不停的再增大.
shmdt("名字");
2最后是用完要釋放共享內存
shmctl(segment_id, IPC_RMID, 0);
3 使用 shmget -> shmat -> shmctl 這樣一個流程就能描述一個內存從創建到銷毀的過程。
(創建)->(映射)-> (斷開映射)->(銷毀)
測試環境
ubuntu18.05
聯想筆記本
工程

1編譯
cd bulid
刪除清空
cmake ..
make
生成
c++ 發送測試端 send
c++ 接收測試端 client
c++ python和c++的交互動態庫 libpython2share.so

同時python的測試樣例

python的發送端 py_send.py
python的接收端 py_client.py
2測試樣例
測試數據: 共享內存
-1圖像1920*1080
-2 gps數組(經度 維度 高度 時間戳)
-3 gps結構體(標志位 字符串說明 經度 維度 高度 時間戳)

2-1 c++ 發送,c++接收

2-2 c++發送,pytho接受

2-3 python發送,c++接受

2-3 python發送,python接收
(如果是單純的pyton接受,python有自己的共享內存機制,更好用)
參考整理 python共享內存 https://www.cnblogs.com/gooutlook/p/12262304.html



3其他說明
3-1 while不要出現空循環(什么也不做),容易導致一個進程占用cpu,導致其他進程無法獲取cpu控制權,無法修改共享內存數據,造成假死狀態。在while中加入sleep(0.001)操作。
雖然是多核CPU,從道理上來說不應出現這種問題,但是各種程序測試都是類似問題。
4代碼結構
CMakeLists.txt
# cmake needs this line
cmake_minimum_required(VERSION 3.1)
# Define project name
project(opencv_example_project)
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
# Declare the executable target built from your sources
add_library(python2share SHARED ApiShare_dll.cpp)
#add_executable(send send_example.cpp ApiShare_dll.cpp)
#add_executable(client recive_example.cpp ApiShare.cpp)
add_executable(send send_example.cpp)
add_executable(client recive_example.cpp)
# Link your application with OpenCV libraries
target_link_libraries(send ${OpenCV_LIBS} )
target_link_libraries(client ${OpenCV_LIBS} )
target_link_libraries(python2share ${OpenCV_LIBS})
C++動態庫
ApiShare_dll.cpp
使用前修改以下數據:
1 圖像分辨率 默認1920*1080
#define IMAGE_W 1920 //圖像寬 #define IMAGE_H 1080 //圖像高 #define IMAGE_SIZE IMAGE_W*IMAGE_H*3 //圖片像素總大小 3通道彩色
2 共享內存標識,默認一個共享內存地址,未來如果開啟多個地址同可修改這個
#define Shm_addrees 1203 //共享內存地址標識
3 共享內存數據結構,未來根據自己需要修改
//共享內存-圖像
typedef struct ShareData
{
int flag;
int rows;//圖像高
int cols;//圖像寬
char imgdata[IMAGE_SIZE];//圖像數據一維數據,之前用了cv::Mat不行,因為無法在結構體里初始化大小
float Gps[4];//保存gps信息 經緯高時間戳
}ShareData_;
4 共享內存圖像格式默認是char,其中類中圖像變量cvoutImg 是用來暫存一個mat類型圖像,便於直接訪問無需轉化才能訪問。根據不同的數據修改圖像類型
cv::Mat cvoutImg = cv::Mat(IMAGE_H,IMAGE_W,CV_8UC3,cv::Scalar(255, 255, 255));//bufHight,bufWidthl
例如 zed雙目相機出來的圖格式是CV_8UC4而不是文件中默認的CV_8UC3。所以就要改成
cv::Mat cvoutImg = cv::Mat(IMAGE_H,IMAGE_W,CV_8UC4,cv::Scalar(255, 255, 255));//bufHight,bufWidthl
ApiShare_dll.cpp 完整代碼
#ifndef SHARE
#define SHARE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
using namespace cv;
namespace MyShare{
#define Shm_addrees 1203 //共享內存地址標識
#define IMAGE_W 1920 //圖像寬
#define IMAGE_H 1080 //圖像高
#define IMAGE_SIZE IMAGE_W*IMAGE_H*3 //圖片像素總大小 3通道彩色
//共享內存-圖像
typedef struct ShareData
{
int flag;
int rows;//圖像高
int cols;//圖像寬
char imgdata[IMAGE_SIZE];//圖像數據一維數據,之前用了cv::Mat不行,因為無法在結構體里初始化大小
float Gps[4];//保存gps信息 經緯高時間戳
}ShareData_;
// 非共享內存-傳送gps混合數據
typedef struct StructGpsData {
int flag;
char *msg;
float longitude;
float latitude;
float high;
float time;
} ;
class Share_class
{
//變量定義
public:
//1創建共享內存
int shmid = shmget((key_t)Shm_addrees, sizeof(ShareData), 0666|IPC_CREAT);
//2映射共享內存地址 shm指針記錄了起始地址
void *shm = shmat(shmid, (void*)0, 0);//如果創建一個函數每次調用都執行,需要執行完釋放一下shmdt
//printf("共享內存地址 : %p\n", (int *)(shm));
//2-1以ShareData結構體類型-訪問共享內存
ShareData *pShareData= (ShareData*)shm;
//用來保存轉化后的共享內存的圖像結果
cv::Mat cvoutImg = cv::Mat(IMAGE_H,IMAGE_W,CV_8UC3,cv::Scalar(255, 255, 255));//bufHight,bufWidth
//未來加速 可以搞一個圖像隊列 隊列大小3 不停存圖,然后挨着丟進共享內存,滿了就清除。
//函數定義
public:
//1初始化執行
Share_class(){
printf("共享內存地址 : %p\n", (int *)(shm));
//存圖要先把圖像標志位初始給0,這里給會導致接收端調用開啟的時候再次給0覆蓋了1導致取圖失敗。
}//1構造函數
//0銷毀執行
~Share_class() {
cout<<"析構函數執行"<<endl;
DestroyShare();
} //0結束銷毀函數
//3銷毀共享內存
int DestroyShare(){
//4斷開映射 ,保證下次訪問不被占用
shmdt(shm);
//5釋放共享內存地址
shmctl(shmid, IPC_RMID, 0);
cout<<"共享內存已經銷毀"<<endl;
}
/*
函數功能: c++-》c++庫-》共享內存
c++ 模式調用,
c++ 發送圖像一張到共享內存 ,
修改圖像標志位1,允許c++和pythoN調用接收函數接受圖像。
函數輸入:
cv::Mat Img 要發送的圖像
函數輸出:
pShareData->flag = 1; 圖像標志位
Mat cvoutImg 該類圖像變量
*/
int Send_pic2_share_once(cv::Mat Img){
int i = 0;
if(pShareData->flag == 0)
{
//cv::Mat Img=cv::imread("../data_img/1.jpg",cv::IMREAD_COLOR);
if(Img.data== nullptr)//nullptr是c++11新出現的空指針常量
{
printf("圖片文件不存在\n");
return 0;
}
else{
// printf("圖片文件存在\n");
}
//3-1共享內存保存圖像寬和高
pShareData->rows =Img.rows;
pShareData->cols = Img.cols;
//3-2共享內存保存圖像數據
int size = Img.cols * Img.rows * Img.channels();
char *cvoutImg = (char*)Img.data;
memcpy(pShareData->imgdata, cvoutImg, size);
//3-3共享內存保存標志位
pShareData->flag = 1;
}
//getchar();
}
/*
函數功能:python 或 c++-》c++庫-》共享內存
python 和 c++ 都可調用
c++ 或python 發送圖像一張到共享內存 ,
修改圖像標志位1,允許c++和pythoN調用接收函數接受圖像。
如果是python模式通過c++庫調用,可開啟圖像展示驗證圖像是否完整
函數輸入:
uchar *frame_data, 要發送圖像的圖像數據 Mat img.data
int height, 圖像高
int width 圖像寬
函數輸出:
pShareData->flag = 1; 圖像標志位
Mat cvoutImg 該類圖像變量
*/
int pySend_pic2_share_once(uchar *frame_data, int height, int width){
if(pShareData->flag == 0)
{
//assert(height*width*3<=IMAGE_SIZE);
if(frame_data== nullptr)//nullptr是c++11新出現的空指針常量
{
printf("圖片文件不存在\n");
return 0;
}
else{
// printf("圖片文件存在\n");
}
pShareData->cols=width;
pShareData->rows=height;
int size = height*width*3;
memcpy(pShareData->imgdata, frame_data, size);
//3-3共享內存保存標志位
pShareData->flag = 1;
//printf("數據保存成功 %d\n",pShareData->flag);
/*
//python模式下用來驗證發送的圖像是否完整。 python-》c++庫-》共享內存
int showimg=0; //如果要顯示 打開設置1
if(!showimg) return 0;
int channel=3;
cv::Mat image(height, width, CV_8UC3);
for (int row = 0; row < height; row++) {
uchar *pxvec = image.ptr<uchar>(row);
for (int col = 0; col < width; col++) {
for (int c = 0; c < channel; c++) {
pxvec[col * channel + c] = frame_data[row * width * channel + channel * col + c];
}
}
}
cv::imshow("image", image);
cv::waitKey(3);
*/
}
}
/*
函數功能: 共享內存 -> c++庫-> c++
C++ 調用
C++從共享內存讀取一張圖片
修改圖像標志位0,允許發送端往共享內存存圖。
函數輸入:
函數輸出:
pShareData->flag = 0; 圖像標志位
Mat cvoutImg 該類圖像變量
*/
int Rec_pic2_data_once()
{ //cv::Mat &cvoutImg_in
//3-1共享內存讀取標志位
if(pShareData->flag == 1)
{
//3-2從共享內存獲取圖像高和寬
int IMAGE_h=pShareData->rows;//從共享內存獲取圖像高
int IMAGE_w=pShareData->cols;//從共享內存獲取圖像寬
//3-3共享內存讀取圖像數據
//cv::Mat cvoutImg = cv::Mat(IMAGE_h,IMAGE_w,CV_8UC3,cv::Scalar(255, 255, 255));//bufHight,bufWidth
int size = cvoutImg.cols * cvoutImg.rows * cvoutImg.channels();
memcpy((char*)cvoutImg.data, pShareData->imgdata,size);
//cv::imshow("RecData_Show",cvoutImg);
//cv::waitKey(1);
// printf("數據跟新一次\n");
//3-4共享內存修改標志位
pShareData->flag = 0;
}
}
/*
函數功能: 共享內存 -> c++庫-> python 或 c++
python 調用(C++用Rec_pic2_data_once) 主要是給python用獲取共享內存的圖像
python從共享內存讀取一張圖片
修改圖像標志位0,允許發送端往共享內存存圖。
函數輸入:
調用前先用c++端更新共享內存最新的圖像
函數輸出:
pShareData->flag = 0; 圖像標志位
(uchar*)cvoutImg.data 該類圖像變量cvoutImg的數據data指針
*/
uchar* Img_Cgg2py(){ //uchar* frame_data, int rows, int cols, int channels
//將共享內存現有的圖像數據發送
if(pShareData->flag == 1){
// cvoutImg=cv::imread("/home/dongdong/3Code/python2c/1/c++2c++/v4_c++_class_python/img_data/00001.jpg");
if(cvoutImg.data== nullptr)//nullptr是c++11新出現的空指針常量
{
printf("圖片文件不存在\n");
return 0;
}
else{
// printf("圖片文件存在\n");
}
//pShareData->flag = 0; //等python完成數組轉化到圖像,在python端完成標志位0
return (uchar*)pShareData->imgdata;//這里只試穿了一個數組,瞬間完成
// pShareData->flag = 0; //等python完成數組轉化到圖像,在python端完成標志位0
}
//重新建立新的數據發送模式
/*
Mat image =cv::imread("/home/dongdong/3Code/python2c/1/c++2c++/v4_c++_class_python/img_data/00001.jpg");
if (!image.empty()) {
//cout<< "cgg2py new pic"<<endl;
//cv::imshow("cgg", image);
//cv::waitKey(0);
int rows = image.rows;
int cols = image.cols;
int channels = image.channels();
// printf("rows = %d cols = %d channels = %d size = %d\n", rows, cols, channels, rows*cols*channels);
uchar *data = (uchar*)malloc(sizeof(uchar) * rows * cols * channels);
memcpy(data, image.data, rows * cols * channels);
return data;
}
*/
}
/*
函數功能: 共享內存 -> c++庫-> python 或 c++
python 調用(C++直接通過類變量引用) 主要是給python通過函數方式用獲取共享內存的int flag數據
獲取圖像標志位,用於判斷是否可以讀寫
函數輸入:
函數輸出:
pShareData->flag = 0 or 1; 圖像標志位
*/
//4-1獲取圖像保存標志位
int Get_ImgFlag(){
return pShareData->flag ;
}
/*
函數功能: 共享內存 -> c++庫-> python 或 c++
python 調用(C++直接通過類變量引用) 主要是給python通過函數方式用修改共享內存的int flag數據
設置圖像標志位,用於開啟是否可以讀寫
函數輸入:
int value pythoN需要將數據轉化為 ctypes.c_int 送進來 默認int不需要
函數輸出:
pShareData->flag = 0 or 1; 圖像標志位 pythoN需要將數據轉化為 ctypes.c_int 接受 默認int不需要
*/
int Set_ImgFalg(int value){
pShareData->flag =value;
}
/*
函數功能: python send -> c++庫 -> 共享內存 -> c++庫-> python rec
python 調用 (c++端直接通過類的變量引用就可以)
python 修改共享內存中的gps數據
函數輸入:
float *data python的數組索引 和 類型
int len python的數組長度
函數輸出:
float result 操作結果 可不使用(python接收端需要指明接收數據類型 c float指針 ctypes.POINTER(ctypes.c_float) )
*/
//5傳輸數組 接受py數組並修改python原數組,返回總和結果
float pyarr_set_cgg_gps_share(float *data, int len) {
float result=1;
for (int i = 0; i < len; i++) {
pShareData->Gps[i]=data[i] ;
}
return result;
}
/*
函數功能: python -> c++庫 -> 共享內存 -> c++庫-> python
python 調用 (c++端直接通過類的變量引用就可以)
python 獲取共享內存中的gps數據
函數輸入:
float pShareData->Gps[4] C++ 共享內存結構體pShareData中的GPS數據
函數輸出:
(uchar*) pShareData->Gps; (python接收端需要指明接收數據類型 c float指針 ctypes.POINTER(ctypes.c_float) )
*/
uchar* py_get_cgg_gps_share(){
// c++發送端調用其他函數更新GPS數據,保存在共內存(簡單舉例)
//pShareData->Gps[0]=1.56;
//pShareData->Gps[1]=2.34;
//pShareData->Gps[2]=3.14;
//pShareData->Gps[3]=4.78;
return (uchar*) pShareData->Gps; //返回指針
}
/*
函數功能: python -> c++庫 -> 共享內存 -> c++庫-> python
python 調用 (c++端直接通過類的變量引用就可以)
python 獲取共享內存中的gps數據 python傳送過來一個結構體,修改pytho原結構體返回
函數輸入:
float pShareData->Gps[4] C++ 共享內存結構體pShareData中的GPS數據
StructGpsData gps C++的結構體- python需要將對應的python結構體輸入
函數輸出:
StructGpsData gps (python接收端需要指明接收數據類型 )
*/
StructGpsData py_get_cgg_gps_Struct( StructGpsData gps){
// c++發送端調用其他函數更新GPS數據,保存在共內存(簡單舉例)
//pShareData->Gps[0]=1.56;
//pShareData->Gps[1]=2.34;
//pShareData->Gps[2]=3.14;
//pShareData->Gps[3]=4.78;
//共享內存數據更新gps數據
gps.flag=1;
gps.msg="new share data from c++ share";
gps.longitude=pShareData->Gps[0];
gps.latitude=pShareData->Gps[1];
gps.high=pShareData->Gps[2];
gps.time=pShareData->Gps[3];
return gps;
}
/*
函數功能: python -> c++庫 -> 共享內存
python 調用 (c++端直接通過類的變量引用就可以)
python 修改共享內存中的gps數據 python傳送過來一個結構體,修改C++原結構體
函數輸入:
float pShareData->Gps[4] C++ 共享內存結構體pShareData中的GPS數據
StructGpsData gps C++的結構體- python需要將對應的python結構體輸入
函數輸出:
StructGpsData gps (python接收端需要指明接收數據類型 )
*/
StructGpsData py_Set_cgg_gps_Struct( StructGpsData gps){
// c++發送端調用其他函數更新GPS數據,保存在共內存(簡單舉例)
gps.flag=1;
gps.msg="new share have set share c++";
pShareData->Gps[0]=gps.longitude;
pShareData->Gps[1]=gps.latitude;
pShareData->Gps[2]= gps.high;
pShareData->Gps[3]=gps.time;
return gps;
}
};//類定義結束
}//namespace 定義
//按照C語言格式重新打包-python調用
extern "C" {
MyShare::Share_class useShare;
int DestroyShare_(){
useShare.DestroyShare();
}
int Send_pic2_share_once_(cv::Mat Img){
useShare.Send_pic2_share_once(Img);
}
int pySend_pic2_share_once_(uchar *frame_data, int height, int width){
useShare.pySend_pic2_share_once(frame_data, height, width);
}
int Rec_pic2_data_once_(){
useShare.Rec_pic2_data_once();
}
uchar* Img_Cgg2py_(){
useShare.Img_Cgg2py();
}
int Get_ImgFlag_(){
useShare.Get_ImgFlag();
}
int Set_ImgFalg_(int value){
useShare.Set_ImgFalg(value);
}
float pyarr_set_cgg_gps_share_(float *data, int len) {
useShare.pyarr_set_cgg_gps_share( data, len);
}
uchar* py_get_cgg_gps_share_(){
useShare.py_get_cgg_gps_share();
}
MyShare::StructGpsData py_get_cgg_gps_Struct_( MyShare::StructGpsData gps){
return useShare.py_get_cgg_gps_Struct(gps);
}
MyShare::StructGpsData py_Set_cgg_gps_Struct_(MyShare::StructGpsData gps){
return useShare.py_Set_cgg_gps_Struct(gps);
}
}
#endif
c++發送端
send_example.cpp
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
#include <string>
#include "ApiShare_dll.cpp"
using namespace std;
int main()
{
//1創建對象 可以不創建 調用文件自動有一個
//MyShare::Share_class useShare; //頭文件c++封裝c函數時候已經創建了
//2-1發送數據-讀取數據
cv::Mat Img=cv::imread("/home/dongdong/3Code/python2c/1/c++2c++/v4_c++_class_python/img_data/00001.jpg",cv::IMREAD_COLOR);
//cv::imshow("RecData_Show",Img);
//char key=cv::waitKey(0);
//2-2修改標志位--用來控制讀取同步
useShare.pShareData->flag = 0; //提醒。第一次初始化強制給0,清除上次程序殘留結果,類初始化已經給0了
//3發送圖像
while (1){
sleep(0.001);//防止絕對的空循環導致CPu占用,其他進程無法修改共享內存
//發送gps-C++直接訪問類變量發送修改
if( useShare.pShareData->flag ==0){
useShare.pShareData->Gps[0]=32.3;
useShare.pShareData->Gps[1]=12.3;
useShare.pShareData->Gps[2]=72.3;
useShare.pShareData->Gps[3]=12.3;
}
if( useShare.pShareData->flag ==0){//讀取完畢,允許存圖
// 發送圖像-C++模式
//useShare.Send_pic2_share_once(Img);//發送一張圖像
//發送圖像-C++和python模式
useShare.pySend_pic2_share_once((uchar*)Img.data,Img.rows,Img.cols);//發送一張圖
useShare.pShareData->flag =1;//存儲完畢,允許讀圖
}
if(useShare.pShareData->flag ==3){ //接收端讀取成功並且將標志位修改成3 關閉
break;
}
}
//銷毀
//useShare.DestroyShare(); //銷毀共享內存 類釋放時候會自動銷毀,這里做個提醒
}
C++接收端
recive_example.cpp
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
#include <string>
#include "ApiShare_dll.cpp"
using namespace std;
int main()
{
//1創建對象
//MyShare::Share_class useShare;
//2創建接受圖像
cv::Mat RecImg = cv::Mat(676,1201,CV_8UC3,cv::Scalar(255, 255, 255));//bufHight,bufWidth
//3接受GPS數據
float Gps_c[4];
//3接受圖像
while (1){
sleep(0.001);//防止絕對的空循環導致CPu占用,其他進程無法修改共享內存
//接受GPS
if( useShare.pShareData->flag ==1){
Gps_c[0]=useShare.pShareData->Gps[0];
Gps_c[1]=useShare.pShareData->Gps[1];
Gps_c[2]=useShare.pShareData->Gps[2];
Gps_c[3]=useShare.pShareData->Gps[3];
for(int i=0;i<=3;i++){cout<< "GPS_DATA"<<i <<" "<<Gps_c[i] <<" ";}
cout<<endl;
}
//接受圖像
if( useShare.pShareData->flag ==1){//存儲完畢,允許讀圖
useShare.Rec_pic2_data_once();//接受一張圖像自動保存在useShare.cvoutImg中,然后修改標志位
RecImg=useShare.cvoutImg;
useShare.pShareData->flag =0;//讀取完畢,允許存圖
}
cv::imshow("RecData_Show",RecImg);
char key=cv::waitKey(1);
if(key=='q'){ useShare.pShareData->flag=3; printf("按鍵退出"); break;}
}
//銷毀
//useShare.DestroyShare(); //銷毀共享內存 類釋放自動銷毀
return 0;
}

python發送端
py_send.py
import numpy as np
import time
import ctypes
import os
import cv2
#更多類型參看 https://docs.python.org/3/library/ctypes.html
# c_bool c_char c_int c_long c_float c_double
# c_char_p c_wchar_p c_void_p
#1載入庫
libLoad = ctypes.cdll.LoadLibrary
sharelib = libLoad("./build/libpython2share.so")
#--------------0-發送單個int 初始第一次設置為0 允許開始存圖------------------------
sharelib.Set_ImgFalg_.argtype = ctypes.c_int # 設置函數輸入值類型 int可忽略
#sharelib.Set_ImgFalg_(0) #修改c++類的某一個變量(py只能通過函數而非直接訪問修改)
sharelib.Get_ImgFlag_.restype = ctypes.c_int # 設置返回值類型 int可忽略
#reuslt=sharelib.Get_ImgFlag_()#獲取變量的結果
#--------------------2-1 數組修改GPS ----------------
def py_Arr_GPS(pyarray):
sharelib.pyarr_set_cgg_gps_share_.restype = ctypes.c_float #定義函數返回值類型
#pyarray = [1., 2., 3., 4.] #創建py數組
carray2cgg = (ctypes.c_float * len(pyarray))(*pyarray) #轉化成c_float指針
reuls_sum=sharelib.pyarr_set_cgg_gps_share_(carray2cgg, len(pyarray)) #調用查詢
size=(1,4) #將獲取的數組變成 1*3矩陣
pose = np.reshape(np.array(np.fromiter(carray2cgg, np.float64, size[0]*size[1])), size)
print("c++修改后返回,python n*n維度數組:\n",pose)
#--------------------2-2 結構體修改GPS ----------------
#python創建結構體
class py_Struct_GPS(ctypes.Structure):
_fields_ = [
('flag', ctypes.c_int), #c++ int
('msg', ctypes.c_char_p), #c++ char*
('longitude', ctypes.c_float), # c++ float
('latitude', ctypes.c_float),# c++ float
('high', ctypes.c_float),# c++ float
('time', ctypes.c_float)# c++ float
] #c++ char*[]
#python結構體賦予初值
struct_gps=py_Struct_GPS()
struct_gps.flag=ctypes.c_int(0)
struct_gps.msg=ctypes.c_char_p('GPS DATA'.encode())
struct_gps.longitude=ctypes.c_float(0.)
struct_gps.latitude=ctypes.c_float(0.)
struct_gps.high=ctypes.c_float(0.)
struct_gps.time=ctypes.c_float(0.)
print("結構體gps_old \n",struct_gps)
print(struct_gps.flag,struct_gps.msg.decode(),struct_gps.longitude,struct_gps.latitude,struct_gps.high,struct_gps.time)
#0 GPS DATA 0.0 0.0 0.0 0.0
def SetGPSToShare_struct(struct_gps,flag,msg,longitude,latitude,high,time):
struct_gps.flag=ctypes.c_int(flag)
struct_gps.msg=ctypes.c_char_p(msg.encode())
struct_gps.longitude=ctypes.c_float(longitude)
struct_gps.latitude=ctypes.c_float(latitude)
struct_gps.high=ctypes.c_float(high)
struct_gps.time=ctypes.c_float(time)
#從c++獲取數據-數據保存在 共享內存或C++直接生成
# 定義返回類型為結構體類型
sharelib.py_Set_cgg_gps_Struct_.restype = py_Struct_GPS
# 調用獲取gps數據-返回數據結構體
struct_gps= sharelib.py_Set_cgg_gps_Struct_(struct_gps)
#print(struct_gps.flag)
print(struct_gps.msg.decode()) #必須解碼
#print("結構體gps_new \n",struct_gps)
#print(struct_gps.flag,struct_gps.msg.decode(),struct_gps.longitude,struct_gps.latitude,struct_gps.high,struct_gps.time)
#1 new data 1.559999942779541 2.559999942779541 3.559999942779541 5.559999942779541
#--------------------2-2 結構體拿GPS ----------------
#3發送圖像
sharelib.Set_ImgFalg_(0) #允許存圖
pyimage = cv2.imread("img_data/00001.jpg")#讀取原始圖像
#cv2.imshow("1 ", pyimage)
#cv2.waitKey(0)
def SendImgFromShare(image):
image_data = np.asarray(image, dtype=np.uint8)#圖像轉化成數組
image_data = image_data.ctypes.data_as(ctypes.c_char_p)#數組轉化成C指針一維數組
sharelib.pySend_pic2_share_once_(image_data,image.shape[0],image.shape[1])#發送到共享內存
while True:
time.sleep(0.001)#防止絕對的空循環導致CPu占用,其他進程無法修改共享內存
#發送gps數據-數組模式
gps_p=[1.31, 3.42, 2.41, 6.41]
py_Arr_GPS(gps_p)
#發送gps數據-結構體模式
#SetGPSToShare_struct(struct_gps,0,"set gps to share",11.034,145.565,80.0,121314)
#發送圖像數據
if sharelib.Get_ImgFlag_()==0:#讀圖結束,允許存圖
SendImgFromShare(pyimage)#發送圖像
sharelib.Set_ImgFalg_(1)#存圖結束,允許讀圖
if sharelib.Get_ImgFlag_()==3:
print("接收端停止")
break
c++接收端
py_client.py
import numpy as np
import time
import ctypes
import os
import cv2
#更多類型參看 https://docs.python.org/3/library/ctypes.html
# c_bool c_char c_int c_long c_float c_double
# c_char_p c_wchar_p c_void_p
#1載入庫
libLoad = ctypes.cdll.LoadLibrary
sharelib = libLoad("./build/libpython2share.so")
#--------------0-發送單個int 初始第一次設置為0 允許開始存圖------------------------
sharelib.Set_ImgFalg_.argtype = ctypes.c_int # 設置初始值類型
#sharelib.Set_ImgFalg_(0) #修改c++類的某一個變量(py只能通過函數而非直接訪問修改)
sharelib.Get_ImgFlag_.restype = ctypes.c_int # 設置返回值類型
#reuslt=sharelib.Get_ImgFlag_()#獲取變量的結果
# -----------------2-1 獲取gps數組----------------
# 設置輸出數據類型為uint8的指針
def ReadGPSFromShare():
sharelib.py_get_cgg_gps_share_.restype =ctypes.POINTER(ctypes.c_float) #c_char_p
#獲取輸出圖像數據指針
pointer_f_gps= sharelib.py_get_cgg_gps_share_()
size=(1,4)
#數據轉化成圖像
gps = np.reshape(np.array(np.fromiter(pointer_f_gps, dtype=np.float, count=size[0]*size[1])) ,size)
print("數組模式獲取的GPS:",gps)
return gps
# -----------------2-1 獲取gps數組結束----------------
#--------------------2-2 結構體拿GPS ----------------
#python創建結構體
class py_Struct_GPS(ctypes.Structure):
_fields_ = [
('flag', ctypes.c_int), #c++ int
('msg', ctypes.c_char_p), #c++ char*
('longitude', ctypes.c_float), # c++ float
('latitude', ctypes.c_float),# c++ float
('high', ctypes.c_float),# c++ float
('time', ctypes.c_float)# c++ float
] #c++ char*[]
#python結構體賦予初值
struct_gps=py_Struct_GPS()
struct_gps.flag=ctypes.c_int(0)
struct_gps.msg=ctypes.c_char_p('GPS DATA'.encode())
struct_gps.longitude=ctypes.c_float(0.)
struct_gps.latitude=ctypes.c_float(0.)
struct_gps.high=ctypes.c_float(0.)
struct_gps.time=ctypes.c_float(0.)
print("結構體gps_old \n",struct_gps)
print(struct_gps.flag,struct_gps.msg.decode(),struct_gps.longitude,struct_gps.latitude,struct_gps.high,struct_gps.time)
#0 GPS DATA 0.0 0.0 0.0 0.0
#從c++獲取數據-數據保存在 共享內存或C++直接生成
# 定義返回類型為結構體類型
sharelib.py_get_cgg_gps_Struct_.restype = py_Struct_GPS
# 調用獲取gps數據-返回數據結構體
struct_gps= sharelib.py_get_cgg_gps_Struct_(struct_gps)
#print(struct_gps.flag)
#print(struct_gps.msg.decode()) #必須解碼
print("結構體gps_new \n",struct_gps)
print(struct_gps.flag,struct_gps.msg.decode(),struct_gps.longitude,struct_gps.latitude,struct_gps.high,struct_gps.time)
#1 new data 1.559999942779541 2.559999942779541 3.559999942779541 5.559999942779541
#--------------------2-2 結構體拿GPS ----------------
# -----------------3python read cgg 讀取圖像-------------------
def ReadImgFromShare():
# 設置輸出數據類型為uint8的指針
sharelib.Img_Cgg2py_.restype =ctypes.POINTER(ctypes.c_uint8) #c_char_p
#獲取輸出圖像數據指針
pointer_img = sharelib.Img_Cgg2py_()
size=(1080,1920,3)
#數據轉化成圖像
RecImg = np.reshape(np.array(np.fromiter(pointer_img, dtype=np.uint8, count=size[0]*size[1]*size[2])) ,size)
'''
print(RecImg.shape)#1920*1080*3
print(RecImg)
if RecImg is not None:
#展示圖像
#cv2.namedWindow("showimg",0)
cv2.imshow("showimg ", RecImg)
cv2.waitKey(1)
#return RecImg
else:
return 1
'''
return RecImg
while True:
time.sleep(0.001)#防止絕對的空循環導致CPu占用,其他進程無法修改共享內存
if sharelib.Get_ImgFlag_()==1:#存圖結束,允許讀圖
#方法1-直接訪問共享內存接受GPS數據
PyArr1x4Gps=ReadGPSFromShare()#獲取GPS
print("python直接訪問共享內存GPS數據索引:\n",PyArr1x4Gps[0][0],PyArr1x4Gps[0][1],PyArr1x4Gps[0][2],PyArr1x4Gps[0][3])
#方法2-通過結構體訪問共享內存接受GPS數據
# 調用獲取gps數據-返回數據結構體
struct_gps= sharelib.py_get_cgg_gps_Struct_(struct_gps)
#print("python通過結構體獲取共享內存GPS數據:\n",struct_gps.flag,struct_gps.msg.decode(),struct_gps.longitude,struct_gps.latitude,struct_gps.high,struct_gps.time)
#接受圖像
Py_img=ReadImgFromShare()
#展示圖像
cv2.namedWindow("showimg1",0)
cv2.imshow("showimg1 ", Py_img)
cv2.waitKey(1)
sharelib.Set_ImgFalg_(0)#讀圖結束,允許存圖
if sharelib.Get_ImgFlag_()==3:
break
