笔记(五)

c++的#include 和using namespace

image

#include 详解:代码的 “复制粘贴” 指令

  1. 核心作用

include 是 C++ 预处理指令,作用是将指定文件的全部内容原封不动地插入到当前代码文件中,解决 “代码复用” 和 “跨文件调用” 问题。

简单类比:你写代码时需要用标准库的 cout,但 cout 的定义不在你当前文件里,#include 就是把包含 cout 定义的 iostream 文件内容复制到你的代码里,编译器才能认识 cout。
2. 语法与分类

// 方式1:包含标准库头文件(<> 表示从系统库路径查找)
#include <iostream>   // 标准输入输出库
#include <vector>     // 容器库

// 方式2:包含自定义头文件("" 表示先从当前项目路径查找,再找系统路径)
#include "myfunc.h"   // 自己写的头文件
#include "datatype.hpp"
  1. 新手必懂的关键规则
    头文件保护:自定义头文件必须加 “防重复包含” 代码,否则多次 #include 会导致重复定义错误:
// myfunc.h 中必须加的保护代码(两种方式二选一)
// 方式1:预处理宏(兼容所有编译器)
#ifndef MYFUNC_H   // 如果未定义该宏
#define MYFUNC_H   // 定义宏

// 头文件内容(函数声明、结构体定义等)
int Add(int a, int b);

#endif // 结束保护

// 方式2:编译器指令(更简洁,C++11 支持)
#pragma once
int Add(int a, int b);

不要滥用 #include:只包含需要的头文件(比如用 vector 只加 ,不加 ),减少编译时间。

using namespace 详解:命名空间的 “简写工具”

  1. 命名空间的背景
    C++ 引入 “命名空间(namespace)” 是为了解决命名冲突问题。比如两个库都有 Print() 函数,通过命名空间 A::Print() 和 B::Print() 就能区分。
    标准库的所有内容都放在 std 命名空间里(比如 std::cout、std::vector),如果不用 using namespace,就必须写完整前缀:
#include <iostream>
// 没有 using namespace std,必须写 std::cout
int main() {
    std::cout << "Hello World" << std::endl;
    return 0;
}
  1. using namespace 的作用
    using namespace std; 表示 “将 std 命名空间中的所有名称引入当前作用域”,之后可以直接写 cout 而非 std::cout:
#include <iostream>
using namespace std;  // 引入std命名空间
int main() {
    cout << "Hello World" << endl;  // 简化写法
    return 0;
}
  1. 新手易踩坑的使用规范
    ❌ 不推荐的写法(全局引入)
    在头文件中写 using namespace std;,或在代码开头全局引入:
// 头文件 myfunc.h(错误示例)
#include <iostream>
using namespace std;  // 坑:所有包含该头文件的文件都会引入std,易引发命名冲突

✅ 推荐的写法(局部 / 精准引入)
方式 1:在函数内引入(仅作用于该函数)

#include <iostream>
int main() {
    using namespace std;  // 仅main函数内有效
    cout << "Hello" << endl;
    return 0;
}

方式 2:只引入需要的名称(最安全)

#include <iostream>
// 只引入 cout 和 endl,不引入std的其他内容
using std::cout;
using std::endl;
int main() {
    cout << "Hello" << endl;
    return 0;
}

完整示例:正确搭配使用

// 1. 包含必要的头文件(只包含需要的)
#include <iostream>   // 用cout需要
#include <vector>     // 用vector需要
#include "myfunc.h"   // 用自定义Add函数需要

// 2. 精准引入命名空间(避免全局引入)
using std::cout;
using std::vector;

int main() {
    // 使用标准库(无需std::前缀)
    vector<int> nums = {1, 2, 3};
    cout << "第一个数:" << nums[0] << endl;

    // 使用自定义函数
    int sum = Add(10, 20);
    cout << "求和结果:" << sum << endl;

    return 0;
}

总结

  • include:是预处理阶段的 “复制粘贴”,必须写(用到外部代码时),自定义头文件要加防重复包含保护;
  • using namespace:是编译阶段的 “简写工具”,非必须,禁止在头文件中全局引入,推荐函数内引入或精准引入单个名称;
  • 核心原则:#include 按需包含,using namespace 按需引入,减少冗余和命名冲突。

& 的核心含义:引用(Reference)

在 C++ 中,& 放在变量类型后、变量名前时,代表引用(可以理解为 “变量的别名”),核心特点:

  • 引用是对已有变量的 “绑定”,而非新变量(不占用额外内存);
  • 引用必须在定义时初始化,且一旦绑定不能修改绑定对象;
  • 对引用的操作,等价于对原变量的操作。

__declspec(dllexport) cv::Mat ImageU8C1ToMat(const ImageU8C1& img)

image

threshold(src,src,0,255,THRESH_BINARY_INV| THRESH_OTSU);

image
image

Otsu 算法(THRESH_OTSU)核心

Otsu(大津法)是一种自动计算最优阈值的算法,核心原理是:

  • 分析图像的像素灰度直方图,找到一个阈值,使得 “前景像素” 和 “背景像素” 的类间方差最大;
  • 这个阈值是区分前景 / 背景的最优值,无需手动调试(新手不用理解算法细节,会用即可)。
    ✅ 关键:只有当图像是单通道灰度图,且二值化类型包含 THRESH_OTSU 时,第 3 个参数(手动阈值)才会被忽略,算法会自动计算阈值。

完整执行流程(以 “黑色元件 + 白色背景” 为例)

Otsu 算法分析 src 的灰度直方图,自动算出最优阈值(比如 127);
对每个像素执行反向二值化:
像素值 ≥ 127(背景,白色)→ 设为 0(黑色);
像素值 < 127(元件,黑色)→ 设为 255(白色);
最终结果:元件变为白色,背景变为黑色(突出前景)。

Otsu 算法的适用场景:

仅适用于前景和背景对比明显的图像(直方图有两个明显峰值);如果图像光照不均,Otsu 效果差,需改用自适应阈值(adaptiveThreshold)。

开运算

Mat element = getStructuringElement(MORPH_ELLIPSE,Size(5,5));
morphologyEx(src, src, MORPH_OPEN, element);//开运算

先创建一个 5×5 的椭圆形结构元素,对二值化后的图像执行开运算(先腐蚀后膨胀),去除图像中的小噪声点、孤立的细小亮斑,同时保留元件 / 目标的整体轮廓,最后将处理后的图像保存为 BMP 格式文件。

getStructuringElement

image
image

开运算核心原理(新手易理解)

  • 腐蚀(第一步):用结构元素扫描图像,只有当模板内所有像素都是白色(255)时,中心像素才保留白色,否则变为黑色(0)→ 作用:消除小的亮噪声、收缩目标边缘;
  • 膨胀(第二步):用结构元素扫描图像,只要模板内有一个像素是白色(255),中心像素就设为白色 → 作用:将腐蚀后收缩的目标轮廓恢复到原有大小;
    ✅ 开运算的最终效果:去除小噪声、平滑目标边缘,不改变目标整体大小和形状(专门解决二值化后图像有细小白点噪声的问题)。

image

开运算的典型使用场景(为什么要做这一步)

二值化后的图像往往会有 “噪声白点”(比如元件背景中的细小亮斑),这些噪声会干扰后续的轮廓检测、目标识别,开运算就是为了解决这个问题:

  • 工业检测:去除元件表面的细小反光点、背景杂点;
  • 文字识别:消除文字周围的毛刺、孤立白点;
  • 轮廓提取:让目标轮廓更平滑,避免噪声形成虚假小轮廓。

开运算的关键特性(新手必记)

  • 只删 “小的亮区域”,不影响大目标
    开运算只会去除比 “结构元素尺寸小” 的白色噪声点(比如 5×5 结构元素能删 ≤4×4 的白点),大于结构元素的目标(如元件)只会短暂收缩再恢复,整体形状不变。
  • 平滑目标边缘,不改变整体位置
    能消除目标边缘的细小毛刺、凸起,让轮廓更平滑,且目标的中心位置、整体尺寸基本不变。
  • 不可逆性
    被腐蚀掉的小噪声点,膨胀步骤无法恢复,因此噪声被永久去除(这是开运算的核心价值)。

开运算的典型使用场景

  • 工业检测(最常用)
    元件 / 工件二值化后,背景有细小的反光点、杂点,开运算能精准去除这些噪声,不影响元件轮廓(比如你之前的代码场景)。
  • 文字识别
    扫描的文字图像有墨水毛刺、纸张杂点,开运算能平滑文字边缘,消除孤立白点,提升识别准确率。
  • 医学图像
    细胞、病灶图像中,去除小的伪影、噪声点,保留病灶的完整轮廓。

形态学处理

posted @ 2026-03-08 17:06  huihui不会写代码  阅读(1)  评论(0)    收藏  举报