IntroductionUsing OpenCV in Python is a very good solution to prototype vision applications, it allows you to quickly draft and test algorithms. It’s very easy to process images read from files, not so easy if you want to process images captured from a camera. OpenCV provides some basic methods to access the camera linked to the PC (through the object In Windows to interact with the cameras, DirectShow is often used. Its main strengths are:
Conversely, it’s quite an old technology that is being replaced by the Windows Media Foundation and Microsoft is not developing it anymore. But it’s not a big deal because it has all the features needed and it’s used in so many applications that (in my opinion), Microsoft will keep it available for a long time. Here, I want to propose a simple application written entirely in Python that allows you to capture images from a camera using You can find the code of the application also on https://github.com/andreaschiavinato/python_grabber. BackgroundTo understand this article, you need basic knowledge of Python and of the Windows application development. Using the Application
On Windows 10, if the size of text has been set to a value different from 100% (on the Display settings screen of Windows), the live image of the camera may show not well aligned on the containing frame. This seems an issue of DirectShow, since I have the same behaviour on other applications. DirectShow in Short Words
The filters can have input and output pins, and they can be connected together in order to perform the required job
For our application, we need the following filters:
Depending on the camera, we may need additional filters to convert the images provided by the camera in images that can be used by the If you want to learn more about Using the Class FilterGraphYou can use the class Example 1This code lists the cameras connected to your PC: from pygrabber.dshow_graph import FilterGraph
graph = FilterGraph()
print(graph.get_input_devices())
Example 2This code shows a screen with the live image from the first camera in your PC. We add to the graph two filters: one is a source filter corresponding to the first camera connected to your PC, the second is the default render, that shows the images from the camera in a window on the screen. Then we call Finally, we need a method to pause the program while watching the camera video. I use the Tkinter from pygrabber.dshow_graph import FilterGraph
from tkinter import Tk
graph = FilterGraph()
graph.add_input_device(0)
graph.add_default_render()
graph.prepare()
graph.run()
root = Tk()
root.withdraw() # hide Tkinter main window
root.mainloop()
Example 3The following code uses the sample grabber filter to capture single images from the camera. To capture an image, the method from pygrabber.dshow_graph import FilterGraph
import cv2
graph = FilterGraph()
cv2.namedWindow('Image', cv2.WINDOW_NORMAL)
graph.add_input_device(0)
graph.add_sample_grabber(lambda image: cv2.imshow("Image", image))
graph.add_null_render()
graph.prepare()
graph.run()
print("Press 'C' or 'c' to grab photo, another key to exit")
while cv2.waitKey(0) in [ord('c'), ord('C')]:
graph.grab_frame()
graph.stop()
cv2.destroyAllWindows()
print("Done")
Example 4The following code captures an image from a camera in a synchronous way. An The image is shown using import threading
import matplotlib.pyplot as plt
import numpy as np
from pygrabber.dshow_graph import FilterGraph
image_done = threading.Event()
image_grabbed = None
def img_cb(image):
global image_done
global image_grabbed
image_grabbed = np.flip(image, 2)
image_done.set()
graph = FilterGraph()
graph.add_input_device(0)
graph.add_sample_grabber(img_cb)
graph.add_null_render()
graph.prepare()
graph.run()
input("Press ENTER to grab photo")
graph.grab_frame()
image_done.wait(1000)
graph.stop()
plt.imshow(image_grabbed)
plt.show()
Example 5The following code is an improvement of Example 4 that allows you to capture images from two camera at the same time. import threading
import matplotlib.pyplot as plt
import numpy as np
from pygrabber.dshow_graph import FilterGraph
class Camera:
def __init__(self, device_id):
self.graph = FilterGraph()
self.graph.add_input_device(device_id)
self.graph.add_sample_grabber(self.img_cb)
self.graph.add_null_render()
self.graph.display_format_dialog()
self.graph.prepare()
self.graph.run()
self.image_grabbed = None
self.image_done = threading.Event()
def img_cb(self, image):
self.image_grabbed = np.flip(image, 2)
self.image_done.set()
def capture(self):
self.graph.grab_frame()
def wait_image(self):
self.image_done.wait(1000)
return self.image_grabbed
print("Opening first camera")
camera1 = Camera(0)
print("Opening second camera")
camera2 = Camera(1)
input("Press ENTER to grab photos")
camera1.capture()
camera2.capture()
print("Waiting images")
image1 = camera1.wait_image()
image2 = camera2.wait_image()
print("Done")
ax1 = plt.subplot(2, 1, 1)
ax1.imshow(image1)
ax2 = plt.subplot(2, 1, 2)
ax2.imshow(image2)
plt.show()
Example 6
You can install Regsvr32 C:\Program Files (x86)\Screen Capturer Recorder\screen-capture-recorder.dll
Regsvr32 C:\Program Files (x86)\Screen Capturer Recorder\screen-capture-recorder-x64.dll
Below is a variation of Example 4 that makes sure the import threading
import matplotlib.pyplot as plt
import numpy as np
from pygrabber.dshow_graph import FilterGraph
image_done = threading.Event()
image_grabbed = None
def img_cb(image):
global image_done
global image_grabbed
image_grabbed = np.flip(image, 2)
image_done.set()
graph = FilterGraph()
screen_recorder_id = next(device[0] for device in enumerate(graph.get_input_devices())
if device[1] == "screen-capture-recorder")
graph.add_input_device(screen_recorder_id)
graph.add_sample_grabber(img_cb)
graph.add_null_render()
graph.prepare()
graph.run()
input("Press ENTER to capture a screenshot")
graph.grab_frame()
image_done.wait(1000)
graph.stop()
plt.imshow(image_grabbed)
plt.show()
History
|
|