在Matplotlib.pyplot.imshow()中显示OpenCV的二维数组

8 投票
2 回答
10237 浏览
提问于 2025-04-17 10:55

我在用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的尺寸)。我尝试在绘图之前转置数组,改变extentaspectshape参数,参考了imshow的文档,但除了出现一些奇怪的像素拉伸外,我没有找到解决办法。

有什么想法吗?

编辑 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 个回答

1

你是在用2.3.1版本吗?使用cv2这个接口后,我们不需要自己去实现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()
5

我觉得问题出在你的 cv2numpy 函数上。试试这个:

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

这个对我有效。如果你不是用灰度图像作为输入(我知道你说你现在在用灰度图像),那么你需要用 cv.CreateImage 和 cv.CvtColor 来进行转换。

撰写回答