Skip to content

Commit

Permalink
Refactor app.py to use utils module
Browse files Browse the repository at this point in the history
  • Loading branch information
wkentaro committed Mar 16, 2019
1 parent 530ad3a commit 6e352f0
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 62 deletions.
137 changes: 75 additions & 62 deletions labelme/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,14 @@
from labelme import PY2
from labelme import QT5

from . import utils
from labelme.config import get_config
from labelme.label_file import LabelFile
from labelme.label_file import LabelFileError
from labelme.logger import logger
from labelme.shape import DEFAULT_FILL_COLOR
from labelme.shape import DEFAULT_LINE_COLOR
from labelme.shape import Shape
from labelme.utils import addActions
from labelme.utils import fmtShortcut
from labelme.utils import newAction
from labelme.utils import newIcon
from labelme.utils import struct
from labelme.widgets import Canvas
from labelme.widgets import ColorDialog
from labelme.widgets import EscapableQListWidget
Expand Down Expand Up @@ -186,7 +182,7 @@ def __init__(
self.addDockWidget(Qt.RightDockWidgetArea, self.file_dock)

# Actions
action = functools.partial(newAction, self)
action = functools.partial(utils.newAction, self)
shortcuts = self._config['shortcuts']
quit = action('&Quit', self.close, shortcuts['quit'], 'quit',
'Quit application')
Expand Down Expand Up @@ -341,11 +337,17 @@ def __init__(
zoom = QtWidgets.QWidgetAction(self)
zoom.setDefaultWidget(self.zoomWidget)
self.zoomWidget.setWhatsThis(
"Zoom in or out of the image. Also accessible with"
" %s and %s from the canvas." %
(fmtShortcut('%s,%s' % (shortcuts['zoom_in'],
shortcuts['zoom_out'])),
fmtShortcut("Ctrl+Wheel")))
'Zoom in or out of the image. Also accessible with '
'{} and {} from the canvas.'
.format(
utils.fmtShortcut(
'{},{}'.format(
shortcuts['zoom_in'], shortcuts['zoom_out']
)
),
utils.fmtShortcut("Ctrl+Wheel"),
)
)
self.zoomWidget.setEnabled(False)

zoomIn = action('Zoom &In', functools.partial(self.addZoom, 10),
Expand Down Expand Up @@ -401,13 +403,13 @@ def __init__(

# Lavel list context menu.
labelMenu = QtWidgets.QMenu()
addActions(labelMenu, (edit, delete))
utils.addActions(labelMenu, (edit, delete))
self.labelList.setContextMenuPolicy(Qt.CustomContextMenu)
self.labelList.customContextMenuRequested.connect(
self.popLabelListMenu)

# Store actions for further handling.
self.actions = struct(
self.actions = utils.struct(
saveAuto=saveAuto,
changeOutputDir=changeOutputDir,
save=save, saveAs=saveAs, open=open_, close=close,
Expand Down Expand Up @@ -465,7 +467,7 @@ def __init__(

self.canvas.edgeSelected.connect(self.actions.addPoint.setEnabled)

self.menus = struct(
self.menus = utils.struct(
file=self.menu('&File'),
edit=self.menu('&Edit'),
view=self.menu('&View'),
Expand All @@ -474,40 +476,59 @@ def __init__(
labelList=labelMenu,
)

addActions(self.menus.file, (open_, openNextImg, openPrevImg, opendir,
self.menus.recentFiles,
save, saveAs, saveAuto, changeOutputDir,
close, deleteFile,
None,
quit))
addActions(self.menus.help, (help,))
addActions(self.menus.view, (
self.flag_dock.toggleViewAction(),
self.label_dock.toggleViewAction(),
self.shape_dock.toggleViewAction(),
self.file_dock.toggleViewAction(),
None,
fill_drawing,
None,
hideAll,
showAll,
None,
zoomIn,
zoomOut,
zoomOrg,
None,
fitWindow,
fitWidth,
None,
))
utils.addActions(
self.menus.file,
(
open_,
openNextImg,
openPrevImg,
opendir,
self.menus.recentFiles,
save,
saveAs,
saveAuto,
changeOutputDir,
close,
deleteFile,
None,
quit,
),
)
utils.addActions(self.menus.help, (help,))
utils.addActions(
self.menus.view,
(
self.flag_dock.toggleViewAction(),
self.label_dock.toggleViewAction(),
self.shape_dock.toggleViewAction(),
self.file_dock.toggleViewAction(),
None,
fill_drawing,
None,
hideAll,
showAll,
None,
zoomIn,
zoomOut,
zoomOrg,
None,
fitWindow,
fitWidth,
None,
),
)

self.menus.file.aboutToShow.connect(self.updateFileMenu)

# Custom context menu for the canvas widget:
addActions(self.canvas.menus[0], self.actions.menu)
addActions(self.canvas.menus[1], (
action('&Copy here', self.copyShape),
action('&Move here', self.moveShape)))
utils.addActions(self.canvas.menus[0], self.actions.menu)
utils.addActions(
self.canvas.menus[1],
(
action('&Copy here', self.copyShape),
action('&Move here', self.moveShape),
),
)

self.tools = self.toolbar('Tools')
# Menu buttons on Left
Expand Down Expand Up @@ -603,7 +624,7 @@ def __init__(
def menu(self, title, actions=None):
menu = self.menuBar().addMenu(title)
if actions:
addActions(menu, actions)
utils.addActions(menu, actions)
return menu

def toolbar(self, title, actions=None):
Expand All @@ -612,7 +633,7 @@ def toolbar(self, title, actions=None):
# toolbar.setOrientation(Qt.Vertical)
toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
if actions:
addActions(toolbar, actions)
utils.addActions(toolbar, actions)
self.addToolBar(Qt.LeftToolBarArea, toolbar)
return toolbar

Expand All @@ -624,9 +645,9 @@ def noShapes(self):
def populateModeActions(self):
tool, menu = self.actions.tool, self.actions.menu
self.tools.clear()
addActions(self.tools, tool)
utils.addActions(self.tools, tool)
self.canvas.menus[0].clear()
addActions(self.canvas.menus[0], menu)
utils.addActions(self.canvas.menus[0], menu)
self.menus.edit.clear()
actions = (
self.actions.createMode,
Expand All @@ -637,7 +658,7 @@ def populateModeActions(self):
self.actions.createLineStripMode,
self.actions.editMode,
)
addActions(self.menus.edit, actions + self.actions.editMenu)
utils.addActions(self.menus.edit, actions + self.actions.editMenu)

def setDirty(self):
if self._config['auto_save'] or self.actions.saveAuto.isChecked():
Expand Down Expand Up @@ -803,7 +824,7 @@ def exists(filename):
menu.clear()
files = [f for f in self.recentFiles if f != current and exists(f)]
for i, f in enumerate(files):
icon = newIcon('labels')
icon = utils.newIcon('labels')
action = QtWidgets.QAction(
icon, '&%d %s' % (i + 1, QtCore.QFileInfo(f).fileName()), self)
action.triggered.connect(functools.partial(self.loadRecent, f))
Expand Down Expand Up @@ -1080,16 +1101,6 @@ def togglePolygons(self, value):
for item, shape in self.labelList.itemsToShapes:
item.setCheckState(Qt.Checked if value else Qt.Unchecked)

def convertImageDataToPng(self, imageData):
if imageData is None:
return
img = PIL.Image.open(io.BytesIO(imageData))
with io.BytesIO() as imgBytesIO:
img.save(imgBytesIO, "PNG")
imgBytesIO.seek(0)
data = imgBytesIO.read()
return data

def loadFile(self, filename=None):
"""Load the specified file, or the last opened file if None."""
# changing fileListWidget loads file
Expand Down Expand Up @@ -1123,8 +1134,10 @@ def loadFile(self, filename=None):
# https://github.com/ContinuumIO/anaconda-issues/issues/131
if QtGui.QImage.fromData(self.labelFile.imageData).isNull():
# tries to read image with PIL and convert it to PNG
self.labelFile.imageData = self.convertImageDataToPng(
self.labelFile.imageData)
if self.labelFile.imageData is not None:
self.labelFile.imageData = utils.img_data_to_png_data(
self.labelFile.imageData
)
if QtGui.QImage.fromData(self.labelFile.imageData).isNull():
raise LabelFileError(
'Failed loading image data from label file.\n'
Expand Down
1 change: 1 addition & 0 deletions labelme/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from .image import img_arr_to_b64
from .image import img_b64_to_arr
from .image import img_data_to_png_data

from .shape import labelme_shapes_to_label
from .shape import masks_to_bboxes
Expand Down
11 changes: 11 additions & 0 deletions labelme/utils/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,14 @@ def img_arr_to_b64(img_arr):
else:
img_b64 = base64.encodestring(img_bin)
return img_b64


def img_data_to_png_data(img_data):
with io.BytesIO() as f:
f.write(img_data)
img = PIL.Image.open(f)

with io.BytesIO() as f:
img.save(f, 'PNG')
f.seek(0)
return f.read()
8 changes: 8 additions & 0 deletions tests/utils_tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ def test_img_arr_to_b64():
img_b64 = image_module.img_arr_to_b64(img_arr)
img_arr2 = image_module.img_b64_to_arr(img_b64)
np.testing.assert_allclose(img_arr, img_arr2)


def test_img_data_to_png_data():
img_file = osp.join(data_dir, 'apc2016_obj3.jpg')
with open(img_file, 'rb') as f:
img_data = f.read()
png_data = image_module.img_data_to_png_data(img_data)
assert isinstance(png_data, bytes)

0 comments on commit 6e352f0

Please sign in to comment.