{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "16b55161",
   "metadata": {},
   "source": [
    "# 11. 语义分割"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "edad7a4c",
   "metadata": {},
   "source": [
    "## 11.1 简介"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51f4770e",
   "metadata": {},
   "source": [
    "语义分割是计算机视觉的一个重要研究领域，同时也是一项具有挑战性的任务。简单来说，语义分割为一张图像的每个像素分配一个类别标签，即它是一种像素级别的“图像分类”，如图 11-1 所示。但是，这种分类是具有“语义的可解释性”的，即分类类别在真实世界中是有意义的。如图 11-2 所示，我们需要区分人和马以及背景的像素，并将其分为不同的类别。由于语义分割能够提供像素级别的类别信息，因此它可以应用于许多现实世界中的场景，如自动驾驶，行人检测，缺陷检测等。\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic2.zhimg.com/80/v2-9b9ad2e16e149145c802939acc1e2619_1440w.jpg\n",
    "\" width=600>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-1 语义分割是一种像素级的分类任务。</div>\n",
    "</center>\n",
    "\n",
    "在这一章中，我们将一起学习语义分割的相关知识，并动手实现语义分割。\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic3.zhimg.com/80/v2-d048c6ecd2d0299bc6e7c9de071d9b0a_1440w.jpg\n",
    "\" width=300>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-2 语义分割示例。</div>\n",
    "</center>\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3dc5920",
   "metadata": {},
   "source": [
    "## 11.2 数据集和评测度规"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f523e13",
   "metadata": {},
   "source": [
    "在语义分割中，我们通常会选择以下几种常用的数据集进行模型的训练与测试：\n",
    "\n",
    "1. Pascal Voc：Pascal Voc数据集是PASCAL VOC挑战官方使用的数据集。该数据集包含20类共10k的图像，每张图像都有完整的标签。\n",
    "2. Cityscapes：Cityscapes数据集采集自德国及附近国家的50个城市，包括了春夏秋三个季节的街区场景，包含了5k张图像共19个类别，每张图像都有完整的标签。\n",
    "3. ADE20K：ADE20K数据集是2016年MIT开放的场景理解的数据集，共包含150个类别20k张标记完整的图像。\n",
    "4. MS COCO：MS COCO是微软构建的一个数据集，包含有160k共172个类别的图像，可用于多种任务。由于图像标签的标注比较粗糙，在语义分割中我们一般不选择该数据集。\n",
    "\n",
    "在语义分割中，我们通常选择mIoU（mean region intersection over union）作为评测度规。令$n_{ij}$表示本属于第$i$类、被预测为第$j$类的像素点的总数，令$t_i=\\sum_j n_{ij}$表示所有属于第$i$类的像素的总数，令$l$表示类别的总数，则mIoU定义如下：\n",
    "\n",
    "$$mIoU = \\frac{1}{l} \\sum_i \\frac{n_{ii}}{t_i + \\sum_j n_{ji} -n_{ii}}.$$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "479f64ea",
   "metadata": {},
   "source": [
    "## 11.3 语义分割模型——FCN"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6049ec11",
   "metadata": {},
   "source": [
    "我们知道语义分割是实际上是进行像素级别的分类，因此，一个最为直观的语义分割方法便是训练一个可以对像素进行分类的网络。如图 11-3 所示，我们以图像的每一个像素点为中心提取一个“特征块”（patch），并给其赋予中心像素的标签。接着，我们训练一个CNN模型用于对像素进行分类。在对图像上的每一个像素点进行类别预测之后，我们便得到了语义分割的结果，如图 11-3 最右侧图所示。\n",
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic3.zhimg.com/80/v2-020b2e2159e7f509cb67482447142116_1440w.jpg\n",
    "\" width=800>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-3 一个直观的语义分割模型。</div>\n",
    "</center>\n",
    "\n",
    "上述的方法虽然直观，但实际却存在许多的问题：1. 由于一张图像中可能存在成千上万个像素点，且相邻像素点的特征块有大部分的重叠，这一方法计算量大、计算效率低。2. 与整张图像相比，特征块比较小，只能提取图像局部的特征，这使得分类的性能受限。3. 整个过程不是端到端的，它需要有预处理和后处理的环节。为了应对这些问题，2015年Jonathan Long等人在此基础上提出了一种全新的分割网络——FCN（Fully Convolutional Network)。与传统的CNN网络（如Alexnet等）不同的是，在FCN中，网络输出的全连接层被替换为卷积层，如图 11-4 所示。这使得CNN分类的最后一层不再是各个类别的概率，而是一张“热度图”（或特征图），即含有标签信息的图像。不过，在图 11-4 中我们依旧可以发现两个明显的问题：一是随着卷积的进行，图像分辨率越来越低，最终输出的图像比原图要小很多；二是输出的标签信息十分的粗糙。为了解决上述两个问题，Jonathan提出了两种有效的解决手段：上采样（Unsampling）和跳跃连接（Skip-connection）。\n",
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic1.zhimg.com/80/v2-d7ed66df02bd43d859639dc0fb76adf0_1440w.jpg\n",
    "\" width=600>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-4 用卷积层替换所有的全连接层。</div>\n",
    "</center>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb1393c6",
   "metadata": {},
   "source": [
    "### 11.3.1 上采样"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7a4236a",
   "metadata": {},
   "source": [
    "\n",
    "为了解输出的热度图大小明显小于输入图像的问题，Jonathan 提出对降维后的特征图进行上采样，使其和原图像的大小保持一致。上采样指的是任何可以让图像变成更高分辨率的技术，一般可以通过双线性插值法实现。如图 11-5 所示，若已知$f(x,y)$在点$Q_{11}=(x_{1}, y_{1}), Q_{12}=(x_{1}, y_{2}), Q_{21}=(x_{2}, y_{1}), Q_{22}=(x_{2}, y_{2})$处的值，求$f$在点$P$处的值。求值的过程实际上就是双线性插值的过程。我们首先先在$x$方向上进行插值：\n",
    "$$f(x, y_{1}) \\approx \\frac{x-x_{1}}{x_{2}-x_{1}}[f(Q_{21})-f(Q_{11})]+f(Q_{11})=\\frac{x_{2}-x}{x_{2}-x_{1}} f(Q_{11})+\\frac{x-x_{1}}{x_{2}-x_{1}} f(Q_{21}) \\\\ f(x, y_{2}) \\approx \\frac{x-x_{1}}{x_{2}-x_{1}}[f(Q_{22})-f(Q_{12})]+f(Q_{12}) =\\frac{x_{2}-x}{x_{2}-x_{1}} f(Q_{12})+\\frac{x-x_{1}}{x_{2}-x_{1}} f(Q_{22})\n",
    "$$\n",
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic2.zhimg.com/80/v2-66432863549dccc82a5ac033cbb1e035_1440w.webp\n",
    "\" width=200>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-5 双线性插值法举例。</div>\n",
    "</center>\n",
    "\n",
    "接着，我们在$y$方向上进行插值：\n",
    "\n",
    "$$f(x, y)  \\approx f(x, y_{1})+\\frac{y-y_{1}}{y_{2}-y_{1}}[f(x, y_{2})-f(x, y_{1})] \n",
    "=\\frac{y_{2}-y}{y_{2}-y_{1}} f(x, y_{1})+\\frac{y-y_{1}}{y_{2}-y_{1}} f(x, y_{2}) \n",
    "=\\frac{1}{(x_{2}-x_{1})(y_{2}-y_{1})}[\\begin{array}{ll}x_{2}-x & x-x_{1}\\end{array}] \\left[\\begin{array}{ll} f(Q_{11}) & f(Q_{12}) \\\\ f(Q_{21}) & f(Q_{22})\\end{array}\\right]\\left[\\begin{array}{l} y_{2}-y \\\\y-y_{1}\\end{array}\\right]\n",
    "$$\n",
    "\n",
    "如此，我们便可以求出点$P$处的值。同样，给定一副压缩后的图像，我们可以通过双线性插值法对其进行上采样，如图 11-6 所示，将其和原图像保持大小一致。\n",
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic1.zhimg.com/80/v2-1f0142501d3ba76e85913e0a68f599e4_1440w.jpg\n",
    "\" width=400>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-6 对一副$2\\times 2$的图像上采样，将图像大小变为$4\\times 4$。</div>\n",
    "</center>\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86a32f46",
   "metadata": {},
   "source": [
    "### 11.3.2 跳跃连接"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d8b5f05",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic4.zhimg.com/80/v2-da4000ce2e564398afe9faafc107e0b7_1440w.jpg\n",
    "\" width=800>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-7 融合中间卷积层的特征，这些特征包含了局部与全局的信息，也包含了深度的与浅层的信息。</div>\n",
    "</center>\n",
    "\n",
    "由于网络输出的热度图过于粗糙（如图 11-4），在上采样的过程中所得到的标签信息会非常的模糊。因此，Jonathan 提出可以融合网络中间的卷积层的特征，如图 11-7所示。这些特征包含了全局的与局部的信息，也包含了浅层的与深层的信息。因此，我们可以利用这些信息帮助模型在上采样过程中获得不同维度的特征，融合更多特征的同时也保留更多细节，帮助模型更精细的重建图像信息，弥补上采样带来的损失。\n",
    "\n",
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://img-blog.csdnimg.cn/9a021d7bf5d94c97a3c1741939a65651.png#pic_center\n",
    "\" width=700>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-8 FCN中的跳跃连接</div>\n",
    "</center>\n",
    "\n",
    "\n",
    "具体而言，如图 11-8 所示，对于pool5输出的特征图，我们可以直接对其上采样32倍得到与原图像同样大小的特征图，这样的模型被称为FCN-32s；我们也可以将pool4的特征图与两倍上采样之后的conv7的特征图进行融合（即在RGB通道上直接进行相加），再将其进行16倍的上采样，这样的模型被称为FCN-16s；同样，我们还可以将池化层pool3的输出分别于2倍上采样后的poo4的输出和4倍上采样后的conv7层的输出进行融合得到新的特征图，再将这个特征图进行8倍上采样得到原图大小的特征图，这样的模型被称为FCN-8s。当特征图复原到原图大小之后，我们利用特征图的标签信息与图像真实标签信息进行交叉熵的计算，并作为模型整体的损失函数训练模型。FCN的整体框架如图 11-9 所示。\n",
    "\n",
    "\n",
    "\n",
    "<center>\n",
    "    <img style=\"border-radius: 0.3125em;\" \n",
    "    src=\"https://pic3.zhimg.com/80/v2-b6471052837da9adfa436a6a9bdf4fbe_1440w.jpg\n",
    "\" width=600>\n",
    "    <br>\n",
    "    <div style=\"color:orange; \n",
    "    display: inline-block;\n",
    "    color: #999;\n",
    "    padding: 2px;\">图11-9 FCN的整体框架。</div>\n",
    "</center>\n",
    "\n",
    "接下来，我们将动手编写FCN。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "734924ee",
   "metadata": {},
   "source": [
    "## 11.4 总结"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e42063ef",
   "metadata": {},
   "source": [
    "在本章中，我们学习了语义分割的相关知识。我们了解了分割网络与分类网络的区别，在此基础上学习了用于语义分割的网络FCN，之后动手实现了FCN的相应功能并在Pascal Voc数据集上进行了训练和测试。作为计算机视觉的重要研究内容之一，语义分割为后续的图像语义理解如目标检测、实例分割等奠定了一定的基础。接下来，我们将继续学习另一种图像语义理解的研究——目标检测。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b53feef",
   "metadata": {},
   "source": [
    "## 11.5 习题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f92a6ec",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "be7840f2",
   "metadata": {},
   "source": [
    "## 参考文献"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49822524",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
