Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python

# Virtual envs
.venv/
venv/
env/

# Editor / OS
.DS_Store
.idea/
.vscode/
*.swp

# Build / dist
build/
dist/
*.egg-info/

# CMake build dirs
cmake-build-*/
CMakeCache.txt
CMakeFiles/

# Model weights & datasets (very large)
*.pth
*.pt
*.ckpt
*.bin
*.safetensors
weights/
checkpoints/
data/raw/
1,281 changes: 95 additions & 1,186 deletions README.md

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions code/ch01/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 第 1 章 — 预备知识 · 配套代码

> 抽取自《深度学习图像分割》第 1 章修订稿 `book-review/drafts/ch01-v3.md`。
> 抽取脚本:`book-review/scripts/extract_code.py`。
> 验证脚本:`book-review/scripts/validate_code.py`。

## 概览

Python/C++ 开发环境配置与 OpenCV/PyTorch 基础调用示例。

## 依赖

- python>=3.10
- torch>=2.0
- torchvision

## 文件清单

| 文件 | 状态 | 备注 |
| --- | --- | --- |
| `code_1-1.py` | 可独立运行 | py_compile + pyflakes 通过 |
| `snippet_02.py` | 可独立运行 | py_compile + pyflakes 通过 |
| `cpp/snippet_01.cpp` | 需 OpenCV 4.x | 需 OpenCV / LibTorch 头文件方可编译 |

## 状态说明

- **可独立运行**:单文件 `python file.py` 通过语法校验且无 undefined name。实际跑通仍可能依赖外部数据/模型权重。
- **教学片段**:源自书稿讲解,依赖书稿上下文中已 `import` 或定义的模块/类。可作为参考阅读,需结合书稿前后文方能运行。
- **语法骨架**:源稿用 `def f(self, ...):` 等 Ellipsis 占位、或在 module top-level 出现 `return` 等纯教学截断写法,本仓库保持与书稿一致,**不修改源码**;标注此状态以提示读者。
- **需 OpenCV 4.x / LibTorch**:C++ 示例,依赖外部 SDK 才能编译。

详细 fenced block 盘点见 [`inventory.md`](inventory.md)。
19 changes: 19 additions & 0 deletions code/ch01/code_1-1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# 来源:《深度学习图像分割》第 1 章 — 代码 1-1 对应的Python版本写法如代码1-2所示。
# 原始位置:book-review/drafts/ch01-v3.md:234
# 本文件由 book-review/scripts/extract_code.py 自动抽取生成。
# 修改请回写源稿后重新生成,避免代码与书稿失同步。
# 导入 opencv 库
import cv2
import sys

# 读取图片
img = cv2.imread("example.jpg")
if img is None:
sys.exit("Could not read the image.")

# 显示图片
cv2.imshow("Display window", img)

# 保存图片为 png 格式
cv2.imwrite("example.png", img)
29 changes: 29 additions & 0 deletions code/ch01/cpp/snippet_01.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// -*- coding: utf-8 -*-
// 来源:《深度学习图像分割》第 1 章 — (无标号片段)
// 原始位置:book-review/drafts/ch01-v3.md:203
// 本文件由 book-review/scripts/extract_code.py 自动抽取生成。
// 修改请回写源稿后重新生成,避免代码与书稿失同步。
// 包含 OpenCV 的头文件
#include <opencv2/opencv.hpp>
#include <iostream>

int main(int argc, char** argv)
{
// 读取图像
cv::Mat img = cv::imread("example.jpg");
// 检查图像是否加载成功
if (img.empty())
{
std::cout << "图像加载失败,请检查路径。" << std::endl;
return -1;
}
// 创建窗口
cv::namedWindow("显示图像", cv::WINDOW_AUTOSIZE);
// 在窗口中展示图像
cv::imshow("显示图像", img);
// 等待用户按下任意键后关闭窗口
cv::waitKey(0);
// 另存为 PNG 格式
cv::imwrite("example.png", img);
return 0;
}
12 changes: 12 additions & 0 deletions code/ch01/inventory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 第 1 章代码清单

- 源稿:`book-review/drafts/ch01-v3.md`
- 自动抽取生成:`book-review/scripts/extract_code.py`

## 全章 fenced block 一览

| # | 原稿行 | 语言 | 抽取后文件 | 来源标号 |
| - | ----- | ---- | ---------- | -------- |
| 1 | 203–228 | cpp | `code/ch01/cpp/snippet_01.cpp` | — |
| 2 | 234–249 | python | `code/ch01/code_1-1.py` | 代码 1-1 |
| 3 | 265–296 | python | `code/ch01/snippet_02.py` | — |
35 changes: 35 additions & 0 deletions code/ch01/snippet_02.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# 来源:《深度学习图像分割》第 1 章 — (无标号片段)
# 原始位置:book-review/drafts/ch01-v3.md:265
# 本文件由 book-review/scripts/extract_code.py 自动抽取生成。
# 修改请回写源稿后重新生成,避免代码与书稿失同步。
# 导入 torch.nn 相关模块
import torch.nn as nn
import torch.nn.functional as F

# 搭建一个 LeNet5
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 卷积层 1
self.conv1 = nn.Conv2d(3, 6, 5)
# 池化层
self.pool = nn.MaxPool2d(2, 2)
# 卷积层 2
self.conv2 = nn.Conv2d(6, 16, 5)
# 全连接层 1
self.fc1 = nn.Linear(16 * 5 * 5, 120)
# 全连接层 2
self.fc2 = nn.Linear(120, 84)
# 全连接层 3
self.fc3 = nn.Linear(84, 10)

# 定义网络的前向推理流程
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
33 changes: 33 additions & 0 deletions code/ch02/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 第 2 章 — 传统图像分割算法 · 配套代码

> 抽取自《深度学习图像分割》第 2 章修订稿 `book-review/drafts/ch02-v3.md`。
> 抽取脚本:`book-review/scripts/extract_code.py`。
> 验证脚本:`book-review/scripts/validate_code.py`。

## 概览

传统图像分割算法的 C++ + OpenCV 实现:Canny 边缘检测、大津阈值、区域生长、形态学分水岭、GrabCut。

## 依赖

- OpenCV 4.x (C++)
- CMake >= 3.16

## 文件清单

| 文件 | 状态 | 备注 |
| --- | --- | --- |
| `cpp/code_2-1.cpp` | 需 OpenCV 4.x | 需 OpenCV / LibTorch 头文件方可编译 |
| `cpp/code_2-2.cpp` | 需 OpenCV 4.x | 需 OpenCV / LibTorch 头文件方可编译 |
| `cpp/code_2-3.cpp` | 需 OpenCV 4.x | 需 OpenCV / LibTorch 头文件方可编译 |
| `cpp/code_2-4.cpp` | 需 OpenCV 4.x | 需 OpenCV / LibTorch 头文件方可编译 |
| `cpp/code_2-5.cpp` | 需 OpenCV 4.x | 需 OpenCV / LibTorch 头文件方可编译 |

## 状态说明

- **可独立运行**:单文件 `python file.py` 通过语法校验且无 undefined name。实际跑通仍可能依赖外部数据/模型权重。
- **教学片段**:源自书稿讲解,依赖书稿上下文中已 `import` 或定义的模块/类。可作为参考阅读,需结合书稿前后文方能运行。
- **语法骨架**:源稿用 `def f(self, ...):` 等 Ellipsis 占位、或在 module top-level 出现 `return` 等纯教学截断写法,本仓库保持与书稿一致,**不修改源码**;标注此状态以提示读者。
- **需 OpenCV 4.x / LibTorch**:C++ 示例,依赖外部 SDK 才能编译。

详细 fenced block 盘点见 [`inventory.md`](inventory.md)。
36 changes: 36 additions & 0 deletions code/ch02/cpp/code_2-1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// -*- coding: utf-8 -*-
// 来源:《深度学习图像分割》第 2 章 — 代码 2-1 基于Canny算子的边缘检测算法
// 原始位置:book-review/drafts/ch02-v3.md:262
// 本文件由 book-review/scripts/extract_code.py 自动抽取生成。
// 修改请回写源稿后重新生成,避免代码与书稿失同步。
#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
// 读取图像:将图像读取为灰度图
Mat img = imread("./example.png", IMREAD_GRAYSCALE);
if (img.empty()) {
cout << "Failed to read image." << endl;
return -1;
}

// 第一步: 高斯平滑
Mat blurred;
// 高斯模糊,去除噪声
GaussianBlur(img, blurred, Size(5, 5), 1.0);

// 第二步: 使用Canny算子进行边缘检测
Mat edges;
double lower_threshold = 50; // 设置Canny算子的低阈值
double upper_threshold = 150; // 设置Canny算子的高阈值
Canny(blurred, edges, lower_threshold, upper_threshold);

// 第三步: 保存分割结果
imwrite("./canny_edges.png", edges);

// 显示结果
namedWindow("Canny Edges", WINDOW_NORMAL);
imshow("Canny Edges", edges);
waitKey(0);
return 0;
}
41 changes: 41 additions & 0 deletions code/ch02/cpp/code_2-2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// -*- coding: utf-8 -*-
// 来源:《深度学习图像分割》第 2 章 — 代码 2-2 大津法阈值分割
// 原始位置:book-review/drafts/ch02-v3.md:379
// 本文件由 book-review/scripts/extract_code.py 自动抽取生成。
// 修改请回写源稿后重新生成,避免代码与书稿失同步。
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
// 读取图像(灰度模式)
Mat image = imread("otsu.png", cv::IMREAD_GRAYSCALE);
if (image.empty()) {
cerr << "无法打开图像文件!" << endl;
return -1;
}

// 创建保存大津法结果的矩阵
Mat otsu_result;

// 使用大津法进行图像二值化,返回阈值
double otsu_thresh_val = threshold(image, otsu_result, 0,
255, THRESH_BINARY + THRESH_OTSU);

// 输出自动计算的大津阈值
cout << "Otsu's Threshold Value: " << otsu_thresh_val << endl;

// 显示原始图像和分割结果
imshow("Original Image", image);
imshow("Otsu Threshold Image", otsu_result);

// 保存分割结果
imwrite("./otsu_result.png", otsu_result);
cout << "Otsu分割结果已保存为otsu_result.png" << endl;

// 等待用户按键关闭窗口
waitKey(0);
return 0;
}
60 changes: 60 additions & 0 deletions code/ch02/cpp/code_2-3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// -*- coding: utf-8 -*-
// 来源:《深度学习图像分割》第 2 章 — 代码 2-3 区域生长算法
// 原始位置:book-review/drafts/ch02-v3.md:480
// 本文件由 book-review/scripts/extract_code.py 自动抽取生成。
// 修改请回写源稿后重新生成,避免代码与书稿失同步。
#include <iostream>
#include <queue>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

// 定义区域生长分割算法
void regionGrowing(const Mat& src, Mat& dst, Point seed, int threshold) {
// 图像尺寸
int rows = src.rows;
int cols = src.cols;

// 初始化输出图像,所有像素初始为0(黑色)
dst = Mat::zeros(src.size(), CV_8UC1);

// 定义8邻域
int dx[8] = { -1, 1, 0, 0, -1, -1, 1, 1 };
int dy[8] = { 0, 0, -1, 1, -1, 1, -1, 1 };

// 获取种子点的灰度值
int seedGrayValue = src.at<uchar>(seed);

// 创建一个队列用于存储待处理的点
queue<Point> pointQueue;
pointQueue.push(Point(seed.x, seed.y));

// 将种子点标记为已处理
dst.at<uchar>(seed) = 255; // 标记区域为白色

// 开始区域生长
while (!pointQueue.empty()) {
Point currentPoint = pointQueue.front();
pointQueue.pop();

// 遍历当前点的8邻域
for (int i = 0; i < 8; i++) {
int newX = currentPoint.x + dx[i];
int newY = currentPoint.y + dy[i];

// 确保邻域点在图像范围内
if (newX >= 0 && newX < cols && newY >= 0 && newY < rows) {
// 如果该点还没有被标记并且与种子点的灰度差小于阈值
int neighborGrayValue = src.at<uchar>(newY, newX);
if (dst.at<uchar>(newY, newX) == 0 &&
abs(neighborGrayValue - seedGrayValue) <= threshold) {
// 将该点加入到队列中
pointQueue.push(Point(newX, newY));
// 标记该点为区域的一部分
dst.at<uchar>(newY, newX) = 255;
}
}
}
}
}
Loading
Loading