class ImageEditView(FlaskView): route_base = '/' def __init__(self): self.controller = ImageController() @route('/image/edit/rotate/<dataset>/<imageid>', methods=['GET']) def rotate_image(self, dataset, imageid): (ok, error, orientation) = view_tools.get_param_from_request( request, "orientation") if not ok or orientation == "": raise error_views.InvalidParametersError( "Need to specify the orientation for the rotation: cw or ccw") (ok, error) = self.controller.rotate_image(dataset, imageid, orientation) if not ok: raise error_views.InvalidParametersError(error) return "", 200 @route('/image/edit/flip/<dataset>/<imageid>', methods=['GET']) def flip_image(self, dataset, imageid): (ok, error, direction) = view_tools.get_param_from_request(request, "direction") if not ok or direction == "": raise error_views.InvalidParametersError( "Need to specify the direction for the rotation: h or v") (ok, error) = self.controller.flip_image(dataset, imageid, direction) if not ok: raise error_views.InvalidParametersError(error) return "", 200 @route('/image/edit/ratio/<dataset>/<imageid>', methods=['GET']) def ratio_image(self, dataset, imageid): (ok, error, aspect) = view_tools.get_param_from_request(request, "aspect_ratio") if not ok or aspect == "": raise error_views.InvalidParametersError( "Need to specify the aspect ratio: 4:3") (ok, error) = self.controller.set_aspect_ratio_image( dataset, imageid, aspect) if not ok: raise error_views.InvalidParametersError(error) return "", 200
def set_partition(self, dataset_name, partitions, percentages): """ This function sets the partition (usually test and training) """ if len(partitions) == 0: return (False, "No partition provided!") if len(partitions) != len(percentages): return ( False, "Number of percentages should be equal to the number of partitions." ) ps = [DatasetController.partition_id(p) for p in partitions] if -1 in ps: return (False, "Did not recognize some (or all) partitions specified.") if sum(percentages) - 1 > 10e-3: return (False, "Sum of percentages should be equal to one.") all_images = ImageController.all_images(dataset_name) random.shuffle(all_images) if len(percentages) > 2: return (False, "More than one partition not implemented") fold1 = int(len(all_images) * percentages[0]) for img in all_images[:fold1]: self.image_controller.set_partition(dataset_name, img["phash"], ps[0]) for img in all_images[fold1:]: self.image_controller.set_partition(dataset_name, img["phash"], ps[1]) return (True, "")
def get_all_dataset_anno(self, dataset): all_images = ImageController.all_images(dataset) all_annotations = [] for img in all_images: app.logger.info("img: "+str(img["annotation"])) for i, anno in enumerate(img["annotation"]): d = { "top": anno.top, "bottom": anno.bottom, "left": anno.left, "right": anno.right, "labels": anno.labels, "ignore": anno.ignore, "image_url": img["url"], "anno_ith": i } all_annotations.append(d) ok_pagesize, _, page_size = view_tools.get_param_from_request(request, 'itemsPerPage') ok_page, _, page_number = view_tools.get_param_from_request(request, 'pageNumber') if ok_pagesize and ok_page: return flask.jsonify({ "annotations": self.paginate(all_annotations, int(page_number), int(page_size)), "pageNumber": int(page_number), "itemsPerPage": int(page_size), "totalPages": len(all_annotations)//int(page_size)}) else: return flask.jsonify({"annotations": all_annotations})
def get_plugin_process_partition(self, dataset, partition): self.get_plugin_from_request(request) if partition == "" or (partition != "training" and partition != "testing"): raise error_views.InvalidParametersError( "Partition not informed or invalid.") self.controller.init_plugin( self.dataset_controller.get_dataset(dataset), partition) all_imgs = ImageController.all_images(dataset) for im_obj in all_imgs: (img_m, img_o) = self.get_image_matrix_and_dict(dataset, im_obj['phash']) (img_m, img_o) = self.controller.process(img_m, img_o) bbs_vec = [] for bb in img_o['anno']: bbox_o = BBox(bb['top'], bb['left'], bb['bottom'], bb['right'], bb['labels'], bb['ignore']) bbs_vec.append(bbox_o) self.image_controller.change_annotations(dataset, img_o['phash'], bbs_vec) plugin_res = self.controller.end_plugin() return flask.jsonify({"plugin_response": plugin_res})
class UploadViewWebApp(FlaskView): route_base = '/' def __init__(self): self.dataset_controller = DatasetController() self.image_controller = ImageController() @route('/add/images', methods=['GET']) def datasets(self): datasets = self.dataset_controller.get_datasets() return render_template('upload_images.html', datasets=datasets) def allowed_file(self, filename): ALLOWED_EXTENSIONS = set(['bmp', 'png', 'jpg', 'jpeg', 'gif']) return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS def get_frontend_image(self, request): file = request.files['file'] filename = secure_filename(file.filename) file.save(os.path.join('/tmp/', filename)) # load from file and read image try: image = cv2.imread(os.path.join('/tmp/', filename)) return image except: raise error_views.InternalError( 'Unable to read image from local folder.') @route('/image/front-upload', methods=['POST']) def create_image(self): file = request.files['file'] if file and self.allowed_file(file.filename): if 'dataset' not in request.form: raise error_views.InternalError('No dataset provided!') dataset_name = request.form['dataset'] category = 'default' if 'category' in request.form: category = request.form['category'] image = self.get_frontend_image(request) (ok, error, image_id) = self.image_controller.create_image(dataset_name, image, name=file.filename, category=category) if not ok: raise error_views.InvalidParametersError(error) return '', 200 else: raise error_views.InternalError( 'The provided file is not an accepted extension.')
def get_all_images(self, dataset): all_images = ImageController.all_images(dataset) ok_pagesize, _, page_size = view_tools.get_param_from_request( request, 'itemsPerPage') ok_page, _, page_number = view_tools.get_param_from_request( request, 'pageNumber') if ok_pagesize and ok_page: return flask.jsonify({ "images": self.paginate(all_images, int(page_number), int(page_size)), "pageNumber": int(page_number), "itemsPerPage": int(page_size), "totalPages": len(all_images) // int(page_size) }) else: return flask.jsonify({"images": all_images})
def get_plugin_process(self, dataset): self.get_plugin_from_request(request) self.controller.init_plugin( self.dataset_controller.get_dataset(dataset)) all_imgs = ImageController.all_images(dataset) for im_obj in all_imgs: (img_m, img_o) = self.get_image_matrix_and_dict(dataset, im_obj['phash']) (img_m, img_o) = self.controller.process(img_m, img_o) bbs_vec = [] for bb in img_o['anno']: bbox_o = BBox(bb['top'], bb['left'], bb['bottom'], bb['right'], bb['labels'], bb['ignore']) bbs_vec.append(bbox_o) self.image_controller.change_annotations(dataset, img_o['phash'], bbs_vec) plugin_res = self.controller.end_plugin() return flask.jsonify({"plugin_response": plugin_res})
def get_annotated_images(self, dataset): all_images = ImageController.all_images(dataset) app.logger.info('all_images' + str(all_images)) annotated = [im for im in all_images if len(im["annotation"]) > 0] ok_pagesize, _, page_size = view_tools.get_param_from_request( request, 'itemsPerPage') ok_page, _, page_number = view_tools.get_param_from_request( request, 'pageNumber') if ok_pagesize and ok_page: return flask.jsonify({ "images": self.paginate(annotated, int(page_number), int(page_size)), "pageNumber": int(page_number), "itemsPerPage": int(page_size), "totalPages": len(annotated) // int(page_size) }) else: return flask.jsonify({"images": annotated})
class DatasetController(): def __init__(self): self.image_controller = ImageController() self.ref_controller = RefCountController() def create_dataset(self, dataset_name, tags): d = DatasetModel(dataset_name, tags) d.upsert() def get_dataset(self, dataset_name): dataset_obj = DatasetModel.from_name(dataset_name) if dataset_obj is None: return None labels = self.ref_controller.get_all_labels(dataset_obj.dataset_name) categories = self.ref_controller.get_all_categories( dataset_obj.dataset_name) dataset_d = { "name": dataset_obj.dataset_name, "tags": (None if dataset_obj.tags is None else sorted(dataset_obj.tags)), "annotation_labels": sorted(labels), "image_categories": sorted(categories), "category_colors": ColorUtils.distiguishable_colors_hex(len(categories)) } return dataset_d def get_datasets(self, dataset_name=""): if dataset_name == "": rows = DatasetModel.list_datasets() datasets = [] for ds_row in rows: datasets.append({ 'name': ds_row.name, 'tags': (None if ds_row.tags is None else sorted(ds_row.tags)), 'annotation_labels': sorted(self.ref_controller.get_all_labels(ds_row.name)), 'image_categories': sorted(self.ref_controller.get_all_categories( ds_row.name)), 'last_modified': ds_row.last_modified }) if len(datasets) > 0: datasets = sorted(datasets, key=lambda k: k['name'].lower()) return datasets def set_partition(self, dataset_name, partitions, percentages): """ This function sets the partition (usually test and training) """ if len(partitions) == 0: return (False, "No partition provided!") if len(partitions) != len(percentages): return ( False, "Number of percentages should be equal to the number of partitions." ) ps = [DatasetController.partition_id(p) for p in partitions] if -1 in ps: return (False, "Did not recognize some (or all) partitions specified.") if sum(percentages) - 1 > 10e-3: return (False, "Sum of percentages should be equal to one.") all_images = ImageController.all_images(dataset_name) random.shuffle(all_images) if len(percentages) > 2: return (False, "More than one partition not implemented") fold1 = int(len(all_images) * percentages[0]) for img in all_images[:fold1]: self.image_controller.set_partition(dataset_name, img["phash"], ps[0]) for img in all_images[fold1:]: self.image_controller.set_partition(dataset_name, img["phash"], ps[1]) return (True, "") def purge_dataset(self, dataset_name): # first delete all iamges/annotations from the dataset ok, error = ImageModel.delete_all_images(dataset_name) if ok: d = DatasetModel(dataset_name) ok, error = d.delete() return ok, error else: return ok, error @staticmethod def partition_id(partition): if partition.lower() == "training": return 0 elif partition.lower() == "testing": return 1 else: return -1
def __init__(self): self.image_controller = ImageController() self.ref_controller = RefCountController()
def __init__(self): self.dataset_controller = DatasetController() self.image_controller = ImageController()
def __init__(self): self.controller = ImageController()
class ImageView(FlaskView): route_base = '/' def __init__(self): self.controller = ImageController() @route('/image/<dataset>/<imageid>', methods=['DELETE']) def delete_image(self, dataset, imageid): (ok, error) = self.controller.delete_image(dataset, imageid) if not ok: raise error_views.InvalidParametersError(error) else: return '', 200 @route('/image/details/<dataset>/<imageid>', methods=['GET']) def get_image_details(self, dataset, imageid): img_details = self.controller.get_image_details(dataset, imageid) return flask.jsonify({"image": img_details}) @route('/image/<dataset>/<imageid>', methods=['GET']) def get_image(self, dataset, imageid): img = self.controller.get_image(dataset, imageid) ret, img_bin = cv2.imencode(".jpg", img) return flask.send_file(BytesIO(img_bin), mimetype='image/jpeg') @route('/image/thumb/<dataset>/<imageid>', methods=['GET']) def get_image_thumb(self, dataset, imageid): img = self.controller.get_image(dataset, imageid) img_o = self.controller.get_image_object(dataset, imageid) thumb = ImageUtils.create_thumbnail(img, img_o) ret, img_bin = cv2.imencode(".jpg", thumb) return flask.send_file(BytesIO(img_bin), mimetype='image/jpeg') @route('/image/cropanno/<dataset>/<imageid>/<annotation_i>', methods=['GET']) def get_image_annotation_cropped(self, dataset, imageid, annotation_i): img = self.controller.get_image(dataset, imageid) img_o = self.controller.get_image_object(dataset, imageid) if int(annotation_i) < len(img_o.bboxes): cropped_annotation = ImageUtils.crop_image( img, img_o.bboxes[int(annotation_i)]) else: cropped_annotation = img ret, img_bin = cv2.imencode(".jpg", cropped_annotation) return flask.send_file(BytesIO(img_bin), mimetype='image/jpeg') def paginate(self, list, page_number, page_size): start_elem = page_size * (page_number - 1) return list[start_elem:start_elem + page_size] @route('/image/<dataset>/all', methods=['GET']) def get_all_images(self, dataset): all_images = ImageController.all_images(dataset) ok_pagesize, _, page_size = view_tools.get_param_from_request( request, 'itemsPerPage') ok_page, _, page_number = view_tools.get_param_from_request( request, 'pageNumber') if ok_pagesize and ok_page: return flask.jsonify({ "images": self.paginate(all_images, int(page_number), int(page_size)), "pageNumber": int(page_number), "itemsPerPage": int(page_size), "totalPages": len(all_images) // int(page_size) }) else: return flask.jsonify({"images": all_images}) @route('/image/<dataset>/annotated', methods=['GET']) def get_annotated_images(self, dataset): all_images = ImageController.all_images(dataset) app.logger.info('all_images' + str(all_images)) annotated = [im for im in all_images if len(im["annotation"]) > 0] ok_pagesize, _, page_size = view_tools.get_param_from_request( request, 'itemsPerPage') ok_page, _, page_number = view_tools.get_param_from_request( request, 'pageNumber') if ok_pagesize and ok_page: return flask.jsonify({ "images": self.paginate(annotated, int(page_number), int(page_size)), "pageNumber": int(page_number), "itemsPerPage": int(page_size), "totalPages": len(annotated) // int(page_size) }) else: return flask.jsonify({"images": annotated}) @route('/image/<dataset>/add', methods=['POST']) def create_image(self, dataset): """ Add and image to the dataset --- parameters: - name: the name of the image - category: a name of the category - image: multi-part from data """ (ok, error, image) = view_tools.get_image_from_request(request) if not ok: raise error_views.InvalidParametersError(error) (ok, error, category) = view_tools.get_param_from_request(request, "category") if not ok or category == "": category = "default" (ok, error, name) = view_tools.get_param_from_request(request, "name") if not ok: name = "" (ok, error, image_id) = self.controller.create_image(dataset, image, category=category, name=name) if not ok: raise error_views.InvalidParametersError(error) image_url = "{}/{}".format(dataset, image_id) return flask.jsonify({"imageId": image_id, "imageUrl": image_url})
class AnnoView(FlaskView): route_base = '/' def __init__(self): self.controller = ImageController() @route('/image/anno/<dataset>/<imageid>', methods=['GET']) def get_image_anno(self, dataset, imageid): image = self.controller.get_image_object(dataset, imageid) image_dict = view_tools.image_to_dict(image) return flask.jsonify(image_dict) @route('/image/anno/modify/label/<dataset>/<imageid>/<annotation_ith>', methods=['POST']) def modify_image_anno_label(self, dataset, imageid, annotation_ith): image_o = self.controller.get_image_object(dataset, imageid) ok, error, new_labels = view_tools.get_param_from_request(request, 'newLabels') # count points if the labels changed if current_user.is_authenticated: if image_o.bboxes[int(annotation_ith)].labels.sort() != new_labels.sort(): points = 1 else: points = 0.1 current_user.points = current_user.points + points current_user.upsert() b = BBox(image_o.bboxes[int(annotation_ith)].top, \ image_o.bboxes[int(annotation_ith)].left, \ image_o.bboxes[int(annotation_ith)].bottom, \ image_o.bboxes[int(annotation_ith)].right, \ new_labels, \ image_o.bboxes[int(annotation_ith)].ignore) image_o.bboxes[int(annotation_ith)] = b image_o.upsert() return '', 200 def paginate(self, list, page_number, page_size): start_elem = page_size * (page_number - 1) return list[start_elem:start_elem+page_size] @route('/image/anno/<dataset>/all', methods=['GET']) def get_all_dataset_anno(self, dataset): all_images = ImageController.all_images(dataset) all_annotations = [] for img in all_images: app.logger.info("img: "+str(img["annotation"])) for i, anno in enumerate(img["annotation"]): d = { "top": anno.top, "bottom": anno.bottom, "left": anno.left, "right": anno.right, "labels": anno.labels, "ignore": anno.ignore, "image_url": img["url"], "anno_ith": i } all_annotations.append(d) ok_pagesize, _, page_size = view_tools.get_param_from_request(request, 'itemsPerPage') ok_page, _, page_number = view_tools.get_param_from_request(request, 'pageNumber') if ok_pagesize and ok_page: return flask.jsonify({ "annotations": self.paginate(all_annotations, int(page_number), int(page_size)), "pageNumber": int(page_number), "itemsPerPage": int(page_size), "totalPages": len(all_annotations)//int(page_size)}) else: return flask.jsonify({"annotations": all_annotations}) @route('/image/has_annotation/<dataset>/<imageid>', methods=['GET']) def get_image_has_anno(self, dataset, imageid): image = self.controller.get_image_details(dataset, imageid) return flask.jsonify({"has_annotation": image["has_annotation"]}) @route('/image/anno/<dataset>/<imageid>', methods=['POST']) def post_image_anno(self, dataset, imageid): """ Parameters: - anno: a list of bounding boxes - scale: optional """ (ok, error, anno) = view_tools.get_param_from_request(request, 'anno') (ok_scale, _, scale) = view_tools.get_param_from_request(request, 'scale') try: bbs_vec = [] for bb in anno: bbox_o = BBox(bb['top'], bb['left'], bb['bottom'], bb['right'], bb['labels'], bb['ignore']) if ok_scale and scale != 1.0: bbox_o.scale_itself(scale) bbs_vec.append(bbox_o) except BaseException as e: return 'Problem with provided annotation',500 if current_user.is_authenticated: img_ob = self.controller.get_image_object(dataset, imageid) points = 0.1 if len(img_ob.bboxes) != len(bbs_vec): points = 1 else: old_labels = [bb.labels for bb in img_ob.bboxes] old_labels = list(itertools.chain.from_iterable(old_labels)) new_labels = [bb.labels for bb in bbs_vec] new_labels = list(itertools.chain.from_iterable(new_labels)) if old_labels.sort() != new_labels.sort(): points = 1 current_user.points = current_user.points + points current_user.upsert() self.controller.change_annotations(dataset, imageid, bbs_vec) return '', 200
class DatasetView(FlaskView): route_base = '/' def __init__(self): self.controller = DatasetController() self.image_controller = ImageController() @route('/dataset/all', methods=['GET']) def get_all_datasets(self): obj = self.controller.get_datasets() return flask.jsonify({"datasets": obj}) @route('/dataset/<dataset>', methods=['GET']) def get_dataset(self, dataset): # obj = self.image_controller.all_images(dataset) d = self.controller.get_dataset(dataset) if d == None: return "Dataset not found", 404 else: return flask.jsonify({"dataset": d}) @route('/dataset/<dataset>/size', methods=['GET']) def get_dataset_size(self, dataset): obj = self.image_controller.all_images(dataset) print("obj", obj) # return flask.jsonify({"dataset_size": len(obj)}) print('returning', flask.jsonify({"dataset_size": len(obj)})) return flask.jsonify({"dataset_size": len(obj)}) @route('/dataset/<dataset>', methods=['DELETE']) def delete_dataset(self, dataset): ok, error = self.controller.purge_dataset(dataset) if not ok: raise error_views.InvalidParametersError(error) else: return '', 200 @route('/dataset/<dataset>/partition', methods=['POST']) def create_partition(self, dataset): (ok, error, partitions) = view_tools.get_param_from_request( request, "partitions") if not ok: raise error_views.InvalidParametersError(error) (ok, error, percentages) = view_tools.get_param_from_request( request, "percentages") if not ok: raise error_views.InvalidParametersError(error) (ok, error) = self.controller.set_partition(dataset, partitions, percentages) if not ok: raise error_views.InvalidParametersError(error) return '', 200 @route('/dataset/create', methods=['POST']) def create_datasets(self): (ok, error, name) = view_tools.get_param_from_request(request, "name") if not ok: raise error_views.InvalidParametersError(error) (ok, error, tags) = view_tools.get_param_from_request(request, "tags") if not ok: raise error_views.InvalidParametersError(error) self.controller.create_dataset(name, tags) return flask.jsonify({"ok": "to-do"})
class PluginsView(FlaskView): route_base = '/' def __init__(self): self.controller = PluginsController() self.image_controller = ImageController() self.dataset_controller = DatasetController() @route('/plugins/process/<dataset>/<imageid>', methods=['GET']) def get_plugin_process_image(self, dataset, imageid): self.get_plugin_from_request(request) self.controller.init_plugin( self.dataset_controller.get_dataset(dataset)) (img_m, img_o) = self.get_image_matrix_and_dict(dataset, imageid) (img_m, img_o) = self.controller.process(img_m, img_o) plugin_res = self.controller.end_plugin() fileid = "img" # uuid.uuid4().hex full_filename = 'annotator_supreme/static/' + fileid + '.jpg' cv2.imwrite(full_filename, img_m) filename = 'static/' + fileid + '.jpg' # return flask.send_file(filename, mimetype='image/jpeg') img_bytes = cv2.imencode('.jpg', img_m)[1].tostring() img_encoded = base64.b64encode(img_bytes).decode() return flask.jsonify({ 'image': img_encoded, 'plugin_response': plugin_res }) @route('/plugins/process/<dataset>', methods=['GET']) def get_plugin_process(self, dataset): self.get_plugin_from_request(request) self.controller.init_plugin( self.dataset_controller.get_dataset(dataset)) all_imgs = ImageController.all_images(dataset) for im_obj in all_imgs: (img_m, img_o) = self.get_image_matrix_and_dict(dataset, im_obj['phash']) (img_m, img_o) = self.controller.process(img_m, img_o) bbs_vec = [] for bb in img_o['anno']: bbox_o = BBox(bb['top'], bb['left'], bb['bottom'], bb['right'], bb['labels'], bb['ignore']) bbs_vec.append(bbox_o) self.image_controller.change_annotations(dataset, img_o['phash'], bbs_vec) plugin_res = self.controller.end_plugin() return flask.jsonify({"plugin_response": plugin_res}) @route('/plugins/process/partition/<dataset>/<partition>', methods=['GET']) def get_plugin_process_partition(self, dataset, partition): self.get_plugin_from_request(request) if partition == "" or (partition != "training" and partition != "testing"): raise error_views.InvalidParametersError( "Partition not informed or invalid.") self.controller.init_plugin( self.dataset_controller.get_dataset(dataset), partition) all_imgs = ImageController.all_images(dataset) for im_obj in all_imgs: (img_m, img_o) = self.get_image_matrix_and_dict(dataset, im_obj['phash']) (img_m, img_o) = self.controller.process(img_m, img_o) bbs_vec = [] for bb in img_o['anno']: bbox_o = BBox(bb['top'], bb['left'], bb['bottom'], bb['right'], bb['labels'], bb['ignore']) bbs_vec.append(bbox_o) self.image_controller.change_annotations(dataset, img_o['phash'], bbs_vec) plugin_res = self.controller.end_plugin() return flask.jsonify({"plugin_response": plugin_res}) @route('/plugins/all', methods=['GET']) def get_plugin_all(self): plugins = self.controller.get_all_plugins() return flask.jsonify({"plugins": sorted(plugins)}) def get_plugin_from_request(self, request): (ok, error, plugin_name) = view_tools.get_param_from_request(request, 'plugin') if not ok: raise error_views.InvalidParametersError(error) ok = self.controller.load_plugin(plugin_name) if not ok: print('An error occurred while loading plugin: ' + plugin_name) raise error_views.InternalError( 'An error occurred while loading plugin: ' + plugin_name) def get_image_matrix_and_dict(self, dataset, imageid): img = self.image_controller.get_image(dataset, imageid) img_o = self.image_controller.get_image_object(dataset, imageid) img_d = view_tools.image_to_dict(img_o) return (img, img_d)