Capturing and recording
This example extends the class defined in Camera streaming example to implement image capturing and video recording.
Before running the example, make sure your scripts are placed in the following directory structure:
examples
├── scripts
│⠀⠀⠀├── camera_capture.py
│⠀⠀⠀├── imagecapture.py
│⠀⠀⠀├── videorecorder.py
│⠀⠀⠀└── camera_stream.py
├──
capture.svg└──
record.svgRunning camera_capture.py opens a camera streaming window where you can capture or record the frames.
imagecapture.py
import imageio
import vimba # type: ignore[import]
from PySide6.QtCore import QObject, Signal, Slot, QMutex
from civiq6 import VimbaCaptureSession
from typing import Optional
VIMBA_LOGGER = vimba.Log.get_instance()
class ImageCapture(QObject):
imageSaved = Signal(int, str)
def __init__(self, parent=None):
super().__init__(parent)
self._captureSession = None
self._id = 0
self._image = None
self._lock = QMutex()
def captureSession(self) -> Optional[VimbaCaptureSession]:
return self._captureSession
def _setCaptureSession(self, captureSession: Optional[VimbaCaptureSession]):
self._captureSession = captureSession
@Slot(str)
def captureToFile(self, path: str = "") -> int:
if self.captureSession() is None or self._image is None:
return -1
self._lock.lock()
try:
imageio.imwrite(path, self._image)
self._image = None
finally:
self._lock.unlock()
ret_id = self._id
self._id += 1
VIMBA_LOGGER.info("Captured %s" % path)
self.imageSaved.emit(ret_id, path)
return ret_id
def _setFrame(self, frame: vimba.Frame):
obtained = self._lock.tryLock()
if obtained:
try:
self._image = frame.as_opencv_image().copy()
finally:
self._lock.unlock()
import imageio
import vimba # type: ignore[import]
from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot, QMutex
from civiq6 import VimbaCaptureSession
from typing import Optional
VIMBA_LOGGER = vimba.Log.get_instance()
class ImageCapture(QObject):
imageSaved = pyqtSignal(int, str)
def __init__(self, parent=None):
super().__init__(parent)
self._captureSession = None
self._id = 0
self._image = None
self._lock = QMutex()
def captureSession(self) -> Optional[VimbaCaptureSession]:
return self._captureSession
def _setCaptureSession(self, captureSession: Optional[VimbaCaptureSession]):
self._captureSession = captureSession
@pyqtSlot(str)
def captureToFile(self, path: str = "") -> int:
if self.captureSession() is None or self._image is None:
return -1
self._lock.lock()
try:
imageio.imwrite(path, self._image)
self._image = None
finally:
self._lock.unlock()
ret_id = self._id
self._id += 1
VIMBA_LOGGER.info("Captured %s" % path)
self.imageSaved.emit(ret_id, path)
return ret_id
def _setFrame(self, frame: vimba.Frame):
obtained = self._lock.tryLock()
if obtained:
try:
self._image = frame.as_opencv_image().copy()
finally:
self._lock.unlock()
videorecorder.py
import enum
import imageio
import vimba # type: ignore[import]
from PySide6.QtCore import QObject, QUrl, Signal, Slot, QMutex
from civiq6 import VimbaCaptureSession
from typing import Optional
VIMBA_LOGGER = vimba.Log.get_instance()
class VideoRecorder(QObject):
class RecorderState(enum.IntEnum):
StoppedState = 1
RecordingState = 2
PausedState = 3
recorderStateChanged = Signal(RecorderState)
def __init__(self, parent=None):
super().__init__(parent)
self._captureSession = None
self._outputLocation = QUrl()
self._recorderState = self.RecorderState.StoppedState
self._writer = None
self._lock = QMutex()
def captureSession(self) -> Optional[VimbaCaptureSession]:
return self._captureSession
def _setCaptureSession(self, captureSession: Optional[VimbaCaptureSession]):
self._captureSession = captureSession
def outputLocation(self) -> QUrl:
return self._outputLocation
@Slot(QUrl)
def setOutputLocation(self, outputLocation: QUrl):
self._outputLocation = outputLocation
def recorderState(self) -> RecorderState:
return self._recorderState
@Slot()
def record(self):
session = self._captureSession
if session is None:
return
camera = session.camera()
if camera is None:
return
if not camera.isAvailable():
return
if self._recorderState == self.RecorderState.StoppedState:
path = self._outputLocation.toLocalFile()
fps = camera.getFeatureByName("AcquisitionFrameRate").get()
self._lock.lock()
try:
self._writer = imageio.get_writer(path, fps=fps)
finally:
self._lock.unlock()
self._recorderState = self.RecorderState.RecordingState
VIMBA_LOGGER.info(f"Started recording {path}")
self.recorderStateChanged.emit(self._recorderState)
elif self._recorderState == self.RecorderState.PausedState:
self._recorderState = self.RecorderState.RecordingState
VIMBA_LOGGER.info(f"Resumed recording {self._outputLocation.toLocalFile()}")
self.recorderStateChanged.emit(self._recorderState)
@Slot()
def pause(self):
if self._recorderState == self.RecorderState.RecordingState:
self._recorderState = self.RecorderState.PausedState
VIMBA_LOGGER.info(f"Paused recording {self._outputLocation.toLocalFile()}")
self.recorderStateChanged.emit(self._recorderState)
@Slot()
def stop(self):
if self._recorderState != self.RecorderState.StoppedState:
self._lock.lock()
try:
self._writer.close()
self._writer = None
finally:
self._lock.unlock()
self._recorderState = self.RecorderState.StoppedState
VIMBA_LOGGER.info(f"Stopped recording {self._outputLocation.toLocalFile()}")
self.recorderStateChanged.emit(self._recorderState)
def _setFrame(self, frame: vimba.Frame):
if self._recorderState == self.RecorderState.RecordingState:
obtained = self._lock.tryLock()
if obtained:
try:
self._writer.append_data(frame.as_opencv_image())
finally:
self._lock.unlock()
import enum
import imageio
import vimba # type: ignore[import]
from PyQt6.QtCore import QObject, QUrl, pyqtSignal, pyqtSlot, QMutex
from civiq6 import VimbaCaptureSession
from typing import Optional
VIMBA_LOGGER = vimba.Log.get_instance()
class VideoRecorder(QObject):
class RecorderState(enum.IntEnum):
StoppedState = 1
RecordingState = 2
PausedState = 3
recorderStateChanged = pyqtSignal(RecorderState)
def __init__(self, parent=None):
super().__init__(parent)
self._captureSession = None
self._outputLocation = QUrl()
self._recorderState = self.RecorderState.StoppedState
self._writer = None
self._lock = QMutex()
def captureSession(self) -> Optional[VimbaCaptureSession]:
return self._captureSession
def _setCaptureSession(self, captureSession: Optional[VimbaCaptureSession]):
self._captureSession = captureSession
def outputLocation(self) -> QUrl:
return self._outputLocation
@pyqtSlot(QUrl)
def setOutputLocation(self, outputLocation: QUrl):
self._outputLocation = outputLocation
def recorderState(self) -> RecorderState:
return self._recorderState
@pyqtSlot()
def record(self):
session = self._captureSession
if session is None:
return
camera = session.camera()
if camera is None:
return
if not camera.isAvailable():
return
if self._recorderState == self.RecorderState.StoppedState:
path = self._outputLocation.toLocalFile()
fps = camera.getFeatureByName("AcquisitionFrameRate").get()
self._lock.lock()
try:
self._writer = imageio.get_writer(path, fps=fps)
finally:
self._lock.unlock()
self._recorderState = self.RecorderState.RecordingState
VIMBA_LOGGER.info(f"Started recording {path}")
self.recorderStateChanged.emit(self._recorderState)
elif self._recorderState == self.RecorderState.PausedState:
self._recorderState = self.RecorderState.RecordingState
VIMBA_LOGGER.info(f"Resumed recording {self._outputLocation.toLocalFile()}")
self.recorderStateChanged.emit(self._recorderState)
@pyqtSlot()
def pause(self):
if self._recorderState == self.RecorderState.RecordingState:
self._recorderState = self.RecorderState.PausedState
VIMBA_LOGGER.info(f"Paused recording {self._outputLocation.toLocalFile()}")
self.recorderStateChanged.emit(self._recorderState)
@pyqtSlot()
def stop(self):
if self._recorderState != self.RecorderState.StoppedState:
self._lock.lock()
try:
self._writer.close()
self._writer = None
finally:
self._lock.unlock()
self._recorderState = self.RecorderState.StoppedState
VIMBA_LOGGER.info(f"Stopped recording {self._outputLocation.toLocalFile()}")
self.recorderStateChanged.emit(self._recorderState)
def _setFrame(self, frame: vimba.Frame):
if self._recorderState == self.RecorderState.RecordingState:
obtained = self._lock.tryLock()
if obtained:
try:
self._writer.append_data(frame.as_opencv_image())
finally:
self._lock.unlock()
camera_capture.py
from PySide6.QtCore import QUrl, Signal, Slot, QSize
from PySide6.QtWidgets import QToolBar, QLineEdit, QToolButton, QStyle
from PySide6.QtGui import QIcon
from imagecapture import ImageCapture
from videorecorder import VideoRecorder
from camera_stream import CameraWindow
class CaptureToolBar(QToolBar):
captureRequested = Signal(str)
recordPathChanged = Signal(QUrl)
recordStartRequested = Signal()
recordStopRequested = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._capturePathLineEdit = QLineEdit()
self._captureButton = QToolButton()
self._recordPathLineEdit = QLineEdit()
self._recordButton = QToolButton()
self._recordState = VideoRecorder.RecorderState.StoppedState
self._capturePathLineEdit.setPlaceholderText("Image capture path")
self._captureButton.setToolTip("Click to capture image")
captureButtonIcon = QIcon()
captureButtonIcon.addFile("../capture.svg", QSize(24, 24))
self._captureButton.setIcon(captureButtonIcon)
self._recordPathLineEdit.setPlaceholderText("Video record path")
self._recordButton.setToolTip("Click to toggle video recording")
recordButtonIcon = QIcon()
recordButtonIcon.addFile("../record.svg", QSize(24, 24))
self._recordButton.setIcon(recordButtonIcon)
self.addWidget(self._capturePathLineEdit)
self.addWidget(self._captureButton)
self.addSeparator()
self.addWidget(self._recordPathLineEdit)
self.addWidget(self._recordButton)
self._captureButton.clicked.connect(self._onCaptureButtonClick)
self._recordPathLineEdit.textChanged.connect(self._onRecordPathEdit)
self._recordButton.clicked.connect(self._onRecordButtonClick)
def _onCaptureButtonClick(self):
path = self._capturePathLineEdit.text()
self.captureRequested.emit(path)
def _onRecordPathEdit(self, path: str):
self.recordPathChanged.emit(QUrl.fromLocalFile(path))
def _onRecordButtonClick(self):
if self._recordState == VideoRecorder.RecorderState.StoppedState:
self.recordStartRequested.emit()
else:
self.recordStopRequested.emit()
@Slot(VideoRecorder.RecorderState)
def setRecorderState(self, state: VideoRecorder.RecorderState):
if state == VideoRecorder.RecorderState.RecordingState:
self._recordButton.setCheckable(True)
self._recordButton.setChecked(True)
self._recordButton.setIcon(
self.style().standardIcon(QStyle.StandardPixmap.SP_MediaStop)
)
elif state == VideoRecorder.RecorderState.StoppedState:
self._recordButton.setChecked(False)
self._recordButton.setCheckable(False)
icon = QIcon()
icon.addFile("../record.svg", QSize(24, 24))
self._recordButton.setIcon(icon)
self._recordState = state
class CameraCaptureWindow(CameraWindow):
def __init__(self, parent=None):
super().__init__(parent)
self._imageCapture = ImageCapture()
self._videoRecorder = VideoRecorder()
self._captureSession.setImageCapture(self._imageCapture)
self._captureSession.setRecorder(self._videoRecorder)
self._toolBar = CaptureToolBar()
self._toolBar.captureRequested.connect(self._imageCapture.captureToFile)
self._toolBar.recordPathChanged.connect(self._videoRecorder.setOutputLocation)
self._toolBar.recordStartRequested.connect(self._videoRecorder.record)
self._toolBar.recordStopRequested.connect(self._videoRecorder.stop)
self._videoRecorder.recorderStateChanged.connect(self._toolBar.setRecorderState)
self.addToolBar(self._toolBar)
if __name__ == "__main__":
import vimba # type: ignore[import]
from PySide6.QtWidgets import QApplication
import sys
VIMBA_INST = vimba.Vimba.get_instance()
VIMBA_INST.enable_log(vimba.LOG_CONFIG_INFO_CONSOLE_ONLY)
app = QApplication(sys.argv)
window = CameraCaptureWindow()
window.camera().start()
window.show()
app.exec()
app.quit()
from PyQt6.QtCore import QUrl, pyqtSignal, pyqtSlot, QSize
from PyQt6.QtWidgets import QToolBar, QLineEdit, QToolButton, QStyle
from PyQt6.QtGui import QIcon
from imagecapture import ImageCapture
from videorecorder import VideoRecorder
from camera_stream import CameraWindow
class CaptureToolBar(QToolBar):
captureRequested = pyqtSignal(str)
recordPathChanged = pyqtSignal(QUrl)
recordStartRequested = pyqtSignal()
recordStopRequested = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self._capturePathLineEdit = QLineEdit()
self._captureButton = QToolButton()
self._recordPathLineEdit = QLineEdit()
self._recordButton = QToolButton()
self._recordState = VideoRecorder.RecorderState.StoppedState
self._capturePathLineEdit.setPlaceholderText("Image capture path")
self._captureButton.setToolTip("Click to capture image")
captureButtonIcon = QIcon()
captureButtonIcon.addFile("../capture.svg", QSize(24, 24))
self._captureButton.setIcon(captureButtonIcon)
self._recordPathLineEdit.setPlaceholderText("Video record path")
self._recordButton.setToolTip("Click to toggle video recording")
recordButtonIcon = QIcon()
recordButtonIcon.addFile("../record.svg", QSize(24, 24))
self._recordButton.setIcon(recordButtonIcon)
self.addWidget(self._capturePathLineEdit)
self.addWidget(self._captureButton)
self.addSeparator()
self.addWidget(self._recordPathLineEdit)
self.addWidget(self._recordButton)
self._captureButton.clicked.connect(self._onCaptureButtonClick)
self._recordPathLineEdit.textChanged.connect(self._onRecordPathEdit)
self._recordButton.clicked.connect(self._onRecordButtonClick)
def _onCaptureButtonClick(self):
path = self._capturePathLineEdit.text()
self.captureRequested.emit(path)
def _onRecordPathEdit(self, path: str):
self.recordPathChanged.emit(QUrl.fromLocalFile(path))
def _onRecordButtonClick(self):
if self._recordState == VideoRecorder.RecorderState.StoppedState:
self.recordStartRequested.emit()
else:
self.recordStopRequested.emit()
@pyqtSlot(VideoRecorder.RecorderState)
def setRecorderState(self, state: VideoRecorder.RecorderState):
if state == VideoRecorder.RecorderState.RecordingState:
self._recordButton.setCheckable(True)
self._recordButton.setChecked(True)
self._recordButton.setIcon(
self.style().standardIcon(QStyle.StandardPixmap.SP_MediaStop)
)
elif state == VideoRecorder.RecorderState.StoppedState:
self._recordButton.setChecked(False)
self._recordButton.setCheckable(False)
icon = QIcon()
icon.addFile("../record.svg", QSize(24, 24))
self._recordButton.setIcon(icon)
self._recordState = state
class CameraCaptureWindow(CameraWindow):
def __init__(self, parent=None):
super().__init__(parent)
self._imageCapture = ImageCapture()
self._videoRecorder = VideoRecorder()
self._captureSession.setImageCapture(self._imageCapture)
self._captureSession.setRecorder(self._videoRecorder)
self._toolBar = CaptureToolBar()
self._toolBar.captureRequested.connect(self._imageCapture.captureToFile)
self._toolBar.recordPathChanged.connect(self._videoRecorder.setOutputLocation)
self._toolBar.recordStartRequested.connect(self._videoRecorder.record)
self._toolBar.recordStopRequested.connect(self._videoRecorder.stop)
self._videoRecorder.recorderStateChanged.connect(self._toolBar.setRecorderState)
self.addToolBar(self._toolBar)
if __name__ == "__main__":
import vimba # type: ignore[import]
from PyQt6.QtWidgets import QApplication
import sys
VIMBA_INST = vimba.Vimba.get_instance()
VIMBA_INST.enable_log(vimba.LOG_CONFIG_INFO_CONSOLE_ONLY)
app = QApplication(sys.argv)
window = CameraCaptureWindow()
window.camera().start()
window.show()
app.exec()
app.quit()