class CroppableCameraView(QGraphicsView): rectChanged = Signal(QRect) imageDisplayed = Signal(np.ndarray) videoStarted = Signal() mouseMoved = Signal(QMouseEvent) mousePressed = Signal(QMouseEvent) mouseReleased = Signal(QMouseEvent) def __init__(self, camera, **settings): super(CroppableCameraView, self).__init__() self.setRenderHint(QPainter.Antialiasing) self.cam = camera self.is_live = False self._cmin = 0 self._cmax = None self.settings = settings self._selecting = False self.needs_resize = False self.latest_array = None self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene() #self.setFrameStyle(QFrame.NoFrame) self.setScene(self.scene) self.pixmapitem = self.scene.addPixmap(QPixmap()) self._uncropped_pixmap = None self.setMouseTracking(True) self.start = None c1 = QColor(0, 100, 220, 150) self.c2 = QColor(0, 100, 220, 50) self.c3 = QColor(0, 100, 220, 0) pen = QPen(c1, 2) self.selrect = self.scene.addRect(1, 1, 1, 1, pen, self.c3) self.selrect.setZValue(100) self.selrect.hide() def enable_selecting(self): print("Selection enabled") self._selecting = True def disable_selecting(self): self._selecting = False def mousePressEvent(self, event): if self._selecting: print("Mouse pressed") if not self.selrect.isVisible(): self.selrect.show() if event.button() == Qt.LeftButton: sp = self.mapToScene(event.pos()) self.start = (sp.x(), sp.y()) self.selrect.setRect(sp.x(), sp.y(), 0, 0) self.selrect.setBrush(self.c2) self.mousePressed.emit(event) def mouseMoveEvent(self, event): if self.start: x1, y1 = self.start sp = self.mapToScene(event.pos()) # Image width, height in scene coords ir = self.pixmapitem.boundingRect() sr = self.pixmapitem.sceneTransform().mapRect(ir) size = self.pixmapitem.pixmap().size() x2 = max(sr.left(), min(sr.right()-1, sp.x())) y2 = max(sr.top(), min(sr.bottom()-1, sp.y())) x1, x2 = sorted((x1, x2)) y1, y2 = sorted((y1, y2)) self.selrect.setRect(x1, y1, x2-x1, y2-y1) self.mouseMoved.emit(event) def mouseReleaseEvent(self, event): if self.start and event.button() == Qt.LeftButton: self.start = None self.selrect.setBrush(self.c3) self.rectChanged.emit(self.selrect.rect().toRect()) self.mouseReleased.emit(event) def update_rect(self, x, y, w, h): self.selrect.setRect(x, y, w, h) self.rectChanged.emit(self.selrect.rect().toRect()) def hideRect(self): self.selrect.hide() def showRect(self): self.selrect.show() def setRectVisible(self, visible): self.selrect.setVisible(visible) def isRectVisible(self): return self.selrect.isVisible() def rect(self): """QRect of the selection in camera coordinates""" # selrect in _image_ (pixmap) coordinates i_selrect = self.pixmapitem.sceneTransform().inverted()[0].mapRect(self.selrect.rect()) current_left = self.settings.get('left', 0) current_top = self.settings.get('top', 0) return i_selrect.toRect().translated(current_left, current_top) def crop_to_rect(self): was_live = self.is_live if was_live: self.stop_video() self.hideRect() rect = self.rect() self.settings['left'] = rect.left() self.settings['right'] = rect.right() self.settings['top'] = rect.top() self.settings['bot'] = rect.bottom() if was_live: self.start_video() else: if not self._uncropped_pixmap: self._uncropped_pixmap = self.pixmapitem.pixmap() self.pixmapitem.setPixmap(self._uncropped_pixmap.copy(rect)) self.setFixedSize(rect.width(), rect.height()) def uncrop(self): was_live = self.is_live if was_live: self.stop_video() for key in ['left', 'right', 'top', 'bot']: if key in self.settings: del self.settings[key] if was_live: self.start_video() else: pixmap = self._uncropped_pixmap self.pixmapitem.setPixmap(pixmap) ir = self.pixmapitem.boundingRect() sr = self.pixmapitem.sceneTransform().mapRect(ir) self.scene.setSceneRect(sr) self.setFixedSize(sr.width(), sr.height()) def mapSceneToPixmap(self, pt): transform = self.pixmapitem.sceneTransform().inverted()[0] return transform.mapRect(pt) if isinstance(pt, (QRect, QRectF)) else transform.map(pt) def mapViewToPixmap(self, view_pt): scene_pt = self.mapToScene(view_pt) return self.mapSceneToPixmap(scene_pt) def mapPixmapToScene(self, pixmap_pt): transform = self.pixmapitem.sceneTransform() map_func = transform.mapRect if isinstance(pixmap_pt, (QRect, QRectF)) else transform.map return map_func(pixmap_pt) def mapSceneToCamera(self, sc_pt): px_pt = self.mapSceneToPixmap(sc_pt) return QPoint(px_pt.x() + self.settings.get('left', 0), px_pt.y() + self.settings.get('top', 0)) def set_image(self, image_arr): pixmap = QPixmap(self._array_to_qimage(image_arr)) if not self.pixmapitem: self.pixmapitem = self.scene.addPixmap(pixmap) else: self.pixmapitem.setPixmap(pixmap) if self.needs_resize: self._autoresize_viewport() self.needs_resize = False def _autoresize_viewport(self): ir = self.pixmapitem.boundingRect() sr = self.pixmapitem.sceneTransform().mapRect(ir) self.scene.setSceneRect(sr) #self.setFixedSize(sr.width(), sr.height()) self.resize(sr.width(), sr.height()) #self.viewport().setMaximumSize(sr.width(), sr.height()) d = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setMaximumSize(sr.width() + 2*d, sr.height() + 2*d) def grab_image(self): arr = self.cam.grab_image(**self.settings) self.set_image(arr) self.latest_array = arr self.imageDisplayed.emit(arr) def start_video(self): timer = QTimer() self.timer = timer timer.timeout.connect(self._wait_for_frame) self.cam.start_live_video(**self.settings) timer.start(0) # Run full throttle self.is_live = True self.needs_resize = True self.videoStarted.emit() def stop_video(self): self.timer.stop() self.cam.stop_live_video() self.is_live = False def _wait_for_frame(self): frame_ready = self.cam.wait_for_frame(timeout='0 ms') if frame_ready: arr = self.cam.latest_frame(copy=True) self.set_image(arr) self.latest_array = arr self.imageDisplayed.emit(arr) def _scale_image(self, arr): """Return a bytescaled copy of the image array""" if not self._cmax: self._cmax = arr.max() # Set cmax once from first image return scipy.misc.bytescale(arr, self._cmin, self._cmax) def _lut_scale_image(self, arr): if not self._cmax: self._cmax = arr.max() lut = scipy.misc.bytescale(np.arange(2**16), self._cmin, self._cmax) return lut[arr] def _create_lut(self, k): A = 2**15 B = 100 # k's scaling factor g = lambda i, k: A*((k-B)*i) / ((2*k)*x - (k+B)*A) def _array_to_qimage(self, arr): bpl = arr.strides[0] is_rgb = len(arr.shape) == 3 if is_rgb and arr.dtype == np.uint8: format = QImage.Format_RGB32 image = QImage(arr.data, self.cam.width, self.cam.height, bpl, format) elif not is_rgb and arr.dtype == np.uint8: # TODO: Somehow need to make sure data is ordered as I'm assuming format = QImage.Format_Indexed8 image = QImage(arr.data, self.cam.width, self.cam.height, bpl, format) self._saved_img = arr elif not is_rgb and arr.dtype == np.uint16: arr = self._scale_image(arr) format = QImage.Format_Indexed8 w, h = self.cam.width, self.cam.height image = QImage(arr.data, w, h, w, format) self._saved_img = arr # Save a reference to keep Qt from crashing else: raise Exception("Unsupported color mode") return image
class CroppableCameraView(QGraphicsView): rectChanged = Signal(QRect) imageDisplayed = Signal(np.ndarray) videoStarted = Signal() mouseMoved = Signal(QMouseEvent) mousePressed = Signal(QMouseEvent) mouseReleased = Signal(QMouseEvent) def __init__(self, camera, **settings): super(CroppableCameraView, self).__init__() self.setRenderHint(QPainter.Antialiasing) self.cam = camera self.is_live = False self._cmin = 0 self._cmax = None self.settings = settings self._selecting = False self.needs_resize = False self.latest_array = None self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene() #self.setFrameStyle(QFrame.NoFrame) self.setScene(self.scene) self.pixmapitem = self.scene.addPixmap(QPixmap()) self._uncropped_pixmap = None self.setMouseTracking(True) self.start = None c1 = QColor(0, 100, 220, 150) self.c2 = QColor(0, 100, 220, 50) self.c3 = QColor(0, 100, 220, 0) pen = QPen(c1, 2) self.selrect = self.scene.addRect(1, 1, 1, 1, pen, self.c3) self.selrect.setZValue(100) self.selrect.hide() def enable_selecting(self): print("Selection enabled") self._selecting = True def disable_selecting(self): self._selecting = False def mousePressEvent(self, event): if self._selecting: print("Mouse pressed") if not self.selrect.isVisible(): self.selrect.show() if event.button() == Qt.LeftButton: sp = self.mapToScene(event.pos()) self.start = (sp.x(), sp.y()) self.selrect.setRect(sp.x(), sp.y(), 0, 0) self.selrect.setBrush(self.c2) self.mousePressed.emit(event) def mouseMoveEvent(self, event): if self.start: x1, y1 = self.start sp = self.mapToScene(event.pos()) # Image width, height in scene coords ir = self.pixmapitem.boundingRect() sr = self.pixmapitem.sceneTransform().mapRect(ir) size = self.pixmapitem.pixmap().size() x2 = max(sr.left(), min(sr.right() - 1, sp.x())) y2 = max(sr.top(), min(sr.bottom() - 1, sp.y())) x1, x2 = sorted((x1, x2)) y1, y2 = sorted((y1, y2)) self.selrect.setRect(x1, y1, x2 - x1, y2 - y1) self.mouseMoved.emit(event) def mouseReleaseEvent(self, event): if self.start and event.button() == Qt.LeftButton: self.start = None self.selrect.setBrush(self.c3) self.rectChanged.emit(self.selrect.rect().toRect()) self.mouseReleased.emit(event) def update_rect(self, x, y, w, h): self.selrect.setRect(x, y, w, h) self.rectChanged.emit(self.selrect.rect().toRect()) def hideRect(self): self.selrect.hide() def showRect(self): self.selrect.show() def setRectVisible(self, visible): self.selrect.setVisible(visible) def isRectVisible(self): return self.selrect.isVisible() def rect(self): """QRect of the selection in camera coordinates""" # selrect in _image_ (pixmap) coordinates i_selrect = self.pixmapitem.sceneTransform().inverted()[0].mapRect( self.selrect.rect()) current_left = self.settings.get('left', 0) current_top = self.settings.get('top', 0) return i_selrect.toRect().translated(current_left, current_top) def crop_to_rect(self): was_live = self.is_live if was_live: self.stop_video() self.hideRect() rect = self.rect() self.settings['left'] = rect.left() self.settings['right'] = rect.right() self.settings['top'] = rect.top() self.settings['bot'] = rect.bottom() if was_live: self.start_video() else: if not self._uncropped_pixmap: self._uncropped_pixmap = self.pixmapitem.pixmap() self.pixmapitem.setPixmap(self._uncropped_pixmap.copy(rect)) self.setFixedSize(rect.width(), rect.height()) def uncrop(self): was_live = self.is_live if was_live: self.stop_video() for key in ['left', 'right', 'top', 'bot']: if key in self.settings: del self.settings[key] if was_live: self.start_video() else: pixmap = self._uncropped_pixmap self.pixmapitem.setPixmap(pixmap) ir = self.pixmapitem.boundingRect() sr = self.pixmapitem.sceneTransform().mapRect(ir) self.scene.setSceneRect(sr) self.setFixedSize(sr.width(), sr.height()) def mapSceneToPixmap(self, pt): transform = self.pixmapitem.sceneTransform().inverted()[0] return transform.mapRect(pt) if isinstance( pt, (QRect, QRectF)) else transform.map(pt) def mapViewToPixmap(self, view_pt): scene_pt = self.mapToScene(view_pt) return self.mapSceneToPixmap(scene_pt) def mapPixmapToScene(self, pixmap_pt): transform = self.pixmapitem.sceneTransform() map_func = transform.mapRect if isinstance(pixmap_pt, (QRect, QRectF)) else transform.map return map_func(pixmap_pt) def mapSceneToCamera(self, sc_pt): px_pt = self.mapSceneToPixmap(sc_pt) return QPoint(px_pt.x() + self.settings.get('left', 0), px_pt.y() + self.settings.get('top', 0)) def set_image(self, image_arr): pixmap = QPixmap(self._array_to_qimage(image_arr)) if not self.pixmapitem: self.pixmapitem = self.scene.addPixmap(pixmap) else: self.pixmapitem.setPixmap(pixmap) if self.needs_resize: self._autoresize_viewport() self.needs_resize = False def _autoresize_viewport(self): ir = self.pixmapitem.boundingRect() sr = self.pixmapitem.sceneTransform().mapRect(ir) self.scene.setSceneRect(sr) #self.setFixedSize(sr.width(), sr.height()) self.resize(sr.width(), sr.height()) #self.viewport().setMaximumSize(sr.width(), sr.height()) d = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setMaximumSize(sr.width() + 2 * d, sr.height() + 2 * d) def grab_image(self): arr = self.cam.grab_image(**self.settings) self.set_image(arr) self.latest_array = arr self.imageDisplayed.emit(arr) def start_video(self): timer = QTimer() self.timer = timer timer.timeout.connect(self._wait_for_frame) self.cam.start_live_video(**self.settings) timer.start(0) # Run full throttle self.is_live = True self.needs_resize = True self.videoStarted.emit() def stop_video(self): self.timer.stop() self.cam.stop_live_video() self.is_live = False def _wait_for_frame(self): frame_ready = self.cam.wait_for_frame(timeout='0 ms') if frame_ready: arr = self.cam.latest_frame(copy=True) self.set_image(arr) self.latest_array = arr self.imageDisplayed.emit(arr) def _scale_image(self, arr): """Return a bytescaled copy of the image array""" if not self._cmax: self._cmax = arr.max() # Set cmax once from first image return scipy.misc.bytescale(arr, self._cmin, self._cmax) def _lut_scale_image(self, arr): if not self._cmax: self._cmax = arr.max() lut = scipy.misc.bytescale(np.arange(2**16), self._cmin, self._cmax) return lut[arr] def _create_lut(self, k): A = 2**15 B = 100 # k's scaling factor g = lambda i, k: A * ((k - B) * i) / ((2 * k) * x - (k + B) * A) def _array_to_qimage(self, arr): bpl = arr.strides[0] is_rgb = len(arr.shape) == 3 if is_rgb and arr.dtype == np.uint8: format = QImage.Format_RGB32 image = QImage(arr.data, self.cam.width, self.cam.height, bpl, format) elif not is_rgb and arr.dtype == np.uint8: # TODO: Somehow need to make sure data is ordered as I'm assuming format = QImage.Format_Indexed8 image = QImage(arr.data, self.cam.width, self.cam.height, bpl, format) self._saved_img = arr elif not is_rgb and arr.dtype == np.uint16: arr = self._scale_image(arr) format = QImage.Format_Indexed8 w, h = self.cam.width, self.cam.height image = QImage(arr.data, w, h, w, format) self._saved_img = arr # Save a reference to keep Qt from crashing else: raise Exception("Unsupported color mode") return image
class Image_Note(QMainWindow, gui_window.Ui_MainWindow): def __init__(self, parent=None): super(Image_Note, self).__init__(parent) self.setupUi(self) self.button_browse.clicked.connect(self.browse_file) self.button_browse_pdf.clicked.connect(self.browse_pdf_file) self.slider.setMinimum(0) self.slider.setMaximum(100) self.slider.setValue(40) self.button_reset.clicked.connect(self.reset) self.slider.valueChanged.connect(self.sensitivity_slider) self.button_delete.clicked.connect(self.remove_residual_images) self.button_save.clicked.connect(self.save_image) self.button_pdf_save.clicked.connect(self.save_pdf) self.visibility_widgets() def visibility_widgets(self, disable: bool = False): self.all_widgets = [ self.button_delete, self.button_pdf_save, self.button_reset, self.button_save, self.slider ] for widget in self.all_widgets: widget.setEnabled(disable) print(type(widget)) def sensitivity_slider(self): value = self.slider.value() print(value) self.thumbnail_image = Image.open(self.thumbnail_address) self.thumbnail_address_converted = \ file_handler.filepath_modified_suffix( self.thumbnail_address) convert_util.convert_sample(self.thumbnail_address, self.thumbnail_address_converted, value) self.load_graphics_image(self.thumbnail_address_converted) def reset(self): self.slider.setValue(40) self.thumbnail_image = Image.open(self.thumbnail_address) self.load_graphics_image(self.thumbnail_address) def remove_residual_images(self): file_handler.remove_file(self.thumbnail_address) file_handler.remove_file(self.thumbnail_address_converted) def save_image(self): value = self.slider.value() convert_util.convert_full_image(self.file_address, self.modified_image_address, value) def save_pdf(self): import os if not os.path.exists(self.modified_image_address): self.save_image() convert_util.convert_image_to_pdf( self.modified_image_address, file_handler.change_path_extension(self.modified_image_address, ".pdf")) # def pdf_convert(self): # self.save_image() # convert_util.convert_image_to_pdf(self.modified_image_address, # file_handler.change_path_extension( # noqa # self.modified_image_address, # ".pdf")) def browse_pdf_file(self): self.pdf_file_address = QFileDialog.getOpenFileName( self, 'Open PDF File')[0] # print(self.pdf_file_address[0]) self.file_address = file_handler.change_path_extension( self.pdf_file_address, ".png") convert_util.convert_pdf_to_image(self.pdf_file_address, self.file_address) self.process_file() def browse_file(self): response = QFileDialog.getOpenFileName(self, 'Open Image File') self.file_address = response[0] if not os.path.exists(self.file_address): return # return self.process_file() def process_file(self): self.thumbnail_address: str = file_handler.filepath_modified_suffix( self.file_address, "_thumbnail") self.modified_image_address: str = \ file_handler.filepath_modified_suffix( self.file_address) image_handler.save_thumbnail(Image.open(self.file_address), self.thumbnail_address) self.visibility_widgets(True) self.load_graphics_image(self.thumbnail_address) def load_graphics_image(self, image_address: str): self.graphics_scene = QGraphicsScene() self.graphics_scene.addPixmap(QPixmap(image_address)) self.graphicsView.setScene(self.graphics_scene)