【问题标题】:Display 2D array from OpenCV in Matplotlib.pyplot.imshow()在 Matplotlib.pyplot.imshow() 中显示来自 OpenCV 的二维数组
【发布时间】:2012-02-17 03:01:29
【问题描述】:

我在 Python 中有一个设置,我使用 OpenCV 库将视频的帧读取为 2D 数组——这些视频是灰度的,所以我使用无符号 8 位整数作为像素值。

在下一步中,我尝试使用 matplotlib 中的 pyplot.imshow() 来显示视频的帧。不幸的是,我得到的东西根本没有任何意义。

这是阅读视频的代码:

import numpy as np
import cv

def read_video(filename):
  video = cv.CaptureFromFile('%s' % filename)
  num_frames = int(cv.GetCaptureProperty(video, cv.CV_CAP_PROP_FRAME_COUNT))

  frames = []
  for i in range(0, num_frames):
    frame = cv.QueryFrame(video)
    if frame is None:
      quit('Failed to extract frame %s of %s!' % (i, num_frames))
    toadd = cv2numpy(frame, 'uint8')
    frames.append(np.array(toadd))
  return np.array(frames)

cv2numpy 是一个实用函数,可将 OpenCV 数组转换为 numpy 数组(只需调用fromstring,然后调用reshape)。这是我用来绘制视频第一帧的代码:

import matplotlib.pyplot as plot
import matplotlib.cm as cm

frames = read_video('video.avi')
plot.imshow(frames[0], cmap = cm.gray)
plot.show()

在其他一些代码中,我在单个帧上使用了 OpenCV SaveImage,以提供我对 imshow 的期望的参考。 Here's the image I get from the formerhere's the image I get from the code above

如您所见,它们截然不同。我唯一能从实际图像中收集到的是条纹:看起来它的尺寸几乎是错误的,宽度上的像素比高度上的像素多(这个图像应该是 128 x 256)。但是我已经尝试在绘制数组之前对其进行转置,根据imshow documentation 更改extentaspectshape 参数,除了一些奇怪的像素拉伸之外,我还没有找到解决方法。

有什么想法吗?

编辑 1: 我认为添加 cv2numpy 代码可能是谨慎的做法,以防重塑以某种方式使事情变得混乱(因为我上面的“真实”图像没有使用该代码,因此cv2numpy 只涉及有问题的管道)。

def cv2numpy(cvarr, the_type):
  a = np.fromstring(
      cvarr.tostring(),
      dtype = the_type,
      count = cvarr.width * cvarr.height)
  a.shape = (cvarr.height, cvarr.width)
  return a

【问题讨论】:

    标签: python opencv matplotlib computer-vision


    【解决方案1】:

    我认为问题出在您的 cv2numpy 函数上。试试这个:

    def cv2numpy(cvarr, the_type):
      a = np.asarray(cv.GetMat(cvarr), dtype=the_type)
      return a
    

    它对我有用。如果您没有使用灰度输入(我知道您说您现在使用的是灰度),那么您需要使用 cv.CreateImage 和 cv.CvtColor 进行转换。

    【讨论】:

    • 这正是问题所在。 OpenCV 仍在以 RGB 格式读取视频,所以我添加了 cv.CreateImagecv.CvtColor,打印出图像,看起来和我期待的完全一样。非常感谢!显然,通过字符串将 OpenCV 数组转换为 numpy 数组是次优的。
    【解决方案2】:

    您使用的是 2.3.1 版吗?使用 cv2 API,我们不再需要实现我们自己版本的 OpenCV/Numpy 转换。例如,下面的代码就可以正常工作:

    >>> import cv2
    >>> from matplotlib import pyplot as plt
    >>> lenna = cv2.imread('lenna.tiff', cv2.CV_LOAD_IMAGE_GRAYSCALE)
    >>> lenna
    array([[162, 162, 162, ..., 170, 155, 128],
           [162, 162, 162, ..., 170, 155, 128],
           [162, 162, 162, ..., 170, 155, 128],
           ..., 
           [ 43,  43,  50, ..., 104, 100,  98],
           [ 44,  44,  55, ..., 104, 105, 108],
           [ 44,  44,  55, ..., 104, 105, 108]], dtype=uint8)
    >>> plt.imshow(lenna, cmap='gray')
    >>> plt.show()
    

    【讨论】:

    • 这可能是一个愚蠢的问题,但我如何确定我正在使用的 OpenCV 版本?我看到的只是一个.__version__ 选项,但它只告诉我修订版本。
    • @Magsol,OpenCV 的最新版本提供了这两个接口。您可以使用“import cv”和“import cv2”。试试“import cv2”,看看你会得到什么。还可以使用您的包管理系统来查找系统中的 OpenCV 版本。或者从源代码编译(参见goo.gl/8ds4i)。
    • OpenCV Sphinx-base 文档显示了这两个接口,但 cv 接口被认为是“旧版”。 opencv.itseez.com
    • 我通过Ubuntu的包管理器安装了python-opencv包;在 ipython 中,它不能识别 import cv2 语句。我尝试重新安装软件包,但它声称我已经安装了最新版本。
    • 在 Ubuntu 11.04 中,二进制包对应于 OpenCV 2.1。这是一个相当旧的版本,考虑到 cv API 现在是遗留的事实。这就是我从源代码编译 OpenCV 的原因。如果您将大量使用 OpenCV + Numpy + Matplotlib,请考虑花一小时或更短的时间编译源代码并使用 cv2 API。生活会更轻松;)
    猜你喜欢
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2016-12-05
    • 1970-01-01
    • 2012-05-09
    相关资源
    最近更新 更多