python - 在 C++ 程序中嵌入 python-opencv 的问题(单张图片正常,但在网络摄像头上失败)
问题描述
我正在努力使我的 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;
}
主文件
#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"
非常感谢您的帮助。
解决方案
查看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()
。
推荐阅读
- javascript - Flickity:未捕获的 TypeError:无法读取 null 的属性“querySelectorAll”
- flutter - Flutter:device_apps包圆圈图标问题
- c - 为什么我在函数 addRandomNumbers 中出现错误?
- javascript - 如何下载 React 组件的一部分?
- css - CSS:为外部超链接添加图标,但当图像是超链接时不添加
- linux - 无法在 M1 macbook 上安装 Chromium inisde docker 容器
- javascript - 即使依赖项一直没有改变,useEffect 钩子也会变成无限循环
- python - 如何根据其他两列的匹配项添加列?
- ios - 如何为我以自己的自定义格式保存的每个文件添加自定义缩略图
- android - 为什么安装系统信任证书后看不到任何 https 流量?