图像的形状相关参数顺序

图像有单通道和多通道两种分类。我们先用 OpenCV 读一张图片看看它是怎么存放的。读入的图片如下:

   

import cv2

img = cv2.imread('test.jpg')
print(img.shape)
print(type(img))

"""
(36, 100, 3)
<class 'numpy.ndarray'>
"""

可见一幅图像是被保存为 ndarray 类型的多维数组,对于一个三通道的图像而言,多维数组每个维度的含义是:$(height,width,channel)$,

或者简写为 $(h,w,c)$。所以我们想要创建一幅图像就可以创建一个 ndarray,并按这个形状规则给定各个维度的大小。

import cv2
import numpy as np

img = np.zeros((36, 100), dtype=np.uint8) + 255    # 创建一个灰度图像,单通道
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)        # 灰度图像转为 BGR 图像,三通道
print(img.shape)
print(type(img))

"""
(36, 100, 3)
<class 'numpy.ndarray'>
"""

当我们直接通过 img 这个 ndarray 类型来进行访问像素,调整形状等一系列操作时,按 $(h,w,c)$ 的顺序不会有问题,但当我们间接通过

OpenCV 的 API 来操作图像的时候,这个顺序就不对了。这是由于 OpenCV 的坐标系并不是我们平常认为的那么定义的。

OpenCV  的坐标体系:零点坐标为图片的左上角,X 轴为图像矩形的上面那条水平线;Y 轴为图像矩形左边的那条垂直线。

    

所以当我们调用 API 来操作图像时,提供的坐标 $(x,y)$ 表示的含义是宽和高,即 $(w,h)$,举个例子:

import cv2

img = cv2.imread('test.jpg')
print(img.shape)
img = cv2.resize(img, (200, 36), interpolation=cv2.INTER_NEAREST)
print(img.shape)

"""
(36, 100, 3)
(36, 200, 3)
"""

可见 cv2.resize 修改的是图像的宽度,在其它提供坐标的地方都是按 $(w,h)$ 的顺序,比如 cv2.circle 等。

另外需要注意的是:OpenCV 读到的图像通道顺序是 $bgr$

接下来我们用 python 中的 PIL 包来读图片看看,PIL 是一个图像处理的轻量级的库,功能没有 OpenCV 强大。用 PIL 包打开上面的那张图片:

from PIL import Image

img = Image.open('test.jpg')
print(img.size)

"""
(100, 36)
"""

size 返回的是图片的形状是 $(w,h)$。我们再调整一下图片大小:

from PIL import Image

img = Image.open('test.jpg')
print(img.size)
img = img.resize((100, 200))
print(img.size)

"""
(100, 36)
(100, 200)
"""

所以 resize 的参数顺序依然是 $(w,h)$。

最后我们来看下 skimage 这个包,依然是上面那张图片:

from skimage import io, transform

img = io.imread('test.jpg')
print(img.shape)
img = transform.resize(img, (36, 200))
print(img.shape)

"""
(36, 100, 3)
(36, 200, 3)
"""

 可以看出,这个包无论是读取图像还是间接操作图像都是按 $(h,w)$ 顺序。

posted @ 2020-12-05 10:36  _yanghh  阅读(550)  评论(0编辑  收藏  举报