作者ID: 流继承


Ⅰ. 数字图像的表示

0x00 位数

计算机采用0/1编码的系统,数字图像也是利用0/1来记录信息。
我们平常接触的图像都是8位数图像,包含0~255灰度。

  • 0:代表最黑
  • 1:表示最白

0x01 二值图像

一幅二值图像的二维矩阵仅由0、1两个值构成;

“0”代表黑色,“1”代白色。由于每一像素(矩阵中每一元素)。

其取值仅有 0 和 1 两种可能,所以计算机中二值图像的数据类型通常为 1 个二进制位。

二值图像通常用于文字、线条图的扫描识别 (OCR) 和掩膜图像的存储。

灰度图:

每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗黑色到最亮的白色的灰度。

尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。

灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;

但是,灰度图像在黑色与白色之间还有许多级的颜色深度。

灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,

用于显示的灰度图像通常用每个采样像素8位的非线性尺度来保存,

这样可以有256级灰度(如果用16位,则有65536级)。

彩色图:

每个像素通常是由 RGB三个分量来表示的,分量介于 (0,255)

RGB图像与索引图像一样都可以用来表示彩色图像。

与索引图像一样,它分别用 RGB三原色的组合来表示每个像素的颜色。

但与索引图像不同的是,RGB图像每一个像素的颜色值(由 RGB三原色表示),直接存放在图像矩阵中,由于每一像素的颜色需由 RGB三个分量来表示,

M,N分别表示图像的行列数,

3 个M×N的二维矩阵分别表示各个像素的 RGB三个颜色分量。

RGB图像的数据类型一般为 8 位无符号整形,通常用于表示和存放真彩色图像。

  • 像素点取值范围:0−255

    Ⅱ. OpenCV 基本操作

    0x00 图像 I/O 操作的 API

     cv2.imread()     # 读取图像
    
    • cv2.IMREAD*COLOR:以彩色模式加载图像,任何图像的透明度都被忽略,这是默认参数。
    • cv2.IMREAD*GRAYSCALE:以灰度模式加载图像
    • cv.IMREAD_UNCHANGED:包括alpha通道的加载图像模式。
    * 注: 可以使用 1、0 或者 -1 来替代上面三个标志
    cv2.imshow(): #显示图像

    注意:在调用显示图像的 API 后,要调用 cv.waitKey() 给图像绘制留下时间,否则窗口会出现无响应情况,并且图像无法显示出来。

    cv2.imwrite():        #保存图像
    

    在图像上绘制几何图像:

    • cv2.line(): 绘制直线
    • cv2.circle(): 绘制圆形
    • cv2.rectangle(): 绘制矩形
    • cv2.putText(): 在图像上添加文字
      直接使用行列索引获取图像中的像素并进行修改

    图像的属性:

    拆分通道:

    cv.split()
    

    通道合并:

    cv.merge()
    

    色彩空间的改变:

    cv.cvtColor(input_image,flag)
    

    举例:

    • 数据读取 —— 图像:
    image = cv2.imread("sunshine.jpg")
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    cv2.imshow("Over theClouds - gray", gray_image)
    cv2.waitKey(0)#等待时间,毫秒级,0表示按任意键终止
    

    • 截取部分图像数据
    img = cv2.imread("sunshine.jpg")#读取图片
    sunshine = img[0:80, 10:200]#切片
    cv2.imshow("sunshine", sunshine)
    cv2.waitKey(0)#等待时间,毫秒级,0表示按任意键终止
    
    • 颜色通道提取

    颜色排列为 BGR(与三原色 RGB相反)

    只保留 R通道

    img[:, :, 0] = 0
    img[:, :, 1] = 0
    

    只保留 G通道

    img[:, :, 0] = 0
    img[:, :, 2] = 0
    

    边界填充

    top_size, bottom_size, left_size, right_size = (200, 200, 200, 200)
    replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
    reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT)
    reflect_101= cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT_101)
    wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_WRAP)
    constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_CONSTANT, value=0)#zero padding
    
    plt.subplot(231), plt.imshow(sunshine), plt.title('ORIGINAL')
    plt.subplot(232), plt.imshow(replicate), plt.title('REPLICATE')
    plt.subplot(233), plt.imshow(reflect), plt.title('REFLECT')
    plt.subplot(234), plt.imshow(reflect_101), plt.title('REFLECT_101')
    plt.subplot(235), plt.imshow(wrap), plt.title('WRAP')
    plt.subplot(236), plt.imshow(constant), plt.title('CONSTANT')
    

    • BORDER_REPLICATE:复制法,复制最边缘像素
    • BORDER_REFLECT: 反射法,对感兴趣的图像中的像素在两边进行复制
    • BORDER_REFLECT_101:反射法,一最边缘的像素为轴
    • BORDER_WRAP:外包装法
    • BORDER_CONSTANT:常量法,常数值填充

    0x01 算数操作

    图像的加法:

    你可以使用 OpenCV 的 cv.add() 函数把两幅图像相加,

    或者可以简单地通过 Numpy 操作添加两个图像。

    譬如 res=img1+img2,两个图像应具有相同的大小和类型,或第二个图像可以是标量值。

    注意

    OpenCV加法和 Numpy 加法之间存在差异,OpenCV 的加法是饱和操作,而 Numpy 添加是模运算。

    参考以下代码

    >>> x = np.uint8([250])
    >>> y = np.uint8([10])
    >>> print( cv.add(x,y) ) # 250+10 = 260 => 255
    [[255]]
    >>> print( x+y )          # 250+10 = 260 % 256 = 4
    [4]
    

    这种差别在你对两幅图像进行加法时会更加明显,OpenCV 的结果会更好一点。

    所以我们尽量使用 OpenCV中的函数。

    图像融合:

    这其实也是加法,但是不同的是两幅图像的权重不同,

    这就会给人一种混合或者透明的感觉。

    图像混合的计算公式如下:

    g(x)=(1−α)f0(x)+αf1(x)

    通过修改 α的值(0→1),可以实现非常炫酷的混合!

    示例:

    img_sunshine = cv2.resize(img_sunshine, (500, 250))
    img_cloud = cv2.resize(img_cloud, (500, 250))
    
    res = cv2.addWeighted(img_sunshine, 0.4, img_cloud, 0.6, 0)
    plt.imshow(res)
    plt.show()
    

    res2 = cv2.resize(img_sunshine, (0, 0), fx=3, fy=1)
    plt.imshow(res2)
    plt.show()
    

    总结

    1. 图像加法:将两幅图像加载一起
      cv.add()
    2. 图像的混合:将两幅图像按照不同的比例进行混合
      cv.addweight()
      注意:这里都要求两幅图像是相同大小的。