(最终版)linux下python和c++相互调用共享内存通信


 

 本文主要用于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++ pythonc++的交互动态库 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

    

  

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM