程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

(二)ndarray(Python)與Mat(C++)數據的傳輸

編輯:Python

  • 1、前言
  • 2、ndarray和Mat類型轉換
    • 2.1 c++代碼
    • 2.2 python中調用MatSo::get_mat_and_return_uchar()
    • 2.3 python中調用MatSo::get_mat_and_return_buffer()
  • End

該系列文章:
(一)python調用c++代碼《從C++共享鏈接庫編譯到python調用指南》
(二)ndarray(Python)與Mat(C++)數據的傳輸
(三)C++結構體與python的傳輸

1、前言

在(一)python調用c++代碼《從C++共享鏈接庫編譯到python調用指南》中,我們已經實現了在python中調用C++代碼的效果。但是新的問題產生了,python中opencv的圖像數據是ndarray格式,C++中opencv的圖像數據是Mat格式,在C++中定義的test函數入參是Mat數據,在python中調用是不能直接將ndarray數據作為test函數的參數。

2、ndarray和Mat類型轉換

該部分我們將設計c++函數接收並返回圖像數據,你可以看到圖像數據是如何在python的ndarray和c++的Mat直接流轉的。

2.1 c++代碼

在這裡我們定義一個MatSo類,該類有兩個函數,一個函數接收uchar類型(圖像數據),並返回uchar類型(圖像數據);另一個函數接收uchar*類型(圖像數據),並返回buffer類型(圖像數據)。

// Dll2.cpp: 定義 DLL 應用程序的導出函數。
#define EXPORT __declspec(dllexport)
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// MatSO聲明
class MatSO
{

public:
// 該函數接收uchar數據,轉為Mat數據,顯示,然後再返回uchar數據
uchar *get_mat_and_return_uchar(uchar *matrix, int rows, int cols, int channels);
// 該函數接收uchar數據,轉為Mat數據,顯示,然後再返回buffle數據
uchar *get_mat_and_return_buffer(uchar *matrix, int rows, int cols, int channels);
};
// mat數據接收並以uchar返回
uchar *MatSO::get_mat_and_return_uchar(uchar *matrix, int rows, int cols, int channels)
{

// 將接收的uchar轉為Mat
cout << "rows=" << rows << "\ncols=" << cols << "\nchannels=" << channels;
Mat input_mat = Mat(Size(cols, rows), CV_8UC3, Scalar(255, 255, 255));
input_mat.data = matrix;
// 顯示Mat
imshow("input_mat", input_mat);
cv::waitKey(0);
// 將Mat轉為uchar類型並返回
// 注意:要記住這裡Mat的rol、row和channels,在python中才能正確接收
uchar *s = input_mat.data; // Mat轉ucahr*
return s;
}
// mat數據接收並以buffer返回
uchar *MatSO::get_mat_and_return_buffer(uchar *matrix, int rows, int cols, int channels)
{

// 將接收的uchar轉為Mat
cout << "rows=" << rows << "\ncols=" << cols << "\nchannels=" << channels;
Mat input_mat = Mat(Size(cols, rows), CV_8UC3, Scalar(255, 255, 255));
input_mat.data = matrix;
// 顯示Mat
imshow("input_mat", input_mat);
cv::waitKey(0);
// 將Mat轉為buffer並返回
// 注意:要記住這裡Mat的rol、row和channels,在python中才能正確接收
int height = input_mat.cols;
int width = input_mat.rows;
uchar *buffer = (uchar *)malloc(sizeof(uchar) * height * width * 3);
memcpy(buffer, input_mat.data, height * width * 3);
return buffer;
}
extern "C"
{

MatSO td; // 包裝MatSO,使之可以在so文件外調用
uchar *get_mat_and_return_uchar(uchar *matrix, int rows, int cols, int channels)
{

return td.get_mat_and_return_uchar(matrix, rows, cols, channels);
}
uchar *get_mat_and_return_buffer(uchar *matrix, int rows, int cols, int channels)
{

return td.get_mat_and_return_buffer(matrix, rows, cols, channels);
}
}

順便給出CMakeLists.txt配置:

cmake_minimum_required(VERSION 3.0.0)
project(hbp VERSION 0.1.0) # 項目名稱
set(CMAKE_CXX_FLAGS "-std=c++11") # 添加c++11標准
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS}) # 頭文件目錄
add_library(MatSo SHARED MatSo.cpp) # 設置輸出的庫的類型
target_link_libraries(MatSo ${OpenCV_LIBS})

2.2 python中調用MatSo::get_mat_and_return_uchar()

在這裡我們要完成cv2讀取一張圖片,並調用MatSo類中的函數,得到返回的數據並顯示。

主要步驟為:

  1. 加載so共享鏈接庫
  2. 定義要使用函數的入參和出參類型
  3. 對入參數據進行轉換為目的類型
  4. 調用
  5. 對返回數據進行類型轉換
import cv2
import ctypes
from ctypes import *
import numpy as np
# 加載共享鏈接庫
matso = ctypes.cdll.LoadLibrary("build/libMatSo.so")
# matso中有兩個函數我們會使用到
# 現在對這兩個函數定義入參和出參的類型
# 參考:https://blog.csdn.net/qq_40047008/article/details/107785856
matso.get_mat_and_return_uchar.argtypes = (POINTER(c_ubyte), c_int, c_int, c_int)
matso.get_mat_and_return_uchar.restype = POINTER(c_ubyte)
img = cv2.imread("face.jpeg")
rows, cols, channels = img.shape
img = img.ctypes.data_as(POINTER(c_ubyte)) # 將ndarray轉為c++的uchar類型
return_uchar_data = matso.get_mat_and_return_uchar(img, rows, cols, channels) # 調用鏈接庫函數,得到uchar*數據
# 注意這裡的rows、rows和channels是C++函數中返回時的Mat尺寸,與上面中不是同一個意思
# 但是因為上面傳入函數並返回過程中沒有改變圖像的shape,所以在數值上是一樣的
np_canny = np.array(np.fromiter(return_uchar_data, dtype=np.uint8, count=cols * rows * channels))
np_canny = np_canny.reshape((rows, cols, 3))
cv2.imshow("q", np_canny)
cv2.waitKey(0)

2.3 python中調用MatSo::get_mat_and_return_buffer()

get_mat_and_return_uchar和get_mat_and_return_buffer的區別在於返回類型不同,分別是uchar*和buffer,但是從函數類型可以看出都是uchar,所以在python中的代碼都一樣

import cv2
import ctypes
from ctypes import *
import numpy as np
# 加載共享鏈接庫
matso = ctypes.cdll.LoadLibrary("build/libMatSo.so")
# matso中有兩個函數我們會使用到
# 現在對這兩個函數定義入參和出參的類型
# 參考:https://blog.csdn.net/qq_40047008/article/details/107785856
matso.get_mat_and_return_buffer.argtypes = (POINTER(c_ubyte), c_int, c_int, c_int)
# matso.get_mat_and_return_buffer.restype = POINTER(c_uint8)
matso.get_mat_and_return_buffer.restype = POINTER(c_ubyte)
img = cv2.imread("face.jpeg")
rows, cols, channels = img.shape
img = img.ctypes.data_as(POINTER(c_ubyte)) # 將ndarray轉為c++的uchar類型
return_uchar_data = matso.get_mat_and_return_buffer(img, rows, cols, channels) # 調用鏈接庫函數,得到uchar*數據
# 注意這裡的rows、rows和channels是C++函數中返回時的Mat尺寸,與上面中不是同一個意思
# 但是因為上面傳入函數並返回過程中沒有改變圖像的shape,所以在數值上是一樣的
np_canny = np.array(np.fromiter(return_uchar_data, dtype=np.uint8, count=cols * rows * channels))
np_canny = np_canny.reshape((rows, cols, 3))
cv2.imshow("q", np_canny)
cv2.waitKey(0)

End

參考:Python調用c++的動態dll中數據映射(Mat類型傳遞及結構體傳遞)


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved