(最終版)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