如何从C主函数调用OpenCV C++ API并解决编译报错问题
问题与解决方案
问题背景
现有C语言编写的应用程序,需调用OpenCV的C++ API实现图像处理,但OpenCV的C API已被弃用。尝试从C代码调用C++ API时,因头文件包含C专属的opencv2/opencv.hpp,导致C编译器编译主程序失败,且无法用g编译主程序(依赖大量仅支持C编译的库)。
核心问题
- C编译器无法解析C头文件及
cv::Mat这类C专属类型 - 原头文件暴露的
ConnectedComponentsResults结构体包含C++类型,C代码无法处理
解决方案:API隔离与不透明指针
通过**不透明指针(Opaque Pointer)**隐藏C实现细节,让C代码仅与基础C类型交互,C类型完全封装在C++编译单元中。
步骤1:创建纯C兼容的头文件
新建opencv_grouping_c.h,仅保留C语言可识别的内容,用不透明指针替代C++类型:
#ifndef CONNECTED_COMPONENTS_C_H #define CONNECTED_COMPONENTS_C_H #include <stdint.h> // 不透明指针,C代码无需知道内部结构 typedef struct ConnectedComponentsResultsImpl* ConnectedComponentsResults; // C兼容的函数声明,确保C链接 #ifdef __cplusplus extern "C" { #endif // 创建结果对象(C++侧分配内存) ConnectedComponentsResults connected_components_create(); // 执行阈值分割与连通组件分析 void threshold_then_group(uint8_t **image_array, uint32_t SizeY, uint32_t SizeX, double threshold_value, ConnectedComponentsResults results); // 获取连通组件数量 int connected_components_get_num(ConnectedComponentsResults results); // 销毁结果对象(释放C++侧内存) void connected_components_destroy(ConnectedComponentsResults results); #ifdef __cplusplus } #endif #endif
步骤2:修改C++实现文件
更新opencv_grouping.cpp,实现纯C头文件中声明的函数,封装C++逻辑:
#include <stdint.h> #include <cstring> #include <opencv2/opencv.hpp> #include "opencv_grouping_c.h" // 仅C++可见的实际结果结构体 struct ConnectedComponentsResultsImpl { int num_components; cv::Mat labels; cv::Mat stats; cv::Mat centroids; }; extern "C" { ConnectedComponentsResults connected_components_create() { return new ConnectedComponentsResultsImpl(); } void threshold_then_group(uint8_t **image_array, uint32_t SizeY, uint32_t SizeX, double threshold_value, ConnectedComponentsResults results) { uint8_t *image_data = new uint8_t[SizeY * SizeX]; double max_value = 255.0; // 转换2D数组为连续内存 for (int i = 0; i < SizeY; i++) { memcpy(image_data + i * SizeX, image_array[i], SizeX * sizeof(uint8_t)); } cv::Mat image(SizeY, SizeX, CV_8U, image_data); cv::Mat binary; cv::threshold(image, binary, threshold_value, max_value, cv::THRESH_BINARY); int num_components = cv::connectedComponentsWithStats( binary, results->labels, results->stats, results->centroids, 8, CV_32S ); results->num_components = results->stats.rows - 1; delete[] image_data; } int connected_components_get_num(ConnectedComponentsResults results) { return results->num_components; } void connected_components_destroy(ConnectedComponentsResults results) { delete results; } } // extern "C"
步骤3:修改C主函数
更新grouping_test_main.c,使用新的C兼容接口:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdarg.h> #include <malloc.h> #include "opencv_grouping_c.h" uint8_t **allocate_2D_array(uint32_t SizeY, uint32_t SizeX); int free_2D_array(uint8_t **image_array, uint32_t SizeY); int main() { uint32_t SizeY = 19; uint32_t SizeX = 20; uint8_t **image_array; FILE* fimage_array = fopen("./test_array.txt", "r"); double threshold_value = 128; ConnectedComponentsResults results; int i, j; image_array = allocate_2D_array(SizeY, SizeX); // 读取图像数据 for (i = 0; i < SizeY; i++) { for (j = 0; j < SizeX; j++) { fscanf(fimage_array, "%hhd", &image_array[i][j]); } } fclose(fimage_array); // 创建结果对象 results = connected_components_create(); // 调用处理函数 threshold_then_group(image_array, SizeY, SizeX, threshold_value, results); // 获取并打印结果 printf("Number of connected components: %d\n", connected_components_get_num(results)); // 销毁结果对象 connected_components_destroy(results); free_2D_array(image_array, SizeY); return 0; } uint8_t **allocate_2D_array(uint32_t SizeY, uint32_t SizeX) { int i; uint8_t **image_array = malloc(SizeY * sizeof(uint8_t *)); for (i = 0; i < SizeY; i++) { image_array[i] = malloc(SizeX * sizeof(uint8_t)); if (image_array[i] == NULL) { fprintf(stderr, "Memory allocation for image_array[%d] failed.\n", i); exit(EXIT_FAILURE); } } return image_array; } int free_2D_array(uint8_t **image_array, uint32_t SizeY) { int i; for (i = 0; i < SizeY; i++) { free(image_array[i]); } free(image_array); // 补充释放顶层指针 return 1; }
编译命令
# 编译C++实现 g++ `pkg-config --cflags opencv4` -c opencv_grouping.cpp -o opencv_grouping.o # 编译C主程序(无需OpenCV头文件) gcc -c grouping_test_main.c -o grouping_test_main.o # 链接所有目标文件 gcc grouping_test_main.o opencv_grouping.o -lstdc++ `pkg-config --libs opencv4` -o opencv_test2
关键说明
- 不透明指针
ConnectedComponentsResults隐藏了C结构体细节,C代码无需处理cv::Mat等C类型 - C侧统一负责内存分配与释放,避免C代码操作C对象内存
- C主程序编译时不再依赖OpenCV的C++头文件,完全由C编译器处理
内容的提问来源于stack exchange,提问作者Brassard1984
相关产品推荐
相关产品推荐

