Source code for pyplis.forms

# -*- coding: utf-8 -*-
#
# Pyplis is a Python library for the analysis of UV SO2 camera data
# Copyright (C) 2017 Jonas Gliss (jonasgliss@gmail.com)
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License a
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division)
from collections import OrderedDict as od
from pyplis import logger
import six


[docs]class FormCollectionBase(object): """Abtract base class representing collection of geometrical forms. Abstract class providing basic functionality for object collections. Note that the basic management functions for adding / deleting forms :func:`add` , :func:`remove` create the objects based on start (x,y) and stop (x,y) points, i.e. [x0, y0, x1, y1] This class and classes inheriting from it show large similarities to dictionaries """
[docs] def __init__(self, forms_dict=None): """Class initialisation.""" if forms_dict is None: forms_dict = {} self._forms = od() self.id_count = 0 self.type = "" for key, val in six.iteritems(forms_dict): self[key] = val
[docs] def add(self, x0, y0, x1, y1, id=None): """Create a new form from input coordinates. :param int x0: x coordinate of start point :param int y0: y coordinate of start point :param int x1: x coordinate of stop point :param int y1: y coordinate of stop point :param str id: name of form (if None, it will be set automatically based on current object counter value) """ if not self.check_input(x0, y0, x1, y1): raise ValueError("Check coordinates...") if id in self.keys(): raise KeyError("A form with name %s already exists" % id) if x1 < x0: x0, y0, x1, y1 = x1, y1, x0, y0 if id is None: id = self.type + str(self.id_count) self._forms[id] = [x0, y0, x1, y1] self.id_count += 1 return True
@property def tot_num(self): """Return current number of forms in collection.""" return len(self._forms.keys())
[docs] def update(self, x0, y0, x1, y1, id): """Update an existing form (or create new if it does not exist).""" if id in self._forms.keys(): logger.info("Form with ID " + str(id) + " could not be updated because " "it does not exist, creating new form instead") self.remove(id) if self.add(x0, y0, x1, y1, id): return 1 return 0
[docs] def check_input(self, x0, y0, x1, y1): """Check if input for adding a form has the right format.""" items = [x0, y0, x1, y1] for item in items: if not any([isinstance(item, tp) for tp in [int, float]]): return False return True
[docs] def remove(self, id): """Remove one form from collection. :param str id: string id of the form to be deleted """ if id not in self._forms.keys(): logger.info("Error: could not delete form " + id + " from " "collection, no such form in collection") return 0 logger.info("Delete form " + id + " from collection") del self._forms[id]
[docs] def rename(self, current_id, new_id): """Rename one form.""" if new_id in self._forms.keys(): raise Exception("Error renaming form %s to %s. Such a form already" " exists in collection, delete the old one first " % (current_id, new_id)) l = self._forms[current_id] self.add(l[0], l[1], l[2], l[3], new_id) del self._forms[current_id]
""" Helpers """
[docs] def has_form(self, form_id): """Check if collection has a form with input ID, returns bool.""" if form_id in self._forms.keys(): return True return False
[docs] def form_info(self, form_id): """Print information about one of the forms in this collection. :param str form_id: string ID of form """ f = self[form_id] add_str = "" if f is None: add_str = "(Form does not exist in collection)" f = ["undefined", "undefined", "undefined", "undefined"] s = ("ID: %s %s\nStart (x,y): %s, %s\nStop (x,y): %s, %s\n" % (form_id, add_str, f[0], f[1], f[2], f[3])) return s
[docs] def keys(self): """Return names of all current forms.""" return list(self._forms.keys())
[docs] def values(self): """Return all current forms.""" return list(self._forms.values())
[docs] def get(self, form_id): """Get one form. :param str form_id: name of the form within collection """ return self[form_id]
""" Magic methods """ def __call__(self, key): """Make object callable. Returns form based on input key (see also :func:`__getitem__`) """ if key in self._forms.keys(): return self._forms[key] else: # Default behaviour raise AttributeError def __setitem__(self, key, val): """Set item method. Adds one form to this collection :param str key: string ID of new form :param list val: list with start / stop coords ``[x0,y0, x1, y1]`` """ try: self.add(val[0], val[1], val[2], val[3], key) except Exception as e: logger.info("Adding form failed_ %s" % repr(e)) def __getitem__(self, name): """Get item. Returns form with corresponding to input name (if it exists) """ try: return self._forms[name] except BaseException: logger.info("No such form: " + str(name)) def __str__(self): s = ("\nForm collection %s\n-----------------------\n" % self.type) if not bool(self.keys()): return s + "No forms available" for key, val in six.iteritems(self._forms): s = (s + "ID: %s\nStart (x,y): %s, %s\n" "Stop (x,y): %s, %s\n" % (key, val[0], val[1], val[2], val[3])) return s
[docs]class LineCollection(FormCollectionBase): """Class specifying line objects on images."""
[docs] def __init__(self, forms_dict=None): super(LineCollection, self).__init__(forms_dict) if forms_dict is None: forms_dict = {} self.type = "line"
[docs]class RectCollection(FormCollectionBase): """Class specifying rectangle objects on images."""
[docs] def __init__(self, forms_dict=None): super(RectCollection, self).__init__(forms_dict) if forms_dict is None: forms_dict = {} self.type = "rect"
[docs] def add(self, x0, y0, x1, y1, id=None): """Create a new form from input coordinates. :param int x0: x coordinate of start point :param int y0: y coordinate of start point :param int x1: x coordinate of stop point :param int y1: y coordinate of stop point :param str id: identification string of object (if None, the id will be set automatically based on current object counter value) """ tl_x, br_x = min([x0, x1]), max( [x0, x1]) # top left / bottom right x coorindates # top left / bottom right y coorindates tl_y, br_y = min([y0, y1]), max([y0, y1]) return super(RectCollection, self).add(tl_x, tl_y, br_x, br_y, id)
if __name__ == "__main__": rects = {"bla": [1, 2, 3, 4], "blub": [10, 20, 30, 40]} rectColl = RectCollection(rects) rectColl["bla"] = [3, 4, 5, 6]