YOLOv2 C代码向Python脚本发布边界框数据编译报错求助
先看你的编译错误,大部分来自拼写错误和Python库链接不完整,还有代码逻辑的小问题,一步步来解决:
1. 修正C代码里的Python API拼写错误
你的代码里有几处Python API函数名大小写错误,这是导致undefined reference的直接原因:
- 把
pyTuple_SetItem改成PyTuple_SetItem(大写P),Python C API所有函数都是大写开头的标准命名 - 把
pyObject_CallMethod改成PyObject_CallMethod(大写P)
修改后的对应代码段:
//Setting the four arguments for the put() function PyObject* pythonArgument; pythonArgument = PyTuple_New(4); PyTuple_SetItem(pythonArgument, 0, pyVal[0]); PyTuple_SetItem(pythonArgument, 1, pyVal[1]); PyTuple_SetItem(pythonArgument, 2, pyVal[2]); PyTuple_SetItem(pythonArgument, 3, pyVal[3]); //Calling put() pyFunc = PyObject_CallMethod(pyModule, pyArgs[3], "O", pythonArgument);
另外,PyObject_CallMethod的参数格式需要注意:第三个参数是格式字符串,后面跟对应参数,所以要加上"O"来表示传入一个对象参数。
2. 修正Python初始化逻辑
你的draw_detections函数里每次都调用Py_Initialize()和Py_Finalize(),这不仅低效,还会导致Python环境重复初始化的问题。应该把Py_Initialize()移到initialize()函数里,只执行一次:
void initialize(){ //先初始化Python环境,只执行一次 Py_Initialize(); //Setting the Path PySys_SetPath(pyArgs[0]); //Importing pynetworktables PyObject* pyName = PyString_FromString(pyArgs[1]); pyModule = PyImport_Import(pyName); Py_DECREF(pyName); //释放引用,避免内存泄漏 //Calling init() PyObject* initFunc = PyObject_GetAttrString(pyModule, pyArgs[2]); if(initFunc && PyCallable_Check(initFunc)){ PyObject_CallObject(initFunc, NULL); Py_DECREF(initFunc); } }
然后在draw_detections里去掉Py_Initialize()和Py_Finalize(),可以在程序退出前(比如main函数结束时)统一调用Py_Finalize()。
3. 确保Makefile正确链接Python库
看你的编译输出,LDFLAGS里没有包含Python的链接参数,虽然Makefile里定义了PYTHON=1,但链接顺序有问题。修改Makefile里的$(EXEC)规则:
$(EXEC): $(EXECOBJ) $(ALIB) $(CC) $(COMMON) $(CFLAGS) $^ -o $@ $(LDFLAGS)
原来的命令重复加了$(ALIB),导致链接顺序错误,库应该放在编译对象之后。另外确认你的Python路径(Python2.7的aarch64架构路径)是正确的。
4. 修正Python脚本的变量作用域与参数错误
你的run_network.py里,init()函数的table是局部变量,put()函数无法访问,而且putNumber的调用格式错误,修正如下:
from networktables import NetworkTables table = None # 定义全局变量 def init(): global table # 声明使用全局变量 NetworkTables.initialize('10.13.39.2') table = NetworkTables.getTable('Root') def put(left, right, top, bot): # 参数顺序和C代码传入的保持一致 if table is not None: table.putNumber("left", left) table.putNumber("right", right) table.putNumber("top", top) table.putNumber("bot", bot)
注意:putNumber需要传递键名和对应数值两个参数,你原来的写法缺少键名,会导致运行时错误。
5. 其他优化细节
- 释放Python对象的引用,比如
Py_DECREF(pyLeft)、Py_DECREF(pythonArgument)等,避免内存泄漏 PyInt_FromSize_t:如果Python2.7中没有这个函数,可以换成PyInt_FromLong((long)left),因为left是int类型,转成long更安全
做完这些修改后,执行make clean && make重新编译,应该就能解决编译错误,成功将边界框数据传到Python脚本中。
内容的提问来源于stack exchange,提问作者Guy997

