OpenCV 在 Google Colaboratory 中不工作
OpenCV not working in Google Colaboratory
我在 google colaboratory 上练习 OpenCV 因为我不知道如何在 GPU 上使用 OpenCV,当我 运行 在我的硬件上使用 OpenCV 时,需要很多 CPU,所以我去了 Google colaboratory。
我笔记本的 link 是 here.
如果你不想看,那么这里是代码:
import cv2
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
while True:
_, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('img', img)
k = cv2.waitKey(30) & 0xff
if k==27:
break
cap.release()
相同的代码在我的 PC 上运行良好,但在 Google Colaboratory 上运行不正常。错误是:
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-5-0d9472926d8c> in <module>()
6 while True:
7 _, img = cap.read()
----> 8 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
9 faces = face_cascade.detectMultiScale(gray, 1.1, 4)
10 for (x, y, w, h) in faces:
error: OpenCV(4.1.2) /io/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
PS~我在 Google Colaboratory
笔记本的同一目录中有 haarcascade 文件
如何处理?如果没有,那么在我启用 CUDA 的 GPU 而不是 CPU 上是否有针对 运行 OpenCV 的任何“concrete”解决方案?提前致谢!
_src.empty()
表示从相机获取帧有问题,img
是 None
,当它尝试 cvtColor(None, ...)
时,它给出 _src.empty()
。
您应该检查 if img is not None:
,因为 cv2
在无法从相机获取帧或无法从文件读取图像时不会引发错误。有时相机需要时间“预热”,它可以提供很少的空帧 (None
)。
VideoCapture(0)
从直接连接到计算机的相机读取帧,其中 运行 是此代码 - 当您在服务器 Google Colaboratory
上 运行 代码时,这意味着相机直接连接到服务器 Google Colaboratory
(不是你的本地摄像头)但是这个服务器没有摄像头所以 VideoCapture(0)
不能在 Google Colaboratory
.
上工作
cv2
当 运行 在服务器上时,无法从您的本地相机获取图像。您的网络浏览器可能可以访问您的相机,但它需要 JavaScript 来获取帧并发送到服务器 - 但服务器需要代码来获取此帧
我检查了 Google 如果 Google Colaboratory
可以访问本地网络摄像头,他们似乎为此创建了脚本 - Camera Capture - 第一个单元格中的函数 take_photo()
使用JavaScript
访问您的摄像头并在浏览器中显示,在第二个单元格中此功能用于显示本地摄像头的图像并截取屏幕截图。
您应该使用此功能而不是 VideoCapture(0)
来使用本地摄像头在服务器上工作。
顺便说一句: 亲爱的 take_photo()
还有关于 cv2.im_show()
的信息,因为它也只适用于直接连接到 运行 计算机的显示器s 这段代码(并且这台计算机必须 运行 GUI,如 Windows 上的 Windows
,Linux 上的 X11
) - 当你 运行 它在服务器上然后它想显示在直接连接到服务器的显示器上 - 但服务器通常在没有显示器(并且没有 GUI)的情况下工作
Google Colaboratory
有特殊替换显示在网络浏览器中
from google.colab.patches import cv2_imshow
顺便说一句: 如果您在加载 haarcascades 时遇到问题 .xml
那么您可能需要文件夹到文件名。 cv2
有这个 cv2.data.haarcascades
的特殊变量
path = os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml')
cv2.CascadeClassifier( path )
您还可以查看此文件夹中的内容
import os
filenames = os.listdir(cv2.data.haarcascades)
filenames = sorted(filenames)
print('\n'.join(filenames))
编辑:
我创建的代码可以在不使用 button
且不保存在文件中的情况下逐帧从本地网络摄像头获取。问题是它很慢 - 因为它仍然需要将帧从本地网络浏览器发送到 google colab 服务器,然后再返回到本地网络浏览器
Python 具有 JavaScript 功能的代码
#
# based on: https://colab.research.google.com/notebooks/snippets/advanced_outputs.ipynb#scrollTo=2viqYx97hPMi
#
from IPython.display import display, Javascript
from google.colab.output import eval_js
from base64 import b64decode, b64encode
import numpy as np
def init_camera():
"""Create objects and functions in HTML/JavaScript to access local web camera"""
js = Javascript('''
// global variables to use in both functions
var div = null;
var video = null; // <video> to display stream from local webcam
var stream = null; // stream from local webcam
var canvas = null; // <canvas> for single frame from <video> and convert frame to JPG
var img = null; // <img> to display JPG after processing with `cv2`
async function initCamera() {
// place for video (and eventually buttons)
div = document.createElement('div');
document.body.appendChild(div);
// <video> to display video
video = document.createElement('video');
video.style.display = 'block';
div.appendChild(video);
// get webcam stream and assing to <video>
stream = await navigator.mediaDevices.getUserMedia({video: true});
video.srcObject = stream;
// start playing stream from webcam in <video>
await video.play();
// Resize the output to fit the video element.
google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);
// <canvas> for frame from <video>
canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
//div.appendChild(input_canvas); // there is no need to display to get image (but you can display it for test)
// <img> for image after processing with `cv2`
img = document.createElement('img');
img.width = video.videoWidth;
img.height = video.videoHeight;
div.appendChild(img);
}
async function takeImage(quality) {
// draw frame from <video> on <canvas>
canvas.getContext('2d').drawImage(video, 0, 0);
// stop webcam stream
//stream.getVideoTracks()[0].stop();
// get data from <canvas> as JPG image decoded base64 and with header "data:image/jpg;base64,"
return canvas.toDataURL('image/jpeg', quality);
//return canvas.toDataURL('image/png', quality);
}
async function showImage(image) {
// it needs string "data:image/jpg;base64,JPG-DATA-ENCODED-BASE64"
// it will replace previous image in `<img src="">`
img.src = image;
// TODO: create <img> if doesn't exists,
// TODO: use `id` to use different `<img>` for different image - like `name` in `cv2.imshow(name, image)`
}
''')
display(js)
eval_js('initCamera()')
def take_frame(quality=0.8):
"""Get frame from web camera"""
data = eval_js('takeImage({})'.format(quality)) # run JavaScript code to get image (JPG as string base64) from <canvas>
header, data = data.split(',') # split header ("data:image/jpg;base64,") and base64 data (JPG)
data = b64decode(data) # decode base64
data = np.frombuffer(data, dtype=np.uint8) # create numpy array with JPG data
img = cv2.imdecode(data, cv2.IMREAD_UNCHANGED) # uncompress JPG data to array of pixels
return img
def show_frame(img, quality=0.8):
"""Put frame as <img src="data:image/jpg;base64,...."> """
ret, data = cv2.imencode('.jpg', img) # compress array of pixels to JPG data
data = b64encode(data) # encode base64
data = data.decode() # convert bytes to string
data = 'data:image/jpg;base64,' + data # join header ("data:image/jpg;base64,") and base64 data (JPG)
eval_js('showImage("{}")'.format(data)) # run JavaScript code to put image (JPG as string base64) in <img>
# argument in `showImage` needs `" "`
以及在循环中使用它的代码
#
# based on: https://colab.research.google.com/notebooks/snippets/advanced_outputs.ipynb#scrollTo=zo9YYDL4SYZr
#
#from google.colab.patches import cv2_imshow # I don't use it but own function `show_frame()`
import cv2
import os
face_cascade = cv2.CascadeClassifier(os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml'))
# init JavaScript code
init_camera()
while True:
try:
img = take_frame()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#cv2_imshow(gray) # it creates new image for every frame (it doesn't replace previous image) so it is useless
#show_frame(gray) # it replace previous image
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
#cv2_imshow(img) # it creates new image for every frame (it doesn't replace previous image) so it is useless
show_frame(img) # it replace previous image
except Exception as err:
print('Exception:', err)
我不使用 from google.colab.patches import cv2_imshow
因为它总是在页面上添加新图像而不是替换现有图像。
与 Google Colab 上的笔记本相同的代码:
https://colab.research.google.com/drive/1j7HTapCLx7BQUBp3USiQPZkA0zBKgLM0?usp=sharing
代码中可能存在的问题是,在使用Haar-like功能时需要将full-path作为目录。
face_cascade = cv2.CascadeClassifier('/User/path/to/opencv/data/haarcascades/haarcascade_frontalface_default.xml')
opencv
的 colab
问题已经知道很长一段时间了,同样的问题也被问到 here
如here所述,您可以使用cv2_imshow
显示图像,但您想要处理相机帧。
from google.colab.patches import cv2_imshow
img = cv2.imread('logo.png', cv2.IMREAD_UNCHANGED)
cv2_imshow(img)
一个可能的答案:
插入相机捕捉片段,方法take_photo
但您需要修改方法。
face_cascade = cv2.CascadeClassifier('/opencv/data/haarcascades/haarcascade_frontalface_default.xml')
try:
filename = take_photo()
img = Image(filename)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2_imshow("img", img)
except Exception as err:
print(str(err))
以上代码需要编辑,因为没有直接使用的方法VideoCapture
你必须修改take_photo
我在 google colaboratory 上练习 OpenCV 因为我不知道如何在 GPU 上使用 OpenCV,当我 运行 在我的硬件上使用 OpenCV 时,需要很多 CPU,所以我去了 Google colaboratory。 我笔记本的 link 是 here.
如果你不想看,那么这里是代码:
import cv2
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
while True:
_, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('img', img)
k = cv2.waitKey(30) & 0xff
if k==27:
break
cap.release()
相同的代码在我的 PC 上运行良好,但在 Google Colaboratory 上运行不正常。错误是:
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-5-0d9472926d8c> in <module>()
6 while True:
7 _, img = cap.read()
----> 8 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
9 faces = face_cascade.detectMultiScale(gray, 1.1, 4)
10 for (x, y, w, h) in faces:
error: OpenCV(4.1.2) /io/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
PS~我在 Google Colaboratory
笔记本的同一目录中有 haarcascade 文件如何处理?如果没有,那么在我启用 CUDA 的 GPU 而不是 CPU 上是否有针对 运行 OpenCV 的任何“concrete”解决方案?提前致谢!
_src.empty()
表示从相机获取帧有问题,img
是 None
,当它尝试 cvtColor(None, ...)
时,它给出 _src.empty()
。
您应该检查 if img is not None:
,因为 cv2
在无法从相机获取帧或无法从文件读取图像时不会引发错误。有时相机需要时间“预热”,它可以提供很少的空帧 (None
)。
VideoCapture(0)
从直接连接到计算机的相机读取帧,其中 运行 是此代码 - 当您在服务器 Google Colaboratory
上 运行 代码时,这意味着相机直接连接到服务器 Google Colaboratory
(不是你的本地摄像头)但是这个服务器没有摄像头所以 VideoCapture(0)
不能在 Google Colaboratory
.
cv2
当 运行 在服务器上时,无法从您的本地相机获取图像。您的网络浏览器可能可以访问您的相机,但它需要 JavaScript 来获取帧并发送到服务器 - 但服务器需要代码来获取此帧
我检查了 Google 如果 Google Colaboratory
可以访问本地网络摄像头,他们似乎为此创建了脚本 - Camera Capture - 第一个单元格中的函数 take_photo()
使用JavaScript
访问您的摄像头并在浏览器中显示,在第二个单元格中此功能用于显示本地摄像头的图像并截取屏幕截图。
您应该使用此功能而不是 VideoCapture(0)
来使用本地摄像头在服务器上工作。
顺便说一句: 亲爱的 take_photo()
还有关于 cv2.im_show()
的信息,因为它也只适用于直接连接到 运行 计算机的显示器s 这段代码(并且这台计算机必须 运行 GUI,如 Windows 上的 Windows
,Linux 上的 X11
) - 当你 运行 它在服务器上然后它想显示在直接连接到服务器的显示器上 - 但服务器通常在没有显示器(并且没有 GUI)的情况下工作
Google Colaboratory
有特殊替换显示在网络浏览器中
from google.colab.patches import cv2_imshow
顺便说一句: 如果您在加载 haarcascades 时遇到问题 .xml
那么您可能需要文件夹到文件名。 cv2
有这个 cv2.data.haarcascades
path = os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml')
cv2.CascadeClassifier( path )
您还可以查看此文件夹中的内容
import os
filenames = os.listdir(cv2.data.haarcascades)
filenames = sorted(filenames)
print('\n'.join(filenames))
编辑:
我创建的代码可以在不使用 button
且不保存在文件中的情况下逐帧从本地网络摄像头获取。问题是它很慢 - 因为它仍然需要将帧从本地网络浏览器发送到 google colab 服务器,然后再返回到本地网络浏览器
Python 具有 JavaScript 功能的代码
#
# based on: https://colab.research.google.com/notebooks/snippets/advanced_outputs.ipynb#scrollTo=2viqYx97hPMi
#
from IPython.display import display, Javascript
from google.colab.output import eval_js
from base64 import b64decode, b64encode
import numpy as np
def init_camera():
"""Create objects and functions in HTML/JavaScript to access local web camera"""
js = Javascript('''
// global variables to use in both functions
var div = null;
var video = null; // <video> to display stream from local webcam
var stream = null; // stream from local webcam
var canvas = null; // <canvas> for single frame from <video> and convert frame to JPG
var img = null; // <img> to display JPG after processing with `cv2`
async function initCamera() {
// place for video (and eventually buttons)
div = document.createElement('div');
document.body.appendChild(div);
// <video> to display video
video = document.createElement('video');
video.style.display = 'block';
div.appendChild(video);
// get webcam stream and assing to <video>
stream = await navigator.mediaDevices.getUserMedia({video: true});
video.srcObject = stream;
// start playing stream from webcam in <video>
await video.play();
// Resize the output to fit the video element.
google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);
// <canvas> for frame from <video>
canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
//div.appendChild(input_canvas); // there is no need to display to get image (but you can display it for test)
// <img> for image after processing with `cv2`
img = document.createElement('img');
img.width = video.videoWidth;
img.height = video.videoHeight;
div.appendChild(img);
}
async function takeImage(quality) {
// draw frame from <video> on <canvas>
canvas.getContext('2d').drawImage(video, 0, 0);
// stop webcam stream
//stream.getVideoTracks()[0].stop();
// get data from <canvas> as JPG image decoded base64 and with header "data:image/jpg;base64,"
return canvas.toDataURL('image/jpeg', quality);
//return canvas.toDataURL('image/png', quality);
}
async function showImage(image) {
// it needs string "data:image/jpg;base64,JPG-DATA-ENCODED-BASE64"
// it will replace previous image in `<img src="">`
img.src = image;
// TODO: create <img> if doesn't exists,
// TODO: use `id` to use different `<img>` for different image - like `name` in `cv2.imshow(name, image)`
}
''')
display(js)
eval_js('initCamera()')
def take_frame(quality=0.8):
"""Get frame from web camera"""
data = eval_js('takeImage({})'.format(quality)) # run JavaScript code to get image (JPG as string base64) from <canvas>
header, data = data.split(',') # split header ("data:image/jpg;base64,") and base64 data (JPG)
data = b64decode(data) # decode base64
data = np.frombuffer(data, dtype=np.uint8) # create numpy array with JPG data
img = cv2.imdecode(data, cv2.IMREAD_UNCHANGED) # uncompress JPG data to array of pixels
return img
def show_frame(img, quality=0.8):
"""Put frame as <img src="data:image/jpg;base64,...."> """
ret, data = cv2.imencode('.jpg', img) # compress array of pixels to JPG data
data = b64encode(data) # encode base64
data = data.decode() # convert bytes to string
data = 'data:image/jpg;base64,' + data # join header ("data:image/jpg;base64,") and base64 data (JPG)
eval_js('showImage("{}")'.format(data)) # run JavaScript code to put image (JPG as string base64) in <img>
# argument in `showImage` needs `" "`
以及在循环中使用它的代码
#
# based on: https://colab.research.google.com/notebooks/snippets/advanced_outputs.ipynb#scrollTo=zo9YYDL4SYZr
#
#from google.colab.patches import cv2_imshow # I don't use it but own function `show_frame()`
import cv2
import os
face_cascade = cv2.CascadeClassifier(os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml'))
# init JavaScript code
init_camera()
while True:
try:
img = take_frame()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#cv2_imshow(gray) # it creates new image for every frame (it doesn't replace previous image) so it is useless
#show_frame(gray) # it replace previous image
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
#cv2_imshow(img) # it creates new image for every frame (it doesn't replace previous image) so it is useless
show_frame(img) # it replace previous image
except Exception as err:
print('Exception:', err)
我不使用 from google.colab.patches import cv2_imshow
因为它总是在页面上添加新图像而不是替换现有图像。
与 Google Colab 上的笔记本相同的代码:
https://colab.research.google.com/drive/1j7HTapCLx7BQUBp3USiQPZkA0zBKgLM0?usp=sharing
代码中可能存在的问题是,在使用Haar-like功能时需要将full-path作为目录。
face_cascade = cv2.CascadeClassifier('/User/path/to/opencv/data/haarcascades/haarcascade_frontalface_default.xml')
opencv
的 colab
问题已经知道很长一段时间了,同样的问题也被问到 here
如here所述,您可以使用cv2_imshow
显示图像,但您想要处理相机帧。
from google.colab.patches import cv2_imshow
img = cv2.imread('logo.png', cv2.IMREAD_UNCHANGED)
cv2_imshow(img)
一个可能的答案:
插入相机捕捉片段,方法take_photo
但您需要修改方法。
face_cascade = cv2.CascadeClassifier('/opencv/data/haarcascades/haarcascade_frontalface_default.xml')
try:
filename = take_photo()
img = Image(filename)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2_imshow("img", img)
except Exception as err:
print(str(err))
以上代码需要编辑,因为没有直接使用的方法VideoCapture
你必须修改take_photo