# algocv
**Repository Path**: ninestars_com/algocv
## Basic Information
- **Project Name**: algocv
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-07-09
- **Last Updated**: 2024-07-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
```txt
AAA lllllll
A:::A l:::::l
A:::::A l:::::l
A:::::::A l:::::l
A:::::::::A l::::l ggggggggg ggggg ooooooooooo ccccccccccccccccvvvvvvv vvvvvvv
A:::::A:::::A l::::l g:::::::::ggg::::g oo:::::::::::oo cc:::::::::::::::c v:::::v v:::::v
A:::::A A:::::A l::::l g:::::::::::::::::go:::::::::::::::o c:::::::::::::::::c v:::::v v:::::v
A:::::A A:::::A l::::l g::::::ggggg::::::ggo:::::ooooo:::::oc:::::::cccccc:::::c v:::::v v:::::v
A:::::A A:::::A l::::l g:::::g g:::::g o::::o o::::oc::::::c ccccccc v:::::v v:::::v
A:::::AAAAAAAAA:::::A l::::l g:::::g g:::::g o::::o o::::oc:::::c v:::::v v:::::v
A:::::::::::::::::::::A l::::l g:::::g g:::::g o::::o o::::oc:::::c v:::::v:::::v
A:::::AAAAAAAAAAAAA:::::A l::::l g::::::g g:::::g o::::o o::::oc::::::c ccccccc v:::::::::v
A:::::A A:::::A l::::::lg:::::::ggggg:::::g o:::::ooooo:::::oc:::::::cccccc:::::c v:::::::v
A:::::A A:::::A l::::::l g::::::::::::::::g o:::::::::::::::o c:::::::::::::::::c v:::::v
A:::::A A:::::A l::::::l gg::::::::::::::g oo:::::::::::oo cc:::::::::::::::c v:::v
AAAAAAA AAAAAAAllllllll gggggggg::::::g ooooooooooo cccccccccccccccc vvv
g:::::g
gggggg g:::::g
g:::::gg gg:::::g
g::::::ggg:::::::g
gg:::::::::::::g
ggg::::::ggg
gggggg
```
#
算法框架介绍及使用规范v1.0.0
* [算法框架介绍及使用规范v1.0.0](#算法框架介绍及使用规范v1.0.0)
* [基本规范](#基本规范)
* [遵守代码风格规范](#遵守代码风格规范)
* [注释和文档](#注释和文档)
* [代码结构](#代码结构)
* [命名规范](#命名规范)
* [变量命名](#变量命名)
* [函数命名](#函数命名)
* [类、结构体命令](#类、结构体命令)
* [枚举类型命名](#枚举类型命名)
* [宏命名](#宏命名)
* [命名空间](#命名空间)
* [其他](#其他)
* [合理组织文件和目录](#合理组织文件和目录)
* [使用模块化和封装](#使用模块化和封装)
* [明确错误处理](#明确错误处理)
* [优化循环和逻辑](#优化循环和逻辑)
* [版本控制](#版本控制)
* [单元测试和代码审查](#单元测试和代码审查)
* [算法工程](#算法工程)
* [目录结构介绍](#目录结构介绍)
* [代码编译](#代码编译)
* [开发板编译](#开发板编译)
* [本机交叉编译](#本机交叉编译)
* [本机直接编译](#本机直接编译)
* [Docker编译](#docker编译)
* [代码框架](#代码框架)
* [消息类图](#消息类图)
* [日志类图](#日志类图)
* [代理类图](#代理类图)
* [配置文件](#配置文件)
* [开发插件](#开发插件)
* [算法输出](#算法输出)
* [Demo例程的构建](#demo例程的构建)
* [编译Demo](#编译demo)
* [输出内容介绍](#输出内容介绍)
## 基本规范
### 遵守代码风格规范
在C++编程中,遵守代码风格规范非常重要,可以让代码更具可读性和可维护性。
#### 注释和文档
帮助他人快速理解代码的功能和工作方式
- 文件注释
```cpp
/**
* @file ninestars.cpp
* @brief This is a demo brief
*/
```
- 函数注释
```cpp
/**
* @brief Returns the maximum between two integers
*
* @param a An integer value
* @param b Another integer value
* @return The larger of the two integer values.
*/
int max(int a, int b)
{
return (a > b) ? a : b;
}
- 类声明注释
```cpp
/**
* @class Caculator
* @brief This is a caculator class defination
*
*/
class Caculator : public Object {
public:
Caculator(int arg1, int arg2);
~Caculator();
int max(int a, int b);
private:
int mArg1;
int mArg2;
};
```
#### 代码结构
保持代码的结构整洁,
- 缩进和行长: 设置tab的宽度为4, 单行代码的长度应在80到120个字符以内, 运算符和逗号后添加空格。
```cpp
int sum = a + b; // Add spaces around the operator
for (int i = 0; i < n; ++i) { // Add a space after the semicolons
char *long_string = "This is a very long string that "
"needs to be broken into multiple "
"lines for better readability.";
}
```
- 函数参数列表: 参数较多时,适当的换行和缩进可以提高代码可读性, 同时建议一个函数不要传递太多参数。
```cpp
void doSomething(
int parameter_long_name_1, int parameter_long_name_2,
const std::string& parameter_long_name_3,
const std::vector& parameter_long_name_4)
{
}
```
- 代码块括号: 即使是单条语句的控制快,**建议**也使用括号,避免潜藏的错误。
```cpp
if (condition) {
donSomething();
}
```
- 数据封装: 使用类的公有方法操作类中的私有成员变量,不要直接去访问它们。
```cpp
class BankAccount {
public:
void deposit(double amount) {
if (amount > 0) {
mBalance += amount;
}
}
private:
double mBalance = 0;
};
```
- 避免使用魔术数字: 硬编码的数字应定义为常量或宏,且名字具有一定可读性。
```cpp
const int MaxBufferSize = 512;
char buffer[MaxBufferSize];
```
- 避免使用全局变量
### 命名规范
#### 变量命名
需清晰反映用途,全局变量以g开头,静态变量以s开头,常量变量以k开头,类成员变量以m开头, 采用骆驼峰命名且首字母**小**写。
如果既是静态或者常量,又是全局变量,以g开头。
> ```cpp
> class Caculator : public Object {
> public:
> Caculator(int weightX, int weightX): mWeightX(weightX), mWeightY(weightX) {}
> ~Caculator() {}
>
> int calculateWeightedSum(int x, int y) {
> return mWeightX * x + mWeightY *y;
> }
>
> private:
> int mWeightX;
> int mWeightY;
> };
>
> const int kFixWeight = 0.321;
> const Caculator* gCaculator = nullptr;
```
#### 函数命名
需清晰反映函数功能,采用骆驼峰规则命名且首字母**小**写。
> ```cpp
> int calculateMaximum(int a, int b)
> {
> return (a > b) ? a : b;
> }
> ```
#### 类、结构体命令
采用骆驼峰命名法,且首字母**大**写
> ```cpp
> class StudentInfo {
> //...
> };
> ```
#### 枚举类型命名
采用骆驼峰,首字母小写**e** (建议)
> ```cpp
> enum State {
> eAlgoInit = 0,
> eAlgoDCPositioning = 1,
> eAlgoNull,
> };
> ```
#### 宏命名
需清晰反映用途,字符全部大些,单词间可以使用**\_**连接
> ```cpp
> #define CAMERA_D_ALIGNMENT 100 // double camera alignment
> #define CAMERA_S_AUTOFOCUS 101 // single camera autofocus
> ```
#### 命名空间
命名空间的名字应该能够反映其封装的代码的功能。避免在头文件中直接使用using namespace将整个命名空间引入。
> ```cpp
> // Good practice: descriptive and hierarchical namespace
> namespace ninestars {
> namespace math {
> class Vector { /* ... */ };
> }
> }
>
> // Using declarations to simplify usage in .cpp files
> using ninestars::math::Vector;
>
> // Bad practice: overuse of using directive in header file
> // This can lead to naming collisions and is not recommended.
> using namespace ninestars;
> ```
### 其他
#### 合理组织文件和目录
1. 将相关的代码文件组织在同一目录下。
2. 使用清晰、描述性的文件名和目录名。
#### 使用模块化和封装
1. 将代码分割成小的、可重用的模块。
2. 封装模块内部的实现细节,仅暴露必要的接口。
#### 明确错误处理
1. 在代码中明确地处理错误情况。
2. 使用异常处理、错误码或是状态标志等机制来管理错误。
#### 优化循环和逻辑
1. 避免不必要的循环和递归调用。
2. 优化条件判断,减少循环迭代次数。
#### 版本控制
1. 使用版本控制系统,如Git,来管理代码的版本。
2. 遵循良好的提交实践,如使用清晰的提交消息,以及合理地分割代码改动。
#### 单元测试和代码审查
1. 编写接口/功能函数等单元测试,确保代码功能的正确性和稳定性。
2. 定期组织代码审查、评估代码质量。
## 算法工程
### 目录结构介绍
```
algocv
│
├── assets ────────────────────► 调试: 算法用到的资源,比如测试图片,测试页面。
│ ├── images
│ └── www
├── cmake ────────────────────► 构建: 项目的配置,根据选项或者平台属性,选择合适的交叉编译链和文件系统。
│ ├── platform
│ │ ├── RK3566
│ │ └── RK3588
│ └── projects
│ ├── biometric_instrument
│ ├── corneal_endothelium
│ └── fundus_camera
├── config ────────────┐
│ └── etc └───────► 调试: 工具类相关的配置,比如nginx、rsync等。
│ └── nginx
│ └── conf.d
├── docker ────────────────────► 环境: 创建目标平台镜像环境的配置。
│ └── aarch64
├── docs ───────────────┐
│ ├── framework └────► 文档: markdown、doc、notebook等。
│ └── codeguide ───────────┐
│ └── notebooks └────► 文档:接口使用、项目需求样例等。
│ └── fundus_camera
├── examples ────────────────────► 调试: 具有一定功能的测试样例。
│ └── motor_control
├── externals ───────────────┐
│ ├── platform └────► 构建: (git)子模块,存放构建项目依赖的交叉编译链、文件系统、第三方库等。
│ │ └── RK3588
│ ├── thirdparts
│ │ └── json
│ │ └── nlohmann ┌───► 调试: 潜入到算法库,具有一定功能的插件开发,比如:控制电机、设置日志级别等。
│ └── toolchain │
├── plugins ────────────────┘
│ ├── http_server
│ └── stream_server
├── scripts ────────────────────► 构建: cmake 配置项目时调用的脚本、其他启动脚本等。
├── src
│ ├── app ────────────────────► 算法: 使用算法库完成具体的应用(暂时无)。
│ │ └── Qt
│ └── lib ────────────────────► 算法: 算法框架、算法核心
│ ├── core ═══════════════╗
│ │ ├── camera ╠════════► 相机相关
│ │ ├── fpga ╠════════► FPGA相关
│ │ ├── handler ╠════════► 与软件应用对应,处理软件发过来的消息命令的处理程序。
│ │ ├── helper ╠════════► 通用辅助类
│ │ ├── measure ╠════════► 测量类算法
│ │ ├── motor ╠════════► 电机相关,如移动步长计算。
│ │ └── xpu ╠════════► 深度学习推理算法。
│ │ ├── jetson
│ │ └── rknn
│ ├── logger ══════════════╗
│ ├── osmsg ║ 算法: 基础框架(消息系统、设置、日志系统)
│ ├── setting ║
│ └── utils ══════════════╝
├── tests ──────────────────────► 调试: 接口、函数、类等单元测试
│ ├── camera
│ ├── cvmsg
│ ├── handler
│ ├── helper
│ ├── motor
│ ├── qtlog
│ ├── setting
│ └── xpu
└── tools ──────────────────────► 工具: 可以加快开发、问题定位的任何工具类,如:日志控制、标定等。
```
### 代码编译
假设`ALGOCV_TOP_DIR`是算法工程的TOP目录
#### 开发板编译
将代码直接`git clone`到开发板上进行开发。
- 优点: 能够保证运行环境一致性。
- 缺点: 需要依赖设备开发,代码放到设备上不安全,涉及到核心代码外泄等。
构建编译步骤:
> ```sh
> cd ${ALGOCV_TOP_DIR}
> mkdir build
> cd build
> ccmake ../ # c - c - e - c - g
> make -j
> ```

#### 本机交叉编译
将代码直接git clone到本机电脑上(本机要求是Linux,构建脚本是linux写的)
交叉编译之后,需要推送开发板上执行,可以通过执行下面的命令自己推送:
1. `make remote_so` 将编译后的库推送到开发板, 需要配置`${ALGOCV_TOP_DIR}/.so-sync`中的开发板地址
2. `make remote_package` 如果代码修改了对外的几个头文件(7个), 需要配置`${ALGOCV_TOP_DIR}/.dev-sync`
- 优点:开发调试速度快,根据爱好选择自己熟悉的代码编辑器。
- 缺点:sysroot文件系统需要根据对应板子(如kr3588)制作压缩包。(只需一次)

#### 本机直接编译
通过配置选项关闭XPU,可以编译出amd64库,结合测试单元,快速验证自己的算法或者程序。
- 优点:同上,本地可执行,非常适合本地快速验证算法接口。
- 缺点:不支持编译XPU, 与深度模型推理的算法代码不会编译。

#### 嵌入式Docker编译
首先使用`${ALGOCV_TOP_DIR}/scripts/build_aarch64_docker.sh`建立一个aarch64嵌入式进行, 需要传入正确的文件系统
比如rk3588, 文件系统在`${ALGOCV_TOP_DIR}/externals/platform`中可以找到, 如果文件系统与开发板一致时,可保证环境一致性。
构建之后,需要启动容器执行`${ALGOCV_TOP_DIR}/scripts/start_aarch64_docker.sh`。
- 优点: 编译程序可以在容器内执行,无需推送到开发板, 代码可在容器外开发,选择喜爱的代码编辑器。
- 缺点: 构建的镜像暂用大量磁盘空间。

### 代码框架
#### 消息类图
**GO**➡️ [docs/framework/message.md](docs/framework/message.md)
算法与软件异步交互,以及算法模块之间交互的核心组件。算法初始化时,启动一个主消息线程,用于接收和分发消息。
#### 日志类图
**GO**➡️ [docs/framework/log.md](docs/framework/log.md)
建议: 如果某个算法模块比较繁重,需要实现对应的LOG模块, 如Handler模块
> ```
> extern int gHandlerModuleLevel;
>
> #define HANDLER_LOGE(args...) _LOGE(gHandlerModuleLevel, args)
> #define HANDLER_LOGW(args...) _LOGW(gHandlerModuleLevel, args)
> #define HANDLER_LOGD(args...) _LOGD(gHandlerModuleLevel, args)
> #define HANDLER_LOGI(args...) _LOGI(gHandlerModuleLevel, args)
> ```
> ```cpp
> int gHandlerModuleLevel = LOG_LEVEL_DEBUG;
>
> static LogModule HandlerLogModule("handler", gHandlerModuleLevel);
> ```
好处: 每个模块单独设置日志级别, 可以通过配置文件,或者开启Plugin功能,动态设置各个框架模块的日志级别。
#### 代理类图
**GO** ➡️ [docs/framework/useme.md](docs/framework/useme.md)
QAlgocvAgent 专门为algocv异步输出的图片数据,需要UI显示,可以交给QAlgocvAgent将数据发给UI主线程。
### 配置文件
减少硬编码
TODO
### 开发插件
辅助algocv调试
TODO
## 算法输出
以[相机对位](examples/Qt/camera_align/)的算法模块为例,介绍本地开发调试及算法最终的输出(给软件部门使用)。
### Demo例程的构建
编写构建文件[CMakeLists.txt](examples/Qt/camera_align/CMakeLists.txt), 该文件分为两部分:
```cmake
if(DEFINED APP_SOURCE_DIRECTORY) # 1. 随algocv项目构建一起编译,并导出算法需要输出的文件
set(DEMO_NAME camera_align)
set(SOURCE_FILES
${APP_SOURCE_DIRECTORY}/Qt/QAlgocvAgent.cpp
main.cpp
)
...
install(FILES ${SOURCE_FILES} DESTINATION ${DEMO_NAME}/src)
install(FILES ${INSTALL_HEADER_FILES} DESTINATION ${DEMO_NAME}/src)
install(FILES ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt DESTINATION ${DEMO_NAME})
install(FILES ${DOCS_SOURCE_DIRECTORY}/codeguide/app/camera_align.md DESTINATION ${DEMO_NAME}/docs)
configure_file(${EXAMPLES_SOURCE_DIRECTORY}/run_it.sh.in ${CMAKE_INSTALL_PREFIX}/${DEMO_NAME}/run_it.sh @ONLY)
execute_process(COMMAND chmod +x ${CMAKE_INSTALL_PREFIX}/${DEMO_NAME}/run_it.sh)
else() # 2. 基于算法输出的文件进行独立地项目构建 (方便软件开发人员直接构建)
cmake_minimum_required(VERSION 3.10)
project(example_camera_align)
...
add_executable(camera_align ${SOURCE_FILES})
set_target_properties(camera_align PROPERTIES LINK_FLAGS "-Wl,--as-needed")
target_link_directories(camera_align PRIVATE ${CMAKE_CURRENT_LIST_DIR}/lib)
target_link_libraries(camera_align algocv Qt5::Core Qt5::Widgets ${OpenCV_LIBS})
endif()
```
### 编译Demo
可以选择`交叉编译`、`Docker容器内编译`、`开发板上编译`等几种方式(上面的介绍)。这里以`容器`的方式编译Algocv算法
1. 启动/进去容器: [./scripts/start_aarch64_docker.sh](scripts/start_aarch64_docker.sh)

2. 选择算法交付的项目以及Demo配置

3. package输出
```sh
make -j2
make install # 生成package目录
```
4. 验证Demo
```sh
cd package/corneal_endothelium/camera_align
./run_it.sh # 1. 构建Demo --> 2. 编译 --> 3. 运行 (如果脚本输出正常,则可打包并发给软件开发人员
```
### 输出内容介绍
```
┌─────────────► 将这个目录打包发给“使用者”
│
package/ │
├── corneal_endothelium ────────────────► cmake编译时选择的项目
│ └── camera_align ────────────────► cmake编译时选择的Demo模块
│ ├── algocv_conf.ini.in ────────────────► 算法配置文件模板,构建时自动替换,可配置
│ ├── CMakeLists.txt
│ ├── docs ──────────────────────────────────────────► 提供简单的介绍
│ │ └── camera_align.md ┌──────────────────────────► 使用者只需要引入algocv_api.h头文件即可
│ ├── include │ ─────────┐
│ │ ├── algocv_api.h ────┘ │
│ │ ├── AlgocvHandler.h │
│ │ ├── Message.h ├───────► 算法提供出的外部头文件
│ │ ├── MessageHandler.h │
│ │ ├── MessageTypes.h │
│ │ ├── Object.h │
│ │ └── PayloadTypes.h ─────────┘
│ ├── lib
│ │ └── libalgocv.so ───────────────────────────────► 输出的算法库
│ ├── run_it.sh ─────────────────────────────────────────► 编译Demo的脚本, 直接执行,可输出结果
│ └── src ──────────┐
│ ├── AlgocvQtAgentDemo.cpp ├──────► 测试Demo, 使用者能够快速适用算法模块
│ ├── AlgocvQtAgentDemo.h │
│ └── main.cpp ──────────┘
└── run_camera_align.sh
```