在Matplotlib.pyplot.imshow()中显示OpenCV的2D数组

8
我可以帮助您进行翻译。这段文字涉及编程相关内容,主要是介绍如何使用Python中的OpenCV库读取视频帧并将其转换为二维数组。这些视频是灰度的,因此像素值使用无符号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中期望得到什么。 这是我从前者得到的图像,而这是我从上述代码中得到的图像

正如您所看到的,它们完全不同。我能从实际图像中获取的唯一信息是条纹:它看起来几乎像是在尺寸上出现了错误,宽度比高度多了更多像素(此图像应为128 x 256)。但是,我已经尝试在绘制之前对数组进行转置,根据imshow文档更改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
2个回答

5
我认为问题出在您的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 数组是次优的。 - Magsol

1
你正在使用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
@Magsol,最近的OpenCV版本提供了两个接口。你可以使用“import cv”和“import cv2”。尝试使用“import cv2”并查看结果。还可以使用软件包管理系统查找您系统中安装的OpenCV版本。或者从源代码编译(请参见http://goo.gl/8ds4i)。 - TH.
OpenCV Sphinx基础文档展示了两个接口,但cv接口被认为是“遗留的”。http://opencv.itseez.com/ - TH.
我通过Ubuntu的软件包管理器安装了python-opencv软件包;在ipython中,它无法识别import cv2语句。我尝试重新安装该软件包,但它声称我已经安装了最新版本。 - Magsol
在Ubuntu 11.04中,二进制软件包对应的是OpenCV 2.1。这是一个相当古老的版本,并且考虑到cv API现在已经过时了。这就是为什么我要从源代码编译OpenCV。如果您将大量使用OpenCV + Numpy + Matplotlib,请考虑花费一小时或更少的时间来编译源代码并使用cv2 API。生活会更轻松;) - TH.
显示剩余2条评论

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