cvtColor 失败,断言 scn == 3 || scn == 4,但图像确实有 3 个通道且存在
我正在尝试在树莓派上进行人脸检测,所以我想找到最快的方法来完成所有操作。(在700MHz的处理器上,每毫秒都很重要!)
我做了一个快速的速度测试,记录了我需要检查的各种选项的时间,这些选项包括:
- 获取网络摄像头的图片(可以选择pygame.camera或openCV的cv2.VideoCapture)
- 调整图片大小,转换为灰度图,如果需要的话,还要转换为numpy格式并旋转。
听起来有点奇怪,但在树莓派上,使用pygame.camera捕捉图片比使用openCV快大约60毫秒。
假设从pygame表面转换到numpy,再加上90度的旋转,所花的时间少于60毫秒,那么混合使用这两者是值得的。
这里的问题是,我遇到了一个奇怪的cvtColor错误,提示我的numpy ndarray(目前是opencv 2.0的后端)没有3个或4个通道。
这很奇怪,因为在我调用cvtColor之前,我打印了ndarray的形状,它确实有3个通道。我只能假设我漏掉了一些非常明显的东西。
这是简化后的代码。
import pygame
import cv2
import numpy
from pygame import camera
pygame.init()
pygame.camera.init()
#get one shot from pygame camera
cam_list = pygame.camera.list_cameras()
pywebcam = pygame.camera.Camera(cam_list[0],(640,480))
pywebcam.start()
image = pywebcam.get_image()
for z in xrange(50):
image = pywebcam.get_image()
pywebcam.stop()
if image:
#numpy (convert to numpy as fast as possible)
numpy_image=pygame.surfarray.array3d(image)
print(numpy_image.shape)
numpy_image=cv2.cvtColor(numpy_image,cv2.COLOR_BGR2GRAY)
numpy_image = cv2.resize(numpy_image, (0,0), fx=0.25, fy=0.25)
numpy_image = numpy.rot90(numpy_image,3)
编辑:删掉了一堆代码。新代码去掉了所有的性能分析。
我从这个程序得到的输出是:
Average time in range: 58.64 ms.
Pausing to ensure webcam is freed.
Average time in range: 115.56 ms.
(480, 640, 3)
Pure NumPy
0 ms to printing shape.
39 ms to convert to grayscale.
16 ms to resize.
0 ms to rotate.
58 total ms.
(640, 480, 3)
OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cvtColor, file /build/opencv-XZa2gn/opencv-2.3.1/modules/imgproc/src/color.cpp, line 2834
Traceback (most recent call last):
File "profile.py", line 72, in <module>
numpy_image=cv2.cvtColor(numpy_image,cv2.COLOR_BGR2GRAY)
cv2.error: /build/opencv-XZa2gn/opencv-2.3.1/modules/imgproc/src/color.cpp:2834: error: (-215) scn == 3 || scn == 4 in function cvtColor
这到底是怎么回事?
1 个回答
1
找到了答案。其实,numpy在处理ndarray的时候并不会直接更新它,而是把临时的变化记在心里。这样做速度很快。
虽然C++版本的opencv 2.0可以处理这个问题,但Python的绑定却不行。而且因为pygame的surfarray代码是基于numpy的,所以任何从pygame到opencv的操作都会遇到这个问题。
所以,你只需要在调用pygame.surfarray.array3d()之后,调用numpy.copy()就可以了。
这样新复制的内容就不会有这些临时的变化。因此,不用纠结于array3d(),直接用pixels3d()就行了——反正你都得做一个复制,那就别做两个了。
关于更多信息,我记得这些临时变化被称为“strides”之类的东西。