基於ubuntu系統qt軟件C++/Python混編

目錄

1.安裝qt軟件

2. python解釋器

3. 配置qt .pro文件

4.使用C++掉用python腳本


 

系統:Ubuntu16.04LTS

編譯器:qt5.x

python: ubuntu系統自帶3.x版本

1.安裝qt軟件

建議通過安裝包方式安裝,通過apt的方式安裝會有一點問題

2. python解釋器

不要使用anaconda,我使用anaconda環境創建的python,使用C++調用python時會出現一些問題,比如在python中無法導入第三方庫,比如numpy, cv2, twnsorflow等等。

使用系統默認自帶的,如果系統沒有,則直接安裝python,並將python默認安裝在usr路徑下

3. 配置qt .pro文件

1. 先創建一個qt C++工程,將頭文件,源文件,python文件都加載進來

2. 將python頭文件和路徑加載進來

庫文件: usr/lib/python3.5/config-3.5m-x86_64-linux-gnu  然後選擇libpython3.5m.a

 包含路徑:/usr/include/python3.5

 將這兩個路徑弄好後,後面還需要將兩個庫手動加入。

python庫路徑圖

可以看到上圖第一行最後有三個庫,第一個python3.5m是前面添加的,最後兩個dl, util需要手動加上,手打加上就可以,不加也可以,主要爲了防止可能出現的錯誤。

如果要使用tensorflow,或別的深度學習框架,需要調用cuda, 需要將cuda 的路徑也加載進來

 qt .pro整體配置如下:

QT -= gui

CONFIG += c++11 console
CONFIG -= app_bundle

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

#cuda cudnn
INCLUDEPATH += /usr/local/cuda/include

LIBS += -L/usr/local/cuda/lib64
LIBS += -lcudart -lcublas -lcurand

DISTFILES += \
    obj.py \
    other.py

unix:!macx: LIBS += -L$$PWD/../../../../usr/lib/python3.5/config-3.5m-x86_64-linux-gnu/ -lpython3.5m  -ldl -lutil

INCLUDEPATH += $$PWD/../../../../usr/include/python3.5
DEPENDPATH += $$PWD/../../../../usr/include/python3.5

unix:!macx: PRE_TARGETDEPS += $$PWD/../../../../usr/lib/python3.5/config-3.5m-x86_64-linux-gnu/libpython3.5m.a

4.使用C++掉用python腳本

這部分代碼網上比較多,我就不說了,我因爲做深度學習,網絡等東西都是使用python寫的,後面項目集成需要在c++上,所以打算使用C++代碼調用python

我的項目要求在C++文件中讀取視頻或相機,獲取每一幀圖像,將每幀mat 類數據圖像發送到python腳本中,然後通過python運行神經網絡,獲取預測結果,最後將結果保存在一個列表中,返回列表。並且要循環調用python腳本,因爲讀取的是視頻或相機,而不是一張圖片。

具體代碼如下:

//c_tf/main.cpp
#include <QCoreApplication>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Python.h>
#include <vector>
#include <string>
#include <time.h>
#include <numpy/arrayobject.h>
using namespace std;
uchar *CArrays = nullptr;
PyObject *ArgArray = nullptr;
struct boxes{
    int x_min = 0;
    int y_min = 0;
    int x_max = 0;
    int y_max = 0;
    int label = 0;
};
vector<boxes> object_detection(0);
clock_t start,finish;
int main()
{
    //初始化python文件,寫在首行
    Py_Initialize();
    import_array();
    if(!Py_IsInitialized())
    {
        //print("initialize failed")
        cout<<"initialize failed"<<endl;
        return -1;
    }
    else
    {
        cout<<"initialize success"<<endl;
    }

    // 導入pyhton文件路徑
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("import os");
    std::cout << std::string(Py_GetVersion()) << "\n";
    PyRun_SimpleString("sys.path.append('/home/chen/CPython_project/c_tf/')");  //python path
    PyRun_SimpleString("sys.path.append('/usr/local/lib/python3.5/dist-packages/')");
    // 加載python文件,傳入需要加載的python文件名
    PyRun_SimpleString("print('success')");
    PyRun_SimpleString("print(os.getcwd())");
    PyRun_SimpleString("print(sys.executable)");
    PyObject *pModule = nullptr;
    PyObject *pDict = nullptr;

    pModule = PyImport_ImportModule("vgg_detec");//調用python腳本
    if (!pModule)
    {
        PyErr_Print();
        return -1;
    }
    else
    {
        cout<<"load module success"<<endl;
    }
    // 讀取視頻
    cv::VideoCapture cap("/home/chen/CPython_project/one1.mp4");
    cv::Mat img;
    while (cap.isOpened())
    {
        start = clock();
        cap >> img;
        if (img.empty())
            break;
        resize(img, img, cv::Size(30,30));

        // 處理圖片數據,傳遞給python腳本
        auto sz = img.size();
        int x = sz.width;
        int y = sz.height;
        int z = img.channels();
        cout<<"size:"<<sz<<" width:"<<x<<" height:"<<y<<" channels:"<<z<<endl;
        CArrays = new uchar[x*y*z];//這一行申請的內存需要釋放指針,否則存在內存泄漏的問題
        int iChannels = img.channels();
        int iRows = img.rows;
        int iCols = img.cols * iChannels;
        if (img.isContinuous())
        {
            iCols *= iRows;
            iRows = 1;
        }

        uchar* p;
        int id = -1;
        for (int i = 0; i < iRows; i++)
        {
            // get the pointer to the ith row
            p = img.ptr<uchar>(i);
            // operates on each pixel
            for (int j = 0; j < iCols; j++)
            {
                CArrays[++id] = p[j];//連續空間
            }
        }

        npy_intp Dims[3] = {y, x, z}; //注意這個維度數據!
        PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
        delete[] CArrays;
        pDict = PyModule_GetDict(pModule);
        ArgArray = PyTuple_New(1);
        PyTuple_SetItem(ArgArray, 0, PyArray);
        PyObject *pFunc = PyDict_GetItemString(pDict, "recognize");
        // 沒有返回數據
        // PyEval_CallObject(pFunc, ArgArray);
        // 有返回數據
        PyObject *pResult = PyObject_CallObject(pFunc, ArgArray);//調用函數,傳入Numpy Array 對象。
        int size = PyList_Size(pResult);
        object_detection.clear();
        PyObject *list_item = nullptr;
        float upper_left_coord_x;
        float upper_left_coord_y;
        float lower_right_coord_x;
        float lower_right_coord_y;
        int label;
        int num_object = size / 5;
        for (int i = 0; i < num_object; i++)
        {
            boxes result_temp;
            list_item = PyList_GetItem(pResult, 5 * i + 0);
            PyArg_Parse(list_item, "d", &upper_left_coord_x);
            result_temp.x_min = static_cast<int>(upper_left_coord_x);
            list_item = PyList_GetItem(pResult, 5 * i + 1);
            PyArg_Parse(list_item, "d", &upper_left_coord_y);
            result_temp.y_min = static_cast<int>(upper_left_coord_y);
            list_item = PyList_GetItem(pResult, 5 * i + 2);
            PyArg_Parse(list_item, "d", &lower_right_coord_x);
            result_temp.x_max = static_cast<int>(lower_right_coord_x);
            list_item = PyList_GetItem(pResult, 5 * i + 3);
            PyArg_Parse(list_item, "d", &lower_right_coord_y);
            result_temp.y_max = static_cast<int>(lower_right_coord_y);
            list_item = PyList_GetItem(pResult, 5 * i + 4);
            PyArg_Parse(list_item, "i", &label);
            result_temp.label = label;
            object_detection.push_back(result_temp);
        }
        int num = object_detection.size();
        std::cout<<"得到的目標值數量:"<<num<<std::endl;
        finish = clock();
        double time_s = static_cast<double>((finish - start)) / CLOCKS_PER_SEC;
        double time_ms = time_s * 1000.0;
        std::cout << "預測一次的時間:"<<time_ms<<" ms"<< std::endl;
        std::cout << "預測一次的時間:"<<time_s<<" s"<< std::endl;

    }
    PyObject *pFunc = PyObject_GetAttrString(pModule, "close_session");
    PyEval_CallObject(pFunc, NULL);
    PyErr_Print();
    Py_DECREF(ArgArray);
    Py_DECREF(pDict);
    Py_DECREF(pModule);
    Py_Finalize();
    return 0;
}

python代碼:

#import matplotlib.pyplot as plt
import tensorflow as tf
import  numpy as np
#import PIL.Image as Image
import cv2
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true"
#from skimage import transform
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.1)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))
pb_file_path="/home/chen/CPython_project/default_python/model/catdog.pb"
W = 224
H = 224
list_results = []
# 將模型讀取到默認的圖中
with tf.gfile.GFile(pb_file_path, 'rb') as fd:
    _graph = tf.GraphDef()
    _graph.ParseFromString(fd.read())
    tf.import_graph_def(_graph, name='')

detection_graph = tf.get_default_graph()
sess = tf.Session(graph=detection_graph)

def recognize(img):
    del list_results[:]
    global x_min,x_max,y_min,y_max
    x_min = 16.0
    x_max = 39.0
    y_min = 56.7
    y_max = 73.4
    confidence_level = 4
    box1 = [x_min, y_min, x_max, y_max, confidence_level]
    box2 = [x_min+2, y_min-2, x_max+10, y_max+40, confidence_level + 5]
    box = [box1, box2]
    for i in range(2):
        list_results.append(box[i][0])
        list_results.append(box[i][1])
        list_results.append(box[i][2])
        list_results.append(box[i][3])
        list_results.append(box[i][4])
    img = cv2.resize(img, (H, W))
    img = img * (1.0 /255)
    input_x = detection_graph.get_tensor_by_name("input:0") ####這就是剛纔取名的原因
    out_softmax = detection_graph.get_tensor_by_name("softmax:0")
    out_label = detection_graph.get_tensor_by_name("output:0")
    img_out_softmax = sess.run(out_softmax, feed_dict={input_x:np.reshape(img, [-1, H, W, 3])})
    print ("img_out_softmax:",img_out_softmax)
    prediction_labels = np.argmax(img_out_softmax, axis=1)
    print ("prediction_labels:",prediction_labels)

    print("list_results len:", len(list_results))
    return list_results
def close_session():
    print('close tf.session!')
    sess.close()
#def recognize(img):
#    with tf.Graph().as_default():
#        output_graph_def = tf.GraphDef()
        
#        with open(pb_file_path, "rb") as f:
#            output_graph_def.ParseFromString(f.read()) #rb
#            _ = tf.import_graph_def(output_graph_def, name="")
 
#        with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:
#            tf.global_variables_initializer().run()
 
#            input_x = sess.graph.get_tensor_by_name("input:0") ####這就是剛纔取名的原因
#            print (input_x)
#            out_softmax = sess.graph.get_tensor_by_name("softmax:0")
#            print (out_softmax)
#            out_label = sess.graph.get_tensor_by_name("output:0")
#            print (out_label)
 
#            #img = cv2.imread(jpg_path)
#            img = cv2.resize(img, (H, W))
 
#            #plt.figure("fig1")
#            #plt.imshow(img)
#            img = img * (1.0 /255)
#            img_out_softmax = sess.run(out_softmax, feed_dict={input_x:np.reshape(img, [-1, H, W, 3])})
 
#            print ("img_out_softmax:",img_out_softmax)
#            prediction_labels = np.argmax(img_out_softmax, axis=1)
#            print ("prediction_labels:",prediction_labels)
 
            #plt.show()
 
if __name__ == "__main__":
	img = cv2.imread("/home/chen/CPython_project/default_python/a/cat/cat.12.jpg")
	recognize(img)  ####修改成自己的圖片路徑

最後感謝xia_xia_mg的博客,給了我很大的幫助《https://blog.csdn.net/xia_xia_mg/article/details/80065284

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章