From d986e8fc087fd9bf251a3033e02bc214a675619c Mon Sep 17 00:00:00 2001 From: alexander-g <3867427+alexander-g@users.noreply.github.com> Date: Sat, 13 Jun 2020 16:19:52 +0200 Subject: [PATCH] Added a tool to adjust image brightness and contrast. Useful for dark images (#494) * Added a tool to adjust image brightness and contrast. Useful for dark images. * Refactor brightness and contrast adjuster * Fix syntax error in Python2 Co-authored-by: Kentaro Wada --- labelme/app.py | 20 +++++++++ labelme/widgets/__init__.py | 2 + labelme/widgets/brightness_contrast_dialog.py | 45 +++++++++++++++++++ labelme/widgets/canvas.py | 5 ++- 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 labelme/widgets/brightness_contrast_dialog.py diff --git a/labelme/app.py b/labelme/app.py index 823f2f3..9477075 100644 --- a/labelme/app.py +++ b/labelme/app.py @@ -22,6 +22,7 @@ from labelme.label_file import LabelFile from labelme.label_file import LabelFileError from labelme.logger import logger from labelme.shape import Shape +from labelme.widgets import BrightnessContrastDialog from labelme.widgets import Canvas from labelme.widgets import LabelDialog from labelme.widgets import LabelListWidget @@ -401,6 +402,11 @@ class MainWindow(QtWidgets.QMainWindow): shortcuts['fit_width'], 'fit-width', self.tr('Zoom follows window width'), checkable=True, enabled=False) + brightnessContrast = action('&Brightness Contrast', + self.brightnessContrast, + None, 'color', + 'Adjust brightness and contrast', + enabled=False) # Group zoom controls into a list for easier toggling. zoomActions = (self.zoomWidget, zoomIn, zoomOut, zoomOrg, fitWindow, fitWidth) @@ -455,6 +461,7 @@ class MainWindow(QtWidgets.QMainWindow): createLineStripMode=createLineStripMode, zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg, fitWindow=fitWindow, fitWidth=fitWidth, + brightnessContrast=brightnessContrast, zoomActions=zoomActions, openNextImg=openNextImg, openPrevImg=openPrevImg, fileMenuActions=(open_, opendir, save, saveAs, close, quit), @@ -498,6 +505,7 @@ class MainWindow(QtWidgets.QMainWindow): createPointMode, createLineStripMode, editMode, + brightnessContrast, ), onShapesPresent=(saveAs, hideAll, showAll), ) @@ -554,6 +562,7 @@ class MainWindow(QtWidgets.QMainWindow): fitWindow, fitWidth, None, + brightnessContrast, ), ) @@ -584,6 +593,7 @@ class MainWindow(QtWidgets.QMainWindow): copy, delete, undo, + brightnessContrast, None, zoomIn, zoom, @@ -1238,6 +1248,16 @@ class MainWindow(QtWidgets.QMainWindow): self.zoomMode = self.FIT_WIDTH if value else self.MANUAL_ZOOM self.adjustScale() + def brightnessContrast(self, value): + + def onNewBrightnessContrast(qimage): + self.canvas.loadPixmap(QtGui.QPixmap.fromImage(qimage), + clear_shapes=False) + + dialog = BrightnessContrastDialog( + self.filename, onNewBrightnessContrast, parent=self) + dialog.exec_() + def togglePolygons(self, value): for item in self.labelList: item.setCheckState(Qt.Checked if value else Qt.Unchecked) diff --git a/labelme/widgets/__init__.py b/labelme/widgets/__init__.py index 198abf0..936f76a 100644 --- a/labelme/widgets/__init__.py +++ b/labelme/widgets/__init__.py @@ -1,5 +1,7 @@ # flake8: noqa +from .brightness_contrast_dialog import BrightnessContrastDialog + from .canvas import Canvas from .color_dialog import ColorDialog diff --git a/labelme/widgets/brightness_contrast_dialog.py b/labelme/widgets/brightness_contrast_dialog.py new file mode 100644 index 0000000..a95512b --- /dev/null +++ b/labelme/widgets/brightness_contrast_dialog.py @@ -0,0 +1,45 @@ +from qtpy.QtCore import Qt +from qtpy import QtGui +from qtpy import QtWidgets + +from PIL import Image +from PIL import ImageEnhance + + +class BrightnessContrastDialog(QtWidgets.QDialog): + def __init__(self, filename, callback, parent=None): + super(BrightnessContrastDialog, self).__init__(parent) + self.setModal(True) + self.setWindowTitle('Brightness/Contrast') + + self.slider_brightness = self._create_slider() + self.slider_contrast = self._create_slider() + + formLayout = QtWidgets.QFormLayout() + formLayout.addRow(self.tr('Brightness'), self.slider_brightness) + formLayout.addRow(self.tr('Contrast'), self.slider_contrast) + self.setLayout(formLayout) + + self.img = Image.open(filename).convert('RGBA') + self.callback = callback + + def onNewValue(self, value): + brightness = self.slider_brightness.value() / 100. + contrast = self.slider_contrast.value() / 100. + + img = self.img + img = ImageEnhance.Brightness(img).enhance(brightness) + img = ImageEnhance.Contrast(img).enhance(contrast) + + bytes = img.tobytes('raw', 'RGBA') + qimage = QtGui.QImage(bytes, + img.size[0], img.size[1], + QtGui.QImage.Format_RGB32).rgbSwapped() + self.callback(qimage) + + def _create_slider(self): + slider = QtWidgets.QSlider(Qt.Horizontal) + slider.setRange(0, 300) + slider.setValue(100) + slider.valueChanged.connect(self.onNewValue) + return slider diff --git a/labelme/widgets/canvas.py b/labelme/widgets/canvas.py index 8058e1f..3f781b8 100644 --- a/labelme/widgets/canvas.py +++ b/labelme/widgets/canvas.py @@ -708,9 +708,10 @@ class Canvas(QtWidgets.QWidget): self.drawingPolygon.emit(False) self.repaint() - def loadPixmap(self, pixmap): + def loadPixmap(self, pixmap, clear_shapes=True): self.pixmap = pixmap - self.shapes = [] + if clear_shapes: + self.shapes = [] self.repaint() def loadShapes(self, shapes, replace=True): -- GitLab