为什么cv2.resize会对请求的维度进行转置?

5
            s1 = image.shape  # Image is an opencv2 image (ndarray)
            w,h,d = s1
            image_ = cv2.resize(image, (w*2, h*2), interpolation = cv2.INTER_CUBIC)
            s2 = image_.shape

在上述代码中,我请求输出的大小为(960,1280),但实际得到的是(1280,960)。这是怎么回事呢?
  image_ = cv2.resize(image, None, fx=2, fy=2, interpolation = cv2.INTER_CUBIC)

...正常工作(不需要指出这一点)。

在此输入图片描述

可运行的示例:

import cv2

def run():
    cap = cv2.VideoCapture(0)

    while cap.isOpened():
        success, image = cap.read()  # (480, 640, 3)
        if not success:
            print("Ignoring empty camera frame.")
            continue

        s1 = image.shape
        w, h, d = s1
        s2 = (w * 2, h * 2)
        image_ = cv2.resize(image, s2, interpolation=cv2.INTER_CUBIC)
        s3 = image_.shape
        cv2.imshow('Camera',
                   image_
                   )

        key = cv2.waitKey(5)
        if key & 0xFF == 27:
            break
    cap.release()


if __name__ == '__main__':
    run()


1
这是在处理图像时经典的问题。在日常用语中,图像大小是按宽度,然后高度引用的(例如1920 x 1080)。矩阵相反是按行(高度索引),然后列(宽度)索引,因此您需要记住转置轴。再加上现代大多数张量图像表示将颜色通道放在第一个轴上,而openCV使用最后一个轴。 - DerekG
1个回答

4

根据OpenCV文档:

img.shape返回(高度, 宽度, 通道数),其中:

  1. 高度表示图像中像素行数或图像数组中每列的像素数量
  2. 宽度表示图像中像素列数或图像数组中每行的像素数量
  3. 通道数表示用于表示每个像素的组件数。

因此,在 opencv 中调整大小应该这样进行:

import cv2
 
cap = cv2.VideoCapture(0)
_, img = cap.read()
cap.release()
 
print('Original Dimensions : ',img.shape)
 
scale_percent = 60 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
  
# resize image
resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)

根据此链接,当没有给出期望的大小时,fx=2, fy=2按预期工作是因为它计算基于fxfy的新尺寸以计算所需的dsize:

  • FX:水平轴上的比例因子。 当其为0时,它将计算为(double)dsize.width/image.cols
  • FY:垂直轴上的比例因子。 当其为0时,它将计算为(double)dsize.height/image.rows

Desired_size_formula

总之,我想这是因为在OpenCV C++版本中,他们考虑了水平方向上的X(列)和垂直方向上的Y(行),而由于CV2只是对OpenCV-C++的包装,所以在考虑第一维和第二维是什么时,发生了不匹配,就像我们在Numpy数组中一样。

更新 HansHirse评论:

OpenCV是一个专门表示图像的C++库,具有专用的cv::Mat类。例如,对于某些cv::Mat图像,image.size将返回一个cv::Size对象,该对象的宽度和高度按顺序排列,使得几个OpenCV函数中的维度参数(宽度,高度)与其一致。 OpenCV的Python API使用NumPy数组,默认情况下使用行优先顺序,因此对于某些NumPy数组图像,image.shape将按顺序返回高度和宽度。这不是故意设计的选择。


1
dim参数中宽度和高度的顺序与形状不匹配是非常疯狂的。谢谢。 - user48956
@user48956 不是这样的。OpenCV是一个C++库,具有专用的cv::Mat类来表示图像。例如,对于一些cv::Mat imageimage.size返回一个cv::Size对象,其中宽度和高度按顺序排列,使得多个OpenCV函数中的尺寸参数(宽度、高度)保持一致。OpenCV的Python API使用NumPy数组,默认情况下使用行优先顺序,因此对于一些NumPy数组图像,image.shape将按顺序返回高度和宽度。这不是一个故意的设计选择。 - HansHirse
@HansHirse 谢谢分享。我将这个添加到答案中。 - aminrd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接