在 C++ 程序中嵌入 python-opencv 的问题(单张图片正常,但在网络摄像头上失败)
Posted
技术标签:
【中文标题】在 C++ 程序中嵌入 python-opencv 的问题(单张图片正常,但在网络摄像头上失败)【英文标题】:Problem of embedding python-opencv in C++ program(OK for single picture, but failed on web camera) 【发布时间】:2020-02-26 02:41:22 【问题描述】:我正在努力让我的 C++ 程序可以嵌入 python 脚本,以便我可以在外部修改图像处理代码。
我已经设法让它可以在单张图片上运行,
但是当我尝试捕捉连续图片并进行图像处理时,它失败了。
你能帮帮我吗?
我的环境是:
Windows 10,Python 版本:3.8.1(32 位)和对应的 numpy Visual Studio 2019 v16.4.3 [vcvarsall.bat] 环境初始化为:'x86' Qt creator 5.14(MSVC 2017,32 bit) 及其 qmake 作为我的 IDE以下是我的源代码。
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;
main.cpp
#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"
非常感谢您的帮助。
【问题讨论】:
【参考方案1】:看看OpenCv documentation for 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 中的 main()
中使用 isOpened()
来检查它是否已正确初始化。
【讨论】:
感谢您的建议。最后,我检查了我的程序,发现我上面的代码可以正常工作。但是当我在 Qt 线程(C++)中使用 move 它时,发生了一些错误。在多线程应用程序中嵌入 python 似乎很困难。我不得不放弃。非常感谢。【参考方案2】:最后,我检查了我的程序,发现我上面的代码可以正常工作。但是当我在 Qt 线程(C++)中使用 move 它时,发生了一些错误。在多线程应用程序中嵌入 python 似乎很困难。
【讨论】:
以上是关于在 C++ 程序中嵌入 python-opencv 的问题(单张图片正常,但在网络摄像头上失败)的主要内容,如果未能解决你的问题,请参考以下文章