CMake、OpenCV 和单元测试

news2024/10/7 20:25:40

在这里插入图片描述我写了很多关于 CMake 的文章,如果你感兴趣,可以点击以下链接阅读:

  • CMake VS Make
  • CMake:在构建世界掀起风暴
  • 现代 CMake 使用技巧
  • CMake 交叉编译
  • CMake 生成器已开启

我们将继续对 CMake 的探索,这篇文章技术性高,且易于实操,我们会练习将 CMake 用于一个实际的项目。我将使用 OpenCV 得到的 CMake 标志显示。听起来就很有意思,话不多说,让我们开始吧。

我们身处何方?

C++ 世界已准备向 C++ 20 跃进。现代 CMake 日趋成熟,在windows 上获取 OpenCV 也只是一些 vcpkg 命令的问题。由于 vcpkg 总是从源代码处编译所有内容,所以与安装器不同,避免了很多兼容性问题。

首先可以参考链接中非常实用的安装说明,安装 vcpkg。在 OpenCV 的编译过程中,将构建和安装以下软件包:

  • libjpeg-turbo[core]:x86-windows -> 2.0.5
  • liblzma[core]:x86-windows -> 5.2.5#2
  • libpng[core]:x86-windows -> 1.6.37#13
  • libwebp[core,nearlossless,simd,unicode]:x86-windows -> 1.1.0#1
  • opencv[core,dnn,jpeg,opengl,png,tiff,webp]:x86-windows -> 4.3.0
  • opencv4[core,dnn,jpeg,opengl,png,tiff,webp]:x86-windows -> 4.3.0#4
  • opengl[core]:x86-windows -> 0.0#8
  • protobuf[core]:x86-windows -> 3.14.0
  • tiff[core]:x86-windows -> 4.1.0
  • zlib[core]:x86-windows -> 1.2.11#9

使用 vcpkg 编译OpenCV 需要一些时间,因为上面的所有依赖项也将从源代码处编译。因此,在 OpenCV 编译过程中要有耐心,具体有下面十个步骤:

  • Starting package 1/10: libjpeg-turbo:x86-windows
  • Starting package 2/10: liblzma:x86-windows
  • Starting package 3/10: zlib:x86-windows
  • Starting package 4/10: libpng:x86-windows
  • Starting package 5/10: libwebp:x86-windows
  • Starting package 6/10: opengl:x86-windows
  • Starting package 7/10: protobuf:x86-windows
  • Starting package 8/10: tiff:x86-windows
  • Starting package 9/10: opencv4:x86-windows
  • Starting package 10/10: opencv:x86-windows

使用 vcpkg 完成 OpenCV 编译后,你将在 \vcpkg\installed\x86-windows\share\opencv\OpenCVConfig.cmake. 中看到 OpenCVConfig.cmake。 此文件包含 OpenCV CMake 选项,用于外部项目。让我们从这个 OpenCV CMake 配置文件的开头开始,构建一个 CMakeLists.txt 文件:

cmake_minimum_required (VERSION 3.8)
project (“CMakeTriangles”)set (CMAKE_TOOLCHAIN_FILE “D:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake”)set (OpenCV_DIR"D:/Tools/vcpkg/installed/x86-windows/share/opencv")
find_package(OpenCV REQUIRED)

#Add source to this project’s executable.add_executable (CMakeTriangles “CMakeTriangles.cpp”)target_link_libraries (CMakeTriangles ${OpenCV_LIBS})# TODO: Add tests and install targets if needed.

在系统中使用硬编码路径获取 CMakeLists.txt 文件,是绝对不可取的,我们稍后会给出建议的方案。现在让我们看看如何使用 OpenCV 制作 CMake 标志。以下是 CMakeTriangles.cpp 的代码:

#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc.hpp>#include
using namespace cv;using namespace std;
int main(){ Mat image = Mat::zeros(400, 600, CV_8UC3); image.setTo(Scalar(255, 255, 255)); fillConvexPoly(image, vector{ Point(200, 300), Point(400, 300), Point(300, 50) }, Scalar(128, 128, 128)); fillConvexPoly(image, vector{ Point(200, 300), Point(300, 175), Point(300, 50) }, Scalar(255, 0, 0)); fillConvexPoly(image, vector{ Point(400, 300), Point(305, 255), Point(305, 50) }, Scalar(0, 0, 255)); fillConvexPoly(image, vector{ Point(205, 300), Point(260, 240), Point(395, 300) }, Scalar(0, 255, 0)); imshow(“CMake Trianges!!”, image); waitKey(0); return 0;}

在这里插入图片描述
考虑到 CMakeLists.txt 文件和 CMakeTriangles.cpp 文件,我们可以很容易地运行编译:

cmake -S. -BBuild -A “Win32” cd Build && cmake --build .

现在让我们从 CMakeLists.txt 文件中删除硬编码的值

cmake_minimum_required (VERSION 3.8)
project (“CMakeTriangles”)
find_package(OpenCV REQUIRED)
#Add source to this project’s executable.add_executable (CMakeTriangles “CMakeTriangles.cpp”)target_link_libraries (CMakeTriangles ${OpenCV_LIBS})
#TODO: Add tests and install targets if needed.

有了这个新的 CMakeLists.txt 文件,项目编译也相应有了些改变:

cmake -S. -BBuild -A “Win32” -DOpenCV_DIR=/vcpkg/installed/x86-windows/share/opencv -DCMAKE_TOOLCHAIN_FILE= /vcpkg/scripts/buildsystems/vcpkg.cmakecd Build && cmake --build .

这里 是相对于已安装的 vcpkg 文件夹的。使用这种方法,你将能在构建文件夹中找到运行程序所需的所有 DLL.
在这里插入图片描述

你现在可以双击这个可执行文件,显示如上图。由于 vcpkg、CMake 和OpenCV 都是跨平台的工具,Windows、Linux 和 Mac 都可以支持,因此我们能够按照上面的步骤编译并运行 CMake triangles 映像。

我们该如何添加测试?

作为架构师,我支持在开发周期中尽早添加单元测试。一种测试驱动的方法,是在编写代码之前就添加测试,这种方法可能适用于某些项目,但我反对软件开发中的任何“过度狂热”。让我们重构我们的单片代码,使其更易于单元测试(读者注意:建议在重构之前添加测试)。经过紧张地重构,我们的项目现在被拆分了 CMakeTrianglesLib.cpp、CMakeTriangles.h 和CMakeTriangles.cpp。
其中 CMakeTriangles.h 是:

#pragma once
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc.hpp>#include
using namespace cv;using namespace std;#include
Mat CreateImageWithBackground(int rows, int cols, int type, Scalar background);
void CreateConvexPolygonsOnImage(Mat image, vector<vector> points, vector backgrounds);
void DisplayWindowWithTitle(Mat image, string title);

CMakeTriangleslib.cpp 是:

#include “CMakeTriangles.h”
Mat CreateImageWithBackground(int rows, int cols, int type, Scalar background){ Mat image = Mat::zeros(rows, cols, type); image.setTo(background); return image;}
void CreateConvexPolygonsOnImage(Mat image, vector<vector> points, vector backgrounds){ if (points.size() != backgrounds.size()) return; // No change in the image
for (auto i = 0UL; i < points.size(); ++i) { fillConvexPoly(image, points[i], backgrounds[i]); }}
void DisplayWindowWithTitle(Mat image, string title){ imshow(title, image);}

CMakeTriangles.cpp 是:

#include “CMakeTriangles.h”
int main(){ auto image = CreateImageWithBackground(400, 600, CV_8UC3, Scalar(255, 255, 255));
CreateConvexPolygonsOnImage(image, { { Point(200, 300), Point(400, 300), Point(300, 50) }, // Grey inner triangle { Point(200, 300), Point(300, 175), Point(300, 50) }, // Blue left triangle { Point(400, 300), Point(305, 255), Point(305, 50) }, // Red right triangle { Point(205, 300), Point(260, 240), Point(395, 300)} }, // Green lower triangle // Grey, Blue Red Green { Scalar(128, 128, 128), Scalar(255, 0, 0), Scalar(0, 0, 255), Scalar(0, 255, 0) });

DisplayWindowWithTitle(image, “CMake Triangles Refactored!!”); waitKey(0); return 0;}

CMakeLists.txt 变成:

cmake_minimum_required (VERSION 3.8)project (“CMakeTrianglesRefactored”)
find_package(OpenCV REQUIRED)
add_library (CMakeTrianglesLib “CMakeTrianglesLib.cpp” “CMakeTriangles.h”)target_include_directories(CMakeTrianglesLib PRIVATE ${OpenCV_INCLUDE_DIRS})
add_executable (CMakeTriangles “CMakeTriangles.cpp”)
target_link_libraries (CMakeTriangles CMakeTrianglesLib ${OpenCV_LIBS})

编译现在生成一个额外的库文件,如下所示:

在这里插入图片描述
测试我们的库代码,我们希望能被广泛使用? –使用谷歌测试(GTest)。使用 vcpkg 安装 GTest,会有下列提示:

The package gtest:x86-windows provides CMake targets: find_package(GTest CONFIG REQUIRED) target_link_libraries(main PRIVATE GTest::gmock GTest::gtest GTest::gmock_main GTest::gtest_main)

我们已经编写了一些测试代码。创建文件 CMakeTrianglesLibTest.cpp 并加入下列代码:

#include “gtest/gtest.h”#include “CMakeTriangles.h”
TEST(testCMakeTriangleLib, Given_Rows_Cols_Type_BG_When_CreateImageWithBackground_Call_Then_Return_OK){ const int r = 300; const int c = 600; auto image = CreateImageWithBackground(r, c, CV_8UC3, Scalar(255, 255, 255)); EXPECT_EQ(c, image.cols); EXPECT_EQ(r, image.rows);}

这个测试代码解释了如何使用 GTest 将所有内容与 CMake 结合起来编写OpenCV 单元测试。最后的 CMakeLists.txt 文件如下所示:

cmake_minimum_required (VERSION 3.8)project (“CMakeTrianglesRefactored”)
find_package(OpenCV REQUIRED)
add_library (CMakeTrianglesLib “CMakeTrianglesLib.cpp” “CMakeTriangles.h”)target_include_directories(CMakeTrianglesLib PRIVATE ${OpenCV_INCLUDE_DIRS})
add_executable (CMakeTriangles “CMakeTriangles.cpp”)
target_link_libraries (CMakeTriangles CMakeTrianglesLib ${OpenCV_LIBS})
find_package(GTest CONFIG REQUIRED)add_executable(CMakeTrianglesLibTest “CMakeTrianglesLibTest.cpp”)target_link_libraries(CMakeTrianglesLibTest PRIVATE CMakeTrianglesLib ${OpenCV_LIBS} GTest::gtest GTest::gtest_main)

最后,你就能成功构建整个项目,并获得:
在这里插入图片描述
你也可以现在执行这些测试,并获得相应结果:

在这里插入图片描述

结论

这是一篇很长的文章,我希望我可以带大家了解 CMake 和 OpenCV 编译,如何使用 GTest 编写 OpenCV 单元测试,并使用 CMake 完成所有工作。我知道 OpenCV ts 模块,但它只是 OpenCV 的内部模块,因此建议不要修补源代码以将它改为公开可见。使用 GTest 测试 OpenCV,使用 CMake 简化跨平台构建。我强烈推荐选择 VCPkg 作为包管理器。

编写这篇文章让我觉得乐趣无穷,希望也能将这种快乐传递给大家!

点击了解 Incredibuild 加速 CI/CD 的解决方案,并获取试用 License!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1479437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云商大宗商品使用的是什么系统,有什么功能

云商大宗商品使用的系统主要包括大宗商品贸易系统、大宗商品仓储管理系统。 大宗商品贸易系统则是一种基于互联网技术的交易平台&#xff0c;旨在为买卖双方提供高效、安全、透明的交易环境。该系统具备商品管理、交易管理、资金管理、数据分析和风险管理等功能模块&#xff0…

2024年四川媒体新闻发布渠道,媒体邀约资源表

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 四川有哪些媒体新闻发布渠道&#xff0c;媒体邀约资源表&#xff1f; 2024年四川媒体新闻发布渠道&#xff0c;媒体邀约资源表 四川本地媒体&#xff1a;如四川日报、华西都市报、成都商…

2024年最好的 5 款免费的数据恢复软件

数据意外损坏或丢失&#xff1f;别担心&#xff0c;今天我为大家带来了实用的免费硬盘数据恢复软件&#xff01; 在数字化时代&#xff0c;数据的重要性不言而喻。但是&#xff0c;由于种种原因&#xff0c;数据意外损坏或丢失的情况时有发生。此时&#xff0c;一款实用的免费…

SpringBoot 自定义映射规则resultMap association一对一

介绍 例&#xff1a;学生表&#xff0c;班级表&#xff0c;希望在查询学生的时候一起返回该学生的班级&#xff0c;而一个实体类封装的是一个表&#xff0c;如需要多表查询就需要自定义映射。 表结构 班级表 学生表 SQL语句 SELECT a.id,a.name,a.classes,b.id classes…

JS(JavaScript)中如何实现,复选框checkbox多选功能

起始界面&#xff1a; 代码元素&#xff1a; <p><input type"checkbox" id"checkedAll"> 全选按钮</p><p><input type"checkbox" class"cl"> 选项1</p><p><input type"checkbox&qu…

张驰咨询:为什么每个应届生都应该参加六西格玛培训?

应届生参加六西格玛培训的现象逐渐成为了一个新的趋势&#xff0c;这背后的原因不仅仅是市场对于品质管理人才的渴求&#xff0c;也源于应届生自身发展的需求。本文张驰咨询将从应届生的视角探讨参加六西格玛培训的动机&#xff0c;以及这种培训如何为他们的职业生涯铺路。 为…

认识通讯协议——TCP/IP、UDP协议的区别,HTTP通讯协议的理解

目录 引出认识通讯协议1、TCP/IP协议&#xff0c;UDP协议的区别2、HTTP通讯协议的讲解 Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 认识通讯协议——TCP/IP、UDP协议的区别&#xff0c;HTTP通讯协议的理解 认识通讯协议 …

做活动和会议直播,为什么要多个媒体平台同步直播?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 多个媒体平台同步直播活动和会议的原因主要有以下几点&#xff1a; 扩大观众覆盖面&#xff1a;不同的媒体平台拥有各自独特的用户群体&#xff0c;通过在多个媒体平台同步直播&#xff…

Unity(第二十一部)动画的基础了解(感觉不了解其实也行)

1、动画组件老的是Animations 动画视频Play Automatically 是否自动播放Animate Physics 驱动方式&#xff0c;勾选后是物理驱动Culling Type 剔除方式 默认总是动画化就会一直执行下去&#xff0c;第二个是基于渲染播放&#xff08;离开镜头后不执行&#xff09;&#xff0c; …

如何解决 C/C++ 编译器优化导致的编译BUG(程序崩溃)支援VC++/CLANG/GCC

本文仅适用于&#xff0c;有愿意、爱捣鼓的童靴。 因编译器优化导致编译BUG&#xff0c;即DEBUG下面无故障稳定工作&#xff0c;但RELESE下程序会在特定函数位置上崩溃。 这要求 C/C 开发人员拥有最基本的素质&#xff0c;需要能够承受&#xff0c;逐行审视编译器输出的目标平…

yolov9,使用自定义的数据训练推理

[源码 &#x1f40b;]( GitHub - WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information) [论文 &#x1f4d8;](arxiv.org/pdf/2402.13616.pdf) 论文摘要&#xff1a;本文介绍了一种新的目标检测…

【 JS 进阶 】正则表达式

“生命是一幅抽象画&#xff0c;每一笔都是独特的经历。在色彩的交织中&#xff0c;用坚定的画笔勾勒出自己的轨迹&#xff0c;让每一幅画作都成为奋斗的印记。” - 亚历山大斯密斯 正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是一种字符串匹配的模式&a…

二、TensorFlow结构分析(2)

目录 1、会话 1.1 __init__(target,graphNone,configNone) 1.2 会话的run() 1.3 feed操作 TF数据流图图与TensorBoard会话张量变量OP高级API 1、会话 1.1 __init__(target,graphNone,configNone) def session_demo():# 会话的演示# Tensorflow实现加法运算a_t tf.constan…

LNMP 架构

搭建 LNMP 架构需要安装 nginx mysql php 软件 linux nginx mysql php结合 在一台主机上搭建LNMP架构 一、编译安装 nginx 安装依赖包 yum -y install pcre-devel zlib-devel gcc gcc-c make 创建nginx程序用户 &#xff08;Nginx 服务程序默认以 nobody 身份运…

基于java Springboot实现课程评分系统设计和实现

基于java Springboot实现课程评分系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源…

MySQL(基础篇)——事务

一.事务简介 事务是一组操作的集合&#xff0c;他是一个不可分割的单位&#xff0c;事务会把所有的操作作色一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 默认MySQL的事务是自动提交的&#xff0c;也就是说&#xff0c…

QML中动态增加表格数据

1.QML中的表格实现 import QtQuick 2.15 import QtQuick.Window 2.15import QtQuick.Controls 2.0 import Qt.labs.qmlmodels 1.0 import QtQuick.Layouts 1.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")TableModel{id:table_modelTabl…

STM32 IIC协议基础概念

文章目录 前言一、IIC协议介绍二、IIC硬件框图和程序层次三、IIC协议1.IIC协议通信流程2.IIC的引脚为什么需要加入上拉电阻3.IIC的引脚为什么需要配置为开漏输出 四、STM32 IIC硬件结构总结 前言 本篇文章将带大家学习IIC通信协议的一些基础概念和使用。 一、IIC协议介绍 I2…

【iOS ARKit】RealityKit 同步机制

协作 Session 可以很方便地实现多用户之间的AR体验实时共享&#xff0c;但开发者需要自行负责并确保AR场景的完整性&#xff0c;自行负责虚拟物体的创建与销毁。为简化同步操作&#xff0c;RealityKit 内建了同步机制&#xff0c;RealityKit 同步机制基于 Multipeer Connectivi…

RISC-V特权架构 - CSR寄存器

RV32/64 特权架构 - CSR寄存器 1 CSR地址空间2 CSR定义2.1 用户级2.2 监管级2.3 超级监管级2.4 机器级 3 CSR访问3.1 CSRRW3.2 CSRRS3.3 CSRRC3.4 CSRRWI3.5 CSRRSI3.6 CSRRCI 本文属于《 RISC-V指令集基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 CSR地址空间 RISC&…