Ejemplo n.º 1
0
class LabelUI():
    def __init__(self, label_db_filename, img_dir, sort=True):

        # what images to review?
        # note: drop trailing / in dir name (if present)
        self.img_dir = re.sub("/$", "", img_dir)
        self.files = os.listdir(img_dir)
        if sort:
            self.files = sorted(self.files)
        else:
            random.shuffle(self.files)
        print("%d files to review" % len(self.files))

        # label db
        self.label_db = LabelDB(label_db_filename)
        self.label_db.create_if_required()

        # TK UI
        root = tk.Tk()
        root.title(label_db_filename)
        root.bind('<Right>', self.display_next_image)
        print("RIGHT  next image")
        root.bind('<Left>', self.display_previous_image)
        print("LEFT   previous image")
        root.bind('<Up>', self.toggle_bees)
        print("UP     toggle labels")
        root.bind('N', self.display_next_unlabelled_image)
        print("N   next image with 0 labels")
        self.canvas = tk.Canvas(root, cursor='tcross')
        self.canvas.config(width=768, height=1024)
        self.canvas.bind('<Button-1>', self.add_bee_event)  # left mouse button
        self.canvas.bind('<Button-3>',
                         self.remove_closest_bee_event)  # right mouse button
        self.canvas.pack()

        # A lookup table from bee x,y to any rectangles that have been drawn
        # in case we want to remove one. the keys of this dict represent all
        # the bee x,y in current image.
        self.x_y_to_boxes = {}  # { (x, y): canvas_id, ... }

        # a flag to denote if bees are being displayed or not
        # while no displayed we lock down all img navigation
        self.bees_on = True

        # Main review loop
        self.file_idx = 0
        self.display_new_image()
        root.mainloop()

    def add_bee_event(self, e):
        if not self.bees_on:
            print("ignore add bee; bees not on")
            return
        self.add_bee_at(e.x, e.y)

    def add_bee_at(self, x, y):
        rectangle_id = self.canvas.create_rectangle(x - 2,
                                                    y - 2,
                                                    x + 2,
                                                    y + 2,
                                                    fill='red')
        self.x_y_to_boxes[(x, y)] = rectangle_id

    def remove_bee(self, rectangle_id):
        self.canvas.delete(rectangle_id)

    def toggle_bees(self, e):
        if self.bees_on:
            # store x,y s in tmp list and delete all rectangles from canvas
            self.tmp_x_y = []
            for (x, y), rectangle_id in self.x_y_to_boxes.items():
                self.remove_bee(rectangle_id)
                self.tmp_x_y.append((x, y))
            self.x_y_to_boxes = {}
            self.bees_on = False
        else:  # bees not on
            # restore all temp stored bees
            for x, y in self.tmp_x_y:
                self.add_bee_at(x, y)
            self.bees_on = True

    def remove_closest_bee_event(self, e):
        if not self.bees_on:
            print("ignore remove bee; bees not on")
            return
        if len(self.x_y_to_boxes) == 0: return
        closest_point = None
        closest_sqr_distance = 0.0
        for x, y in self.x_y_to_boxes.keys():
            sqr_distance = (e.x - x)**2 + (e.y - y)**2
            if sqr_distance < closest_sqr_distance or closest_point is None:
                closest_point = (x, y)
                closest_sqr_distance = sqr_distance
        self.remove_bee(self.x_y_to_boxes.pop(closest_point))

    def display_next_image(self, e=None):
        if not self.bees_on:
            print("ignore move to next image; bees not on")
            return
        self._flush_pending_x_y_to_boxes()
        self.file_idx += 1
        if self.file_idx == len(self.files):
            print("Can't move to image past last image.")
            self.file_idx = len(self.files) - 1
        self.display_new_image()

    def display_next_unlabelled_image(self, e=None):
        self._flush_pending_x_y_to_boxes()
        while True:
            self.file_idx += 1
            if self.file_idx == len(self.files):
                print("Can't move to image past last image.")
                self.file_idx = len(self.files) - 1
                break
            if not self.label_db.has_labels(self.files[self.file_idx]):
                break
        self.display_new_image()

    def display_previous_image(self, e=None):
        if not self.bees_on:
            print("ignore move to previous image; bees not on")
            return
        self._flush_pending_x_y_to_boxes()
        self.file_idx -= 1
        if self.file_idx < 0:
            print("Can't move to image previous to first image.")
            self.file_idx = 0
        self.display_new_image()

    def _flush_pending_x_y_to_boxes(self):
        # Flush existing points.
        img_name = self.files[self.file_idx]
        if len(self.x_y_to_boxes) > 0:
            self.label_db.set_labels(img_name, self.x_y_to_boxes.keys())
            self.x_y_to_boxes.clear()

    def display_new_image(self):
        img_name = self.files[self.file_idx]
        # Display image (with filename added)
        img = Image.open(self.img_dir + "/" + img_name)
        canvas = ImageDraw.Draw(img)
        canvas.text((0, 0), img_name, fill='black')
        self.tk_img = ImageTk.PhotoImage(img)
        self.canvas.create_image(0, 0, image=self.tk_img, anchor=tk.NW)
        # Look up any existing bees in DB for this image.
        existing_labels = self.label_db.get_labels(img_name)
        for x, y in existing_labels:
            self.add_bee_at(x, y)
Ejemplo n.º 2
0
import util as u

parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--true-db', type=str, required=True, help='true labels')
parser.add_argument('--predicted-db', type=str, required=True, help='predicted labels')
opts = parser.parse_args()
assert opts.true_db != opts.predicted_db

true_db = LabelDB(label_db_file=opts.true_db)
predicted_db = LabelDB(label_db_file=opts.predicted_db)

# iterate over predicted_db; we expect true_db to be a super set of it.
print("\t".join(["img", "#1_total", "#2_total", "ad", "#1_left", "#2_left"]))
total_TP = total_FP = total_FN = 0
for img in predicted_db.imgs():
  if not true_db.has_labels(img):
    # note: this can imply 0 labels
    raise Exception("img %s is in --predicted-db but not --true-db")

  true_labels = true_db.get_labels(img)
  predicted_labels = predicted_db.get_labels(img)
  TP, FP, FN = u.compare_sets(true_labels, predicted_labels)
  print("img", img, TP, FP, FN)

  total_TP += TP
  total_FP += FP
  total_FN += FN

precision = total_TP / ( total_TP + total_FP )
recall = total_TP / ( total_TP + total_FN )
f1 = 2 * (precision * recall) / (precision + recall)
Ejemplo n.º 3
0
# super clumsy :/

parser = argparse.ArgumentParser(
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--from-db',
                    type=str,
                    required=True,
                    help='db to take entries from')
parser.add_argument('--into-db',
                    type=str,
                    required=True,
                    help='db to add entries to')
opts = parser.parse_args()

assert opts.from_db != opts.into_db

from_db = LabelDB(label_db_file=opts.from_db)
into_db = LabelDB(label_db_file=opts.into_db)

num_ignored = 0
num_added = 0
for img in from_db.imgs():
    if into_db.has_labels(img):
        print("ignore", img, "; already in into_db")
        num_ignored += 1
    else:
        into_db.set_labels(img, from_db.get_labels(img))
        num_added += 1

print("num_ignored", num_ignored, "num_added", num_added)