首页 > 解决方案 > 在 C++ 程序中嵌入 python-opencv 的问题(单张图片正常,但在网络摄像头上失败)

问题描述

我正在努力使我的 C++ 程序可以嵌入 python 脚本,以便我可以在外部修改图像处理代码。

我设法让它可以在单张图片上运行,

但是当我尝试捕获连续图片并执行图像处理时,它失败了。

你能帮帮我吗?

我的环境是:

以下是我的源代码。

Qt 项目文件:testPyScript.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 += \
        Python_wrapper.cpp \
        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

HEADERS += \
    Python_wrapper.h

# Python
INCLUDEPATH += "C:/Python/Python38-32/include"
LIBS += -L"C:/Python/Python38-32/libs" \
        -lpython38 \
        -lpython3

#numpy
INCLUDEPATH +="C:/Python/Python38-32/Lib/site-packages/numpy/core/include"


# opencv
INCLUDEPATH += "C:/opencv/include"
CONFIG(debug, debug|release) {
LIBS += -L"C:/opencv/lib/Debug" \
        -lopencv_core420d \
        -lopencv_highgui420d \
        -lopencv_imgcodecs420d \
        -lopencv_imgproc420d \
        -lopencv_videoio420d
}
CONFIG(release, debug|release) {
LIBS += -L"C:/opencv/lib/Release" \
        -lopencv_core420 \
        -lopencv_highgui420 \
        -lopencv_imgcodecs420 \
        -lopencv_imgproc420 \
        -lopencv_videoio420
}

Python_wrapper.h

#ifndef PYTHON_WRAPPER_H
#define PYTHON_WRAPPER_H
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#include <numpy/arrayobject.h>
#include <opencv2/core.hpp>

extern PyObject *pyModule,*pyFunc;

bool init_python();
void end_python();
PyObject* convertImage(const cv::Mat& image) ;
std::string type2str(int type) ;
#pragma pop_macro("slots")
#endif // PYTHON_WRAPPER_H

Python_wrapper.cpp

#include"Python_wrapper.h"
#include<fstream>
#include<QDebug>
#include <sys/stat.h>

PyObject *pyModule=nullptr;
PyObject *pyFunc=nullptr;

bool IsPathExist(const std::string &s)
{
  struct stat buffer;
  return (stat (s.c_str(), &buffer) == 0);
}

bool init_python()
{
    if (!Py_IsInitialized())
    {
        //set python path
        std::ifstream infile;
        infile.open("PYTHON_PATH",std::ios::in);
        if(infile)
        {
            qDebug()<<"Given python_path file."<<endl;
            std::string python_path;
            infile>>python_path;
            infile.close();
            qDebug()<<"Given python path:"<<python_path.c_str()<<endl;
            // check path if exists
            if(!IsPathExist(python_path))
            {
                qDebug()<<"Can not find given python path."<<endl;
                return false;
            }
            std::string env = getenv("PATH");
            env += ";"+python_path;
            putenv(env.c_str());
        }
        else
        {
            qDebug()<<"No specify on python path. Default python will be used."<<endl;
        }
        qDebug()<<"Py_Initialize..."<<endl;
        Py_Initialize();
        if(Py_IsInitialized())
            qDebug()<<"Py_Initialize. OK."<<endl;
        else
        {
            qDebug()<<"Failed to initialize Python."<<endl;
            return false;
        }
        qDebug()<<"Python version:"<<Py_GetVersion()<<endl;

        //add current folder to module serach parth
        QString modulePath=QString::fromWCharArray(Py_GetPath());
        qDebug()<<"Module search path:"<<modulePath<<endl;
        //import modoule
        qDebug()<<"Import python module <py_cv>..."<<endl;
        pyModule = PyImport_ImportModule("py_cv");
        if (pyModule == nullptr)
        {
            qDebug()<<"Failed to load python module <py_cv>"<<endl;
            PyErr_Print();
            return false;
        }
        //import module function
        qDebug()<<"Import python function <test>"<<endl;
        pyFunc =PyObject_GetAttrString(pyModule,"test");

        if (pyFunc == NULL)
        {
            qDebug()<<"Failed to load python function <test>"<<endl;
            PyErr_Print();
            return false;
        }
    }
    import_array();
}


void end_python()
{
    if(Py_IsInitialized())
        Py_Finalize();
}

PyObject* convertImage(const cv::Mat& image) {

    //2D image with 3 channels.
    npy_intp dimensions[3] = {image.rows, image.cols, image.channels()};

    //image.dims = 2 for a 2D image, so add another dimension for channels.
    return PyArray_SimpleNewFromData(image.dims + 1, (npy_intp*)&dimensions, NPY_UINT8, image.data);
}

std::string type2str(int type) {
  std::string r;

  uchar depth = type & CV_MAT_DEPTH_MASK;
  uchar chans = 1 + (type >> CV_CN_SHIFT);

  switch ( depth ) {
    case CV_8U:  r = "8U"; break;
    case CV_8S:  r = "8S"; break;
    case CV_16U: r = "16U"; break;
    case CV_16S: r = "16S"; break;
    case CV_32S: r = "32S"; break;
    case CV_32F: r = "32F"; break;
    case CV_64F: r = "64F"; break;
    default:     r = "User"; break;
  }

  r += "C";
  r += (chans+'0');

  return r;
}

主文件

#include "Python_wrapper.h"
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

#include<iostream>

int py_image_process(cv::Mat &img)
{
    int ierr=-1;
    std::cout<<"MatToNDArray"<<std::endl;
    PyObject *pyMat =convertImage(img);

    std::cout<<"Image type:"<<type2str(img.type()).c_str()<<std::endl;
    double d=100.0;
    PyObject *pyArgs = PyTuple_New(2);
    PyObject* pyD=PyFloat_FromDouble(d);
    PyTuple_SetItem(pyArgs,0, pyMat);
    PyTuple_SetItem(pyArgs,1,pyD);

    PyObject *pyValue= PyObject_CallObject(pyFunc, pyArgs);

    if (pyValue != NULL)
    {
        std::cout<<"Function performed OK"<<std::endl;
        if (PyTuple_Check(pyValue))
        {
            std::cout<<"Check PyValue as Tuple OK"<<std::endl;
            ierr = PyLong_AsLong(PyTuple_GetItem(pyValue, 0));
            PyObject* bytes = PyTuple_GetItem(pyValue, 1);
            std::string msg = PyUnicode_AsUTF8(bytes);
            std::cout<<"msg:"<<msg.c_str()<<std::endl;
        }
        Py_DECREF(pyValue);
    }
    else
        std::cout<<"Failed to perform function"<<std::endl;
    Py_XDECREF(pyArgs);
    return ierr;
}

int main()
{
    int ierr=-1;
    std::cout<<"Test embeded python"<<std::endl;

    if(!init_python())
    {
        end_python();
        return 2;
    }

    cv::VideoCapture cap =cv::VideoCapture(0);

//    cv::Mat img =cv::imread("0.jpg",cv::IMREAD_COLOR);
    cv::Mat img;
    for(;;)
    {
        cap.read(img);
        if(!img.empty())
        {
//            ierr= py_image_process(img);
            cv::imshow("image",img);
        }
        else
            break;

        if(cv::waitKey(5)>=0) break;
    }
    cv::destroyAllWindows();
    return ierr;

}

和python测试脚本:py_cv.py

import cv2
import numpy as np

def test(img,d):
    print(type(img),type(d))
    rows,cols,chs=img.shape
    cx,cy=int(rows/2),int(cols/2)
    d=int(d/2.0)
    cv2.circle(img,(cx,cy),d,(0,255,0),2)
    return -99,"test message"

非常感谢您的帮助。

标签: pythonc++opencv

解决方案


查看OpenCv 文档中针对 VideoCapture给出的示例。

//--- INITIALIZE VIDEOCAPTURE
VideoCapture cap;
// open the default camera using default API
// cap.open(0);
// OR advance usage: select any API backend
int deviceID = 0;             // 0 = open default camera
int apiID = cv::CAP_ANY;      // 0 = autodetect default API
// open selected camera using selected API
cap.open(deviceID + apiID);

// check if we succeeded
if (!cap.isOpened()) {
    cerr << "ERROR! Unable to open camera\n";
    return -1;
}

上面的代码是其中的一个小片段。

似乎您没有打开 VideoCapture,也没有通过在 main.cpp 中使用来检查它是否已正确isOpened()初始化main()


推荐阅读