Source code for pynta.view.GUI.camera_viewer_widget
import pyqtgraph as pg
import numpy as np
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QAction
from pyqtgraph import GraphicsLayoutWidget
[docs]class CameraViewerWidget(QWidget):
"""Widget for holding the images generated by the camera.
"""
specialTask = pyqtSignal()
stopSpecialTask = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent=parent)
# General layout of the widget to hold an image and a histogram
self.layout = QHBoxLayout(self)
# Settings for the image
self.viewport = GraphicsLayoutWidget()
self.view = self.viewport.addViewBox(lockAspect=False, enableMenu=True)
self.autoScale = QAction("Auto Range", self.view.menu)
self.autoScale.triggered.connect(self.do_auto_scale)
self.view.menu.addAction(self.autoScale)
self.img = pg.ImageItem()
self.marker = pg.PlotDataItem(pen=None)
self.marker.setBrush(255, 0, 0, 255)
self.view.addItem(self.img)
self.view.addItem(self.marker)
self.imv = pg.ImageView(view=self.view, imageItem=self.img)
# Add everything to the widget
self.layout.addWidget(self.imv)
self.setLayout(self.layout)
self.showCrosshair = False
self.showCrossCut = False
self.rois = []
self.radius_circle = 10 # The radius to draw around particles
self.corner_roi = [0, 0] # Initial ROI corner for the camera
self.first_image = True
[docs] def setup_roi_lines(self, max_size):
"""Sets up the ROI lines surrounding the image.
:param list max_size: List containing the maximum size of the image to avoid ROIs bigger than the CCD."""
self.hline1 = pg.InfiniteLine(angle=0, movable=True, hoverPen={'color': "FF0", 'width': 4})
self.hline2 = pg.InfiniteLine(angle=0, movable=True, hoverPen={'color': "FF0", 'width': 4})
self.vline1 = pg.InfiniteLine(angle=90, movable=True, hoverPen={'color': "FF0", 'width': 4})
self.vline2 = pg.InfiniteLine(angle=90, movable=True, hoverPen={'color': "FF0", 'width': 4})
self.hline1.setValue(0)
self.vline1.setValue(0)
self.vline2.setValue(max_size[0])
self.hline2.setValue(max_size[1])
self.hline1.setBounds((0, max_size[1]))
self.hline2.setBounds((0, max_size[1]))
self.vline1.setBounds((0, max_size[0]))
self.vline2.setBounds((0, max_size[0]))
self.view.addItem(self.hline1)
self.view.addItem(self.hline2)
self.view.addItem(self.vline1)
self.view.addItem(self.vline2)
self.corner_roi[0] = 0
self.corner_roi[1] = 0
[docs] def get_roi_values(self):
""" Get's the ROI values in camera-space. It keeps track of the top left corner in order
to update the values before returning.
:return: Position of the corners of the ROI region assuming 0-indexed cameras.
"""
y1 = round(self.hline1.value())
y2 = round(self.hline2.value())
x1 = round(self.vline1.value())
x2 = round(self.vline2.value())
X = np.sort((x1, x2))
Y = np.sort((y1, y2))
# Updates to the real values in camera space
X += self.corner_roi[0]
Y += self.corner_roi[1]
X[1] -= 1
Y[1] -= 1
return X, Y
[docs] def set_roi_lines(self, X, Y):
self.corner_roi = [X[0], Y[0]]
self.hline1.setValue(0)
self.vline1.setValue(0)
x2 = X[1]-X[0]+1
y2 = Y[1]-Y[0]+1
self.hline2.setValue(y2) # To the last pixel
self.vline2.setValue(x2) # To the last pixel
[docs] def setup_mouse_tracking(self):
self.imv.setMouseTracking(True)
self.imv.getImageItem().scene().sigMouseMoved.connect(self.mouseMoved)
self.imv.getImageItem().scene().contextMenu = None
[docs] def keyPressEvent(self,key):
"""Triggered when there is a key press with some modifier.
Shift+C: Removes the cross hair from the screen
Ctrl+C: Emits a specialTask signal
Ctrl+V: Emits a stopSpecialTask signal
These last two events have to be handeled in the mainWindow that implemented this widget."""
modifiers = QApplication.keyboardModifiers()
if modifiers == Qt.ShiftModifier:
if key.key() == 67: # For letter C of 'Clear
if self.showCrosshair:
for c in self.crosshair:
self.view.removeItem(c)
self.showCrosshair = False
if self.showCrossCut:
self.view.removeItem(self.crossCut)
self.showCrossCut = False
elif modifiers == Qt.ControlModifier:
if key.key() == 67: # For letter C of 'Clear
self.specialTask.emit()
if key.key() == 86: # For letter V
self.stopSpecialTask.emit()
[docs] def mouseMoved(self, arg):
"""Updates the position of the cross hair. The mouse has to be moved while pressing down the Ctrl button."""
# arg = evt.pos()
modifiers = QApplication.keyboardModifiers()
if modifiers == Qt.ControlModifier:
if not self.showCrosshair:
for c in self.crosshair:
self.view.addItem(c)
self.showCrosshair = True
self.crosshair[1].setValue(int(self.img.mapFromScene(arg).x()))
self.crosshair[0].setValue(int(self.img.mapFromScene(arg).y()))
elif modifiers == Qt.AltModifier:
if not self.showCrossCut:
self.view.addItem(self.crossCut)
self.showCrossCut = True
self.crossCut.setValue(int(self.img.mapFromScene(arg).y()))
[docs] def draw_target_pointer(self, locations):
"""gets an image and draws a circle around the target locations.
:param DataFrame locations: DataFrame generated by trackpy's locate method. It only requires columns `x` and `y` with coordinates.
"""
if locations is None:
return
locations = locations[['y', 'x']].values
brush = pg.mkBrush(color=(255, 0, 0))
self.marker.setData(locations[:, 0], locations[:, 1], symbol='x', symbolBrush=brush)
[docs] def update_image(self, image):
self.img.setImage(image.astype(int), autoLevels=False, autoRange=False, autoHistogramRange=False)
if self.first_image:
self.do_auto_scale()
self.first_image = False
[docs] def setup_cross_hair(self, max_size):
"""Sets up a cross hair."""
self.crosshair = []
self.crosshair.append(pg.InfiniteLine(angle=0, movable=False, pen={'color': 124, 'width': 4}))
self.crosshair.append(pg.InfiniteLine(angle=90, movable=False, pen={'color': 124, 'width': 4}))
self.crosshair[0].setBounds((1, max_size[1] - 1))
self.crosshair[1].setBounds((1, max_size[0] - 1))
[docs] def setup_cross_cut(self, max_size):
"""Set ups the horizontal line for the cross cut."""
self.crossCut = pg.InfiniteLine(angle=0, movable=False, pen={'color': 'g', 'width': 2})
self.crossCut.setBounds((1, max_size))
if __name__ == "__main__":
from pandas import DataFrame
app = QApplication([])
win = CameraViewerWidget()
data = np.random.randint(0, 125, (40, 100))
win.update_image(data)
win.show()
location = DataFrame([[20, 50], [30, 60]], columns=['x', 'y'])
win.draw_target_pointer(location)
app.exec()