二、从卷积到卷积神经网络

1 图像的基本表示

深度视觉是处理图像的学科,因此我们需要从图像本身开始说起。来看这张孔雀图像。

在之前的课程中,我为大家展示过图像数据在计算机中的基本结构。首先,每张图像都是以一个三维Tensor或者三维矩阵表示,其三个维度分别是(高度 height,宽度 width,通道 channels)。

高度和宽度往往排列在一起,一般是先高后宽的顺序,两者共同决定图像的尺寸大小。如上图,高度1707为则说明图像在竖直方向有1707个像素点(有1707列),同理宽度则代表水平方向的像素点数目(有2560行),因此如上的孔雀图总共有1707*2560 = 4,369,920个像素点。

通道是单独的维度,通常排在高度宽度之后,但也有可能是排在第一位。它决定图像中的轮廓、线条、色彩,基本决定了图像中显示的所有内容,尤其是颜色,因此又叫做色彩空间(color space)。

怎么理解通道呢?你可能在很年幼的时候就学过一些基本的色彩知识(感谢九年义务教育中的美术课),例如,自然界中的颜色都是由“三原色”红黄蓝构成的,将红色和蓝色混在一起会得到紫色,将红色和黄色混在一起会得到橙色,白色的阳光可以经由三棱镜分解成七彩的光谱等等。计算机的世界中的颜色也是由基本颜色构成的,在计算机的世界里,用于构成其他颜色的基础色彩,就叫做“通道”。

我们最常用的三种基本颜色是红绿蓝(Red, Green, Blue, 简写为RGB),所以最常用的通道就是RGB通道。我们通过将红绿蓝混在一起,创造丰富的色彩。例如,上面的孔雀图,其实是下面三张红、绿、蓝三色的图像叠加而成。

不难注意到,通道就是和原图尺寸一致、像素点数量一致的、只能够显示其通道颜色的图像。例如,红色通道就只能显示红色,绿色通道就只能显示绿色,蓝色同理。

在通道的每一个像素点上,都有[0,255]之间的整数值,这些整数值代表了“该通道上颜色的灰度”。在图像的语言中,“灰度”就是明亮程度。数字越接近255,就代表颜色明亮程度越高,越接近通道本身的颜色,数字越接近0,就代表颜色的明亮程度越弱,也就是越接近黑色。(仔细观察孔雀脖子的部分,孔雀脖子在图像上是蓝色的,这种蓝色主要由蓝色通道和绿色通道构成,几乎没有任何红色通道的元素,因此在红色通道的图片中,孔雀脖子几乎都是黑的。)
在图像的矩阵中,我们可以使用索引找出任意像素的三个通道上的颜色的明度,例如,对于第0行、第0列的样本而言,可以看到一个三列的矩阵,这三列就分别代表着红色、绿色、蓝色的像素值。当三个值都不为0时,这个像素在三个通道上都有颜色。相对应的,最纯的红色会显示为(255,0,0),最纯的蓝色就会显示为(0,0,255),绿色可以此类推。当像素值为(0,0,0)时,这个像素点就为黑色,当像素值为(255,255,255),像素点就为白色。通道上像素的灰度,也就是矩阵中的值几乎100%决定了图像会呈现出什么样子。
在图像的世界中有许多“通道”类型,就和计算机世界有许多编码类型一样,较为常见的通道有以下几种:

灰度通道:灰度在计算机视觉中是指“明暗程度”,而不是指“灰色”,因而灰度通道也不是指图像是灰色的通道,而是只有一种颜色的通道,同理,灰度图像是只有一个通道的图像。所以RGB通道中的任意一个通道单独拿出来之后,都可以用灰度(明暗)来显示。就像我们在Fashion-MNIST数据集中所见到的,灰度图像的shape最后一列为1,索引出来的值中只有一个数字,这个数字就是这种唯一颜色的明度。当你看见图像的通道数为1,无论可视化之后图像显示什么视觉颜色,它都只是表示单一颜色的明度而已。(没有人怀疑过为什么fashion-MNIST中的图绘制出来是黄绿色的吗?你现在了解,其实蓝绿色也只是明度的一种表示)。
RGB色彩空间:数字世界最常见的彩色通道,分别表示红、绿、蓝三种电子成像的基本颜色。

CMYK色彩空间:用于彩色打印机成像的通道,由青色(Cyan)、品红(Magenta)、黄色(Yellow)和黑色(Black)构成,因此是四维通道,在图像结构中会显示为(高度,宽度,4)。

HSV(或HSL)色彩空间:HSV通道是为人们描述和解释颜色而创建的,H代表色相,S代表饱和度,V代表亮度。(H色相这张图以什么颜色为主,S颜色是否鲜艳,亮度是亮度)

以上三种空间可以自由切换(会产生数据损失),在OpenCV中也有支持切换的函数可以调用。在计算机视觉中,我们可能遇见各种通道类型的图片,当我们需要对图像进行特定操作时,我们必须了解这些通道并了解如何在他们之间进行转换。
另一种非常常见的色彩空间是RGBA,它也拥有四维通道,分别是(红色,绿色,蓝色,透明度alpha)。透明度alpha的取值范围在0-1之间。当一个像素的RGB显示为(0,255,0)时,则说明这个像素里是明度最高的绿色,但加上透明度之后,色彩就会变得“透明”。RGBA可以提供更丰富的色彩样式,让图像的色彩变得更加绚丽。

2 OpenCV令像素变化来改变图像

一张图像显示什么内容是由通道中的像素值决定的,只要能够操作像素,就能够改变图像,这是图像能够被“处理”的基本条件。在这一节,我们就使用OpenCV来对图像进行一些改变。首先,先导入一张自己的图像来看看,大家可以根据自己的喜好导入相应的图像。

import numpy as np
import matplotlib.pyplot as plt
import cv2#读取计算机中的图像
img = cv2.imread('/Users/zhucan/Desktop/blue-peacock.jpg') #不要有中文,不要有空格
img
# array([[[ 20,  27,  30],
#         [ 22,  29,  32],
#         [ 24,  31,  34],
#         ...,
#         [109, 153,  84],
#         [108, 152,  83],
#         [104, 148,  79]],#        [[ 23,  30,  33],
#         [ 26,  33,  36],
#         [ 28,  35,  38],
#         ...,
#         [108, 152,  83],
#         [108, 152,  83],
#         [105, 149,  80]],#        [[ 20,  27,  30],
#         [ 24,  31,  34],
#         [ 26,  33,  36],
#         ...,
#         [107, 151,  82],
#         [107, 151,  82],
#         [104, 148,  79]],#        ...,#        [[ 89, 104, 106],
#         [ 98, 111, 113],
#         [ 76,  85,  88],
#         ...,
#         [111, 133, 169],
#         [113, 132, 169],
#         [111, 133, 169]],#        [[ 92, 107, 109],
#         [100, 113, 115],
#         [ 78,  87,  91],
#         ...,
#         [115, 137, 173],
#         [116, 138, 174],
#         [116, 138, 174]],#        [[ 94, 112, 113],
#         [102, 117, 119],
#         [ 80,  91,  95],
#         ...,
#         [118, 139, 177],
#         [118, 141, 179],
#         [119, 142, 180]]], dtype=uint8)
img[0,0,:]
#array([20, 27, 30], dtype=uint8)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #转换方式
#OpenCV在读取图像时会默认图像通道的顺序是BGR
img.shape
#(1707, 2560, 3)
#展示图片
plt.figure(dpi=150) #画布,dpi是分辨率
plt.imshow(img)
plt.axis('off'); #不显示坐标轴

img.dtype
#dtype('uint8')
a = np.array([0,1,255],dtype="uint8") #一个图像中的一个像素点,一个像素点上的三个通道的值
a
#array([  0,   1, 255], dtype=uint8)
a + 10
#array([10, 11,  9], dtype=uint8)
a - 10
#array([246, 247, 245], dtype=uint8)
img = img*1.0        #变成浮点数
img
#array([[[ 30.,  27.,  20.],
#        [ 32.,  29.,  22.],
#        [ 34.,  31.,  24.],
#        ...,
#        [ 84., 153., 109.],
#        [ 83., 152., 108.],
#        [ 79., 148., 104.]],
#
#       [[ 33.,  30.,  23.],
#        [ 36.,  33.,  26.],
#        [ 38.,  35.,  28.],
#        ...,
#        [ 83., 152., 108.],
#        [ 83., 152., 108.],
#        [ 80., 149., 105.]],
#
#       [[ 30.,  27.,  20.],
#        [ 34.,  31.,  24.],
#        [ 36.,  33.,  26.],
#        ...,
#        [ 82., 151., 107.],
#        [ 82., 151., 107.],
#        [ 79., 148., 104.]],
#
#       ...,
#
#       [[106., 104.,  89.],
#        [113., 111.,  98.],
#        [ 88.,  85.,  76.],
#        ...,
#        [169., 133., 111.],
#        [169., 132., 113.],
#        [169., 133., 111.]],
#
#       [[109., 107.,  92.],
#        [115., 113., 100.],
#        [ 91.,  87.,  78.],
#        ...,
#        [173., 137., 115.],
#        [174., 138., 116.],
#        [174., 138., 116.]],
#
#       [[113., 112.,  94.],
#        [119., 117., 102.],
#        [ 95.,  91.,  80.],
#        ...,
#        [177., 139., 118.],
#        [179., 141., 118.],
#        [180., 142., 119.]]])
b = np.array([280,-3,250])
np.clip(b,0,255) #用来将数字限制在某个范围内的函数
#array([255,   0, 250])
img = img/255
img
# array([[[0.11764706, 0.10588235, 0.07843137],
#         [0.1254902 , 0.11372549, 0.08627451],
#         [0.13333333, 0.12156863, 0.09411765],
#         ...,
#         [0.32941176, 0.6       , 0.42745098],
#         [0.3254902 , 0.59607843, 0.42352941],
#         [0.30980392, 0.58039216, 0.40784314]],#        [[0.12941176, 0.11764706, 0.09019608],
#         [0.14117647, 0.12941176, 0.10196078],
#         [0.14901961, 0.1372549 , 0.10980392],
#         ...,
#         [0.3254902 , 0.59607843, 0.42352941],
#         [0.3254902 , 0.59607843, 0.42352941],
#         [0.31372549, 0.58431373, 0.41176471]],#        [[0.11764706, 0.10588235, 0.07843137],
#         [0.13333333, 0.12156863, 0.09411765],
#         [0.14117647, 0.12941176, 0.10196078],
#         ...,
#         [0.32156863, 0.59215686, 0.41960784],
#         [0.32156863, 0.59215686, 0.41960784],
#         [0.30980392, 0.58039216, 0.40784314]],#        ...,#        [[0.41568627, 0.40784314, 0.34901961],
#         [0.44313725, 0.43529412, 0.38431373],
#         [0.34509804, 0.33333333, 0.29803922],
#         ...,
#         [0.6627451 , 0.52156863, 0.43529412],
#         [0.6627451 , 0.51764706, 0.44313725],
#         [0.6627451 , 0.52156863, 0.43529412]],#        [[0.42745098, 0.41960784, 0.36078431],
#         [0.45098039, 0.44313725, 0.39215686],
#         [0.35686275, 0.34117647, 0.30588235],
#         ...,
#         [0.67843137, 0.5372549 , 0.45098039],
#         [0.68235294, 0.54117647, 0.45490196],
#         [0.68235294, 0.54117647, 0.45490196]],#        [[0.44313725, 0.43921569, 0.36862745],
#         [0.46666667, 0.45882353, 0.4       ],
#         [0.37254902, 0.35686275, 0.31372549],
#         ...,
#         [0.69411765, 0.54509804, 0.4627451 ],
#         [0.70196078, 0.55294118, 0.4627451 ],
#         [0.70588235, 0.55686275, 0.46666667]]])

现在我们在图像上做一些改变。之前我们说过,像素值越接近255,就表示图像的“明度”越高,像素值越越接近0,就表示图像会变得越暗,当我们对图像归一化后,像素值越接近1就越亮,越接近0就越暗。所以我们可以通过对像素值做线性变换,来调整图像的“明暗”程度。

#调亮画面
img_ = np.clip(img + 100/255,0,1) #np.clip是一个抹掉范围外值的函数
plt.figure(dpi=100)
plt.imshow(img_)
plt.axis('off');

#调暗画面
img_ = np.clip(img - 100/255,0,1)
plt.figure(dpi=100)
plt.imshow(img_)
plt.axis('off');

#让画面更鲜艳
img_ = np.clip(img*0.5,0,1)
#原本就很大的值会增长得更快,因此原本就很鲜艳的颜色会变得更加鲜艳,增加对比度
plt.figure(dpi=100)
plt.imshow(img_)
plt.axis('off');

img = cv2.imread('/Users/zhucan/Desktop/blue-peacock.jpg')
#OpenCV默认读取后的图像通道是BGR,为了调整饱和度,我们直接将通道转换为HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)#这里分解出的是uint8,要在uint8上进行数值操作则必须先更换为浮点数
#h += np.clip(s*1.0+100,0,255).astype("uint8") # 色相
s += np.clip(s*1.0+100,0,255).astype("uint8") # 饱和度
#v += np.clip(s*1.0+100,0,255).astype("uint8") # 亮度
final_hsv = cv2.merge((h, s, v))
#为了绘图,这里是转回RGB,而不是BGR
img_s = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2RGB)
plt.figure(dpi=100)
plt.imshow(img_s)
plt.axis('off');

plt.figure(dpi=150) #画布,dpi是分辨率
plt.imshow(img)
plt.axis('off'); #不显示坐标轴


你发现了吗?在掌握了一些浅层图像原理之后,我们就可以通过改变像素值来改变图像的模样,这再次证明了,通道上像素的灰度,也就是张量中的值几乎100%决定了图像会呈现出什么样子。因此,只要给与[0,255]之间的值,令其结构形似一张图像(高,宽,3),我们甚至可以自己“瞎编”出一张图像来,所以任意矩阵都可以被以图像的方式进行可视化。

pic = np.random.randint(0,255,size=(300,300,3))
plt.figure(dpi=100)
plt.imshow(pic)
plt.axis('off');


值得注意的是,由于灰度的存在,图像是可以被表示成二元函数的,通常写作f(x,y)f(x, y)f(x,y)或f(i,j)f(i, j)f(i,j)。在这个函数中,函数的两个自变量是图像的宽度与高度,函数值就是该通道上的灰度。

是不是看起来和梯度下降中梯度的图像有些类似呢?由于图像可以被作为二元函数表示,调整亮度等操作也可以用数学的方式来表示:g(i,j)=α⋅f(i,j)+βg(i, j)=\alpha \cdot f(i, j)+\betag(i,j)=α⋅f(i,j)+β

其中,g(i,j)g(i,j)g(i,j)表示输出图像,f(i,j)f(i,j)f(i,j)表示输入图像,α\alphaα控制对比度,β\betaβ控制亮度。这就是视觉领域最简单的线性变化。

有了函数,我们自然也可以对图像的函数进行求导、积分等操作。这种表示大大拓宽了我们可以在图像上进行的操作,只要我们控制像素值的范围在[0,255],我们就可以在图像上进行任意的数学变换。计算机视觉研究如何让计算机从图像或图像序列中获取信息并理解其信息,其主要目的在于从图像或图像序列中提取对世界的描述。什么样的图像信息,才有利于对世界进行描述呢?在人们探索这个问题的时候,发现了一个很有趣并且有用的数学变化,下一节我们来谈谈这种对整个计算机视觉领域影响深远数学变化。

Lesson 16.2 图像的基本操作相关推荐

  1. Python练习 | Python之图像的基本操作和处理

    博主github:https://github.com/MichaelBeechan 博主CSDN:https://blog.csdn.net/u011344545 ***************** ...

  2. matlab中的图像,MATLAB中图像的基本操作

    MATLAB中图像的基本操作 1.读取.显示图片 MATLAB中提供了immread()与imshow()函数读取和显示图片.其中读取函数imread()原型: imread: A= imread(f ...

  3. python opencv 图像切割_【OpenCV+Python】图像的基本操作与算术运算

    图像的基本操作 在上个教程中,我们介绍了使用鼠标画笔的功能.本次教程,我们将要谈及OpenCV图像处理的基本操作. 本次教程的所有操作基本上都和Numpy相关,而不是与OpenCV相关.要使用Open ...

  4. 【学习OpenCV4】图像的基本操作

    图像的基本操作 一.图像色彩空间转换 1.1 基本知识 1.2 创建类 1.3 编写主函数 1.4 测试结果 二.图像对象的创建与复制 2.1 什么是Mat 2.2 创建空白图像 2.3 图像的复制 ...

  5. opencv入门系列教学(五)图像的基本操作(像素值、属性、ROI和边框)

    0.序言 每个图像是由一个个点组成的,而这些点可以表示为像素值的形式. 这篇博客里我们将学会: 访问像素值并修改它们 . 访问图像属性 . 设置感兴趣区域(ROI) . 分割和合并图像. 对于图像的基 ...

  6. Lesson 16 Mary had a little lamb 内容鉴赏

    Lesson 16 Mary had a little lamb 1. Mary and her husband Dimitri lived in the tiny village of Perach ...

  7. Opencv-Python学习(一)———图像的基本操作

    目录 一.Opencv简介 二.安装Opencv 三.Opencv图像的基本操作 一.Opencv简介 OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以 ...

  8. 【opencv学习笔记】003之图像像素基本操作(获取像素指针、范围处理)及掩膜操作(filter2D)详解

    目录 一.前言 二.图像像素基本操作 1.获取图像像素指针 1.获取图像像素指针是什么? 2.相应API 3.获取目的 2.像素范围处理saturate_cast 1.像素范围处理是什么? 2.像素范 ...

  9. matlab 图像上下翻,Matlab图像九宫格基本操作(翻转,镜像等)+位图操作

    Matlab图像九宫格基本操作(翻转,镜像等)+位图操作 Matlab图像九宫格基本操作(翻转,镜像等)+位图操作 这次blog提到的操作对于matlab来说都很基础,而且对于有编程和计算机基础的人来 ...

最新文章

  1. jenkins部署三种构建方式的详细步骤
  2. HTML示例06---水平线
  3. html云文件系统,一种HTML5云文件系统
  4. 智能手机的超性能语音识别技术简介
  5. linux 屏蔽信号 sig_kill sig_stop,linux 信号处理
  6. 北京大学生物信息学课程(5)
  7. 【数据分析师自学系列】Kettle下载安装、Kettle环境部署
  8. web前端网页设计期末课程大作业:旅游网页主题网站设计——紫色的旅游开发景点网站静态模板(4页)HTML+CSS+JavaScript
  9. matlab标题斜体_Matlab绘图中下标、斜体及希腊字母的使用方法
  10. ❀论文篇 ❀ 2010-2022,情绪识别(EmotionRecognition)论文
  11. Windows中mysql使用命令行登录
  12. 7月20日到12月3日
  13. 软件测试过程中有哪些风险?
  14. 飞机大战Python全代码 + 图片
  15. CDH6集成Flink【提供安装包】
  16. php 字典树实现,数据结构之「字典树」
  17. 盘点ML/DL领域国外和国内的顶级大牛
  18. wpf图表-Visifire使用教程分享
  19. MT6735 L版本开机待机后概率性唤醒不了
  20. jzoj3208. 【JSOI2013】编程作业(kmp)

热门文章

  1. android布局翻译,android – 使用翻译动画将视图从一个布局转换为另一个布局
  2. mysql 表中添加数据类型_MySQL数据表添加字段(三种方式)
  3. 栏目图片 栏目描述_网站描述怎么写?对网站优化有什么作用?
  4. 胡正是什么lisp_《亲爱的挚爱的》演员公开,吴白还是胡一天,grunt却换了人
  5. opencv 显示图片(直接)
  6. 文巾解题 面试题 01.03. URL化
  7. 强化学习笔记4:强化学习分类
  8. python函数整理
  9. 趣话题:底层码农的心酸,那么我们 如何避免成为底层码农呢?
  10. 强化学习(十二) Dueling DQN