1. 程式人生 > >【機器學習】C++與OpenCV、Tensorflow-python聯合呼叫

【機器學習】C++與OpenCV、Tensorflow-python聯合呼叫

  上一篇我介紹了C++呼叫Python的入門方法。這一篇我講述C++與OpenCV、Tensorflow-python聯合呼叫的一次成功的實驗過程。
  C++通過python呼叫tensorflow,比呼叫C++版本的tensorflow的優勢在於:tensorflow環境依賴python環境,python環境幾乎是一鍵傻瓜式操作,各種庫依賴的問題,比直接使用tensorflow-C++少得多,只要python配置好了,C++專案根本不需要單獨配置tensorflow,完全靠python模組。在C++專案配置中,根本不需要新增tensorflow的include標頭檔案目錄和庫目錄。
  OpenCV是一個通用的計算機視覺庫,C++版本幾乎是傻瓜式編譯,最後只輸出opencv_world310d.lib / opencv_world310.lib庫檔案,和 opencv_world310d.dll / opencv_world310.dll動態連結庫,標頭檔案只需要包含#include <opencv2/opencv.hpp>

,可以說OpenCV-C++配置相當簡單。
  在C++專案中配置好python,numpy和OpenCV之後,就可以開始寫測試程式碼了:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <Python.h>  
#include <numpy/arrayobject.h>
#include <string>  
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main(int
argc, char *argv[]) { Py_InitializeEx(1); //初始化 python import_array(); if (!Py_IsInitialized()) { cout << "initialized error" << endl; return -1; } PyObject* sys = PyImport_ImportModule("sys"); std::cout << std::string(Py_GetVersion()) << "\n"
; PyRun_SimpleString("import sys"); // 執行 python 中的短語句 PyRun_SimpleString("print('come in python')"); PyRun_SimpleString("sys.path.append('./')"); PyObject *pModule(0), *pDct(0); pModule = PyImport_ImportModule("tfTest"); if (!pModule) { PyErr_Print(); cout << "can not find pytest.py" << endl; return -1; } else cout << "open Module" << endl; cv::Mat oimg = cv::imread("camera.jpg", cv::IMREAD_UNCHANGED); cv::Mat img; cv::cvtColor(oimg, img, cv::COLOR_BGR2GRAY);//測試灰度圖 auto sz = img.size(); int x = sz.width; int y = sz.height; int z = img.channels(); int xy = x*y; int channel = img.channels(); uchar *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 *pDict = PyModule_GetDict(pModule); PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays); PyObject *PyPath = Py_BuildValue("s", "conv.jpg"); PyObject *ArgArray = PyTuple_New(2); PyTuple_SetItem(ArgArray, 1, PyArray); //同樣定義大小與Python函式引數個數一致的PyTuple物件 PyTuple_SetItem(ArgArray, 0, PyPath); //同樣定義大小與Python函式引數個數一致的PyTuple物件 PyObject *pFunc = PyDict_GetItemString(pDict, "CVSaveImage"); PyObject_CallObject(pFunc, ArgArray);//呼叫函式,傳入Numpy Array 物件。 PyErr_Print(); Py_DECREF(ArgArray); Py_DECREF(pDict); Py_DECREF(sys); Py_DECREF(pModule); Py_Finalize(); delete[] CArrays; return 0; }

  OpenCV讀取的影象是一個連續空間,可以直接賦值給numpy陣列。如果是彩色影象,那麼OpenCV Mat資料格式為一個[3*W,H]的一維陣列,其中每一行資料是按照R,G,B,R,G,B。。。來儲存,和OpenCV-python讀取影象後得到的numpy陣列格式是一致的,因此彩色影象也可以使用上述程式碼轉換為numpy資料。
  python程式碼為:

#coding:utf-8
import tensorflow as tf
import numpy as np
import cv2
def CVSaveImage(path, img1):
    img = img1.reshape([img1.shape[0],img1.shape[1],1,1])
    img = img.transpose(3,0,1,2)
    dia = 5
    kernel = np.ones((dia,dia))/(dia**2.)
    kernel = kernel.reshape([dia,dia,1,1])
    sess = tf.Session()
    A=tf.placeholder("float", shape=[1,img1.shape[0],img1.shape[1],1])
    B=tf.placeholder("float", shape=[dia,dia,1,1])
    initial = tf.random_normal([1,img1.shape[0],img1.shape[1],1]) * 0.256
    X = tf.Variable(initial)
    init = tf.global_variables_initializer()
    sess.run(init)
    X = tf.nn.conv2d(A,B,strides=[1,1,1,1],padding='SAME')
    img2 = sess.run(X,feed_dict={A: img, B:kernel})
    print(img2.shape)
    img2= img2.transpose([1,2,3,0])
    img2= img2.reshape([img1.shape[0],img1.shape[1]])
    cv2.imwrite(path,img2) 

  這裡我預設使用了灰度圖來進行處理,channel通道始終是1。這個程式碼的功能是把影象進行一次均值濾波,得到結果:
  這裡寫圖片描述
  這裡寫圖片描述
  這裡寫圖片描述
  至此,C++與OpenCV、Tensorflow-python聯合呼叫完成。
  影象黑邊是我截圖的問題,原圖是沒有的。