sudo apt-get install python3
在安装过程中会遇到一些问题sudo pip3 install --upgrade pip
sudo apt-get install python3-scipy
或者pip3 install scipy
。这里吃了不少苦头,就是用前一条命令能安装上,用后面这条就不行。还有就是必须在liunx机器上直接安装才能成功,而通过远程的方式就不行。也许是因为我在linux机器上装之前执行了sudo root。这里还不清楚原因,记录一下。有时候尽管更换了源,仍然无法成功执行sudo apt-get install python3-scipy
或者pip3 install scipy
。这时候就需要进行离线安装。离线安装之前需要确定这么几件事:
(1)确定linux机器是32位的还是64位的。在linux终端上输入getconf LONG_BIT
确认。
(2)确定自己安装的Python版本:在终端输入python3,可以看到python3的版本。
(3)补充:尽管树莓派也是linux系统,但是由于嵌入式设备的构架和普通电脑的构架不一样,导致某些安装方法并不能通用。比如树莓派很难通过whl文件安装包,大多数都是通过源码安装。对于opencv-python来说,一般的linux机器可以直接安装,但是由于树莓派(我用的Nano pi)等嵌入式设备可能不是arm,因此没有与之匹配的opencv-python安装包,因此只能使用源码安装。
参考https://blog.csdn.net/weixin_34148456/article/details/94106195。
https://www.cnblogs.com/freeweb/p/5794447.html
https://blog.csdn.net/llfjcmx/article/details/81238766?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
https://blog.csdn.net/YZXnuaa/article/details/79137762?utm_source=blogxgwz2
关于下载opencv安装包,可以参考https://www.bzblog.online/wordpress/index.php/2020/03/09/opencvdownload/
我的机器上已经安装了opencv4.1,但是我的python脚本需要opencv3的版本。而且经过尝试,虽然机器已经装了opencv4.1和python解释器,但是import cv2失败。此外我的numpy版本较低,不支持高版本的opencv。但是已有的C++程序框架又是基于opencv4的。各种原因,导致我不得不在机器上再次安装一个opencv3,涉及到多版本opencv共存的问题。经过尝试以后,探索出一条安装方法:
unzip opencv-3.4.2.zip
mkdir release
sudo apt-get install build-essential cmake libgtk2.0-dev pkg-config python-dev python-numpy libavcodec-dev libavformat-dev libswscale-dev
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local/opencv32 -D PYTHON_EXECUTABLE=/usr/lib/python3.6..
代码部分参考多篇博客:
https://blog.csdn.net/iamqianrenzhan/article/details/86516440
https://blog.csdn.net/fireflychh/article/details/77413005
https://blog.csdn.net/xranmail/article/details/84759553
https://blog.csdn.net/qq_42517195/article/details/80769974?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.nonecase
cmakelist
cmake_minimum_required(VERSION 3.10)
project(counting)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenCV 3.2 REQUIRED)#找到opencv源
set(OpenCV_INCLUDE_DIRS ${OpenCV_INSTALL_PATH})
INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
#LINK_LIBRARIES(${OpenCV_LIBS})
#include_directories(/usr/local/include)
#link_directories(/usr/local/lib)
find_package(PythonLibs 3.6 REQUIRED)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})
link_directories(${PYTHON_LIBRARY_DIRS})
#include_directories(/usr/include/python3.6)#添加头文件目录,相当于g++ -I参数
#link_directories(/usr/lib/python3.6)#动态链接库或静态链接库的搜索路径,相当于gcc的-L参数
add_executable(counting c_call_python.cpp)
target_link_libraries(counting ${OpenCV_LIBS})#添加opencv链接选项
target_link_libraries(counting ${PYTHON_LIBRARIES})#添加链接库,相同于指定gcc -l参数
C++主程序:(由于涉及到需要对大量指针进行内存释放以避免内存泄露,因此没有将一些功能封装成函数。此外程序的稳定性和内存泄漏问题仍需要进行测试)
#include "Python.h"
#include
#include
#include
using namespace cv;
using namespace std;
int main() {
// 初始化-----------------------------------------------
Py_Initialize();
cout << "Python start --------------------" << endl;
if (!Py_IsInitialized()) {
cout << "Python start defeat--------------------" << endl;
return -1;
}
// 加载python文件----------------------------------------------
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('../')"); // demo_test.py的路径,这里与c_call_python放在同一个目录下
PyObject *moduleName = PyUnicode_FromString("demo_test"); //载入名为demo_test.py的文件
PyObject *pModule = PyImport_Import(moduleName);
if (!pModule) { //如果不存在改文件,则结束
printf("can't find python file");
Py_Finalize(); //关闭python解释器
return -1;
}
PyObject *pFunc = PyObject_GetAttrString(pModule, "run"); //获取函数
if (!pFunc)
{
printf("can't find function [run]");
Py_Finalize();
return -1;
}
// 循环执行任务-------------------------------------------------------
int *a;
for (int i = 1; i<10000000; i++) {
cout << i << endl;
// 读取图片---------------------------------------------------
Mat img = imread("../su.jpg"); // 读取图片
if (img.empty())
{
cout << "img read wrong" << endl;
Py_Finalize();
return -1;
}
cout << img.size() << endl;
// CV::Mat 转 python numpy------------------------------------
auto sz = img.size(); // 获取图像的尺寸
int x = sz.width;
int y = sz.height;
int z = 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(i);
// operates on each pixel
for (int j = 0; j < iCols; j++)
{
CArrays[++id] = p[j];//连续空间
}
}
import_array1(-1);
npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
// 准备其他python函数需要的参数
//...
// 将图片以及其他参数进行封装
PyObject *ArgList = PyTuple_New(1); //参数列表:创建一个长度为1的元组
PyTuple_SetItem(ArgList, 0, PyArray); //将PyArray的引用指向元组ArgList的第0个元素
PyObject *pReturn = PyObject_CallObject(pFunc, ArgList);
if (pReturn == NULL) {
printf("Return value is NULL.");
Py_Finalize();
return -1;
}
PyArrayObject *Py_array1;
//读取从python脚本返回的numpy值
//查看是否是元组数据
if (PyTuple_Check(pReturn)) {
//当返回值不止一个,pReturn是一个元组
PyArg_UnpackTuple(pReturn, "ref", 2, 2, &Py_array1, &a); //解析元组的内容
//获取矩阵维度
npy_intp *Py_array1_shape = PyArray_DIMS(Py_array1); //获取元组第一个元素(矩阵)的大小
npy_intp array1row = Py_array1_shape[0];
npy_intp array1col = Py_array1_shape[1];
npy_intp array1high = Py_array1_shape[2];
Mat mask(array1row, array1col, CV_8UC3, PyArray_DATA(Py_array1));
imwrite("../cut.jpg", mask);
// Py_XDECREF(PyArray);
/*这里Py_XDECREF(ArgList); 和 Py_XDECREF(PyArray);不能同时使用,否则会引起内存访问冲突
* 我的理解是:PyTuple_SetItem并不复制数据,只是引用的复制。因此对这两个对象中的任意一个使用
* Py_XDECREF都可以回收对象。使用两次的话反而会导致冲突。
*/
Py_XDECREF(ArgList);
delete[] CArrays; // 释放数组内存,最好在PyArray被使用完以后释放
CArrays = nullptr;
Py_XDECREF(pReturn);
// delete(Py_array1);
// imshow("su", mask);
// waitKey(0);
mask.release();
}
}
// Py_CLEAR(moduleName);
// Py_CLEAR(pModule);
Py_XDECREF(moduleName);
Py_XDECREF(pModule);
Py_XDECREF(pFunc); //Py_XDECREF是很有必要的,为了避免内存泄漏
Py_Finalize(); // 关闭Python
return 0;
}
python函数:
#coding:utf-8
import cv2
import numpy as np
def run(imgdata):
print(imgdata.shape)
a, b = imgdata.shape[0], imgdata.shape[1]
result = imgdata[0: a>>1, 0:b>>1]
print(result.shape)
#cv2.imshow("img", img)
#cv2.waitKey(0)
return result, 0