In [35]:
from __future__ import print_function
#Importss
%matplotlib inline
import numpy as np
In [36]:
%%javascript
// Añadimos script que nos permite mostrar notificaciones bootstrap-growl
$('head').append('<script src="../../rsc/bootstrap-growl/jquery.bootstrap-growl.min.js">');
$('head').append('<link rel="stylesheet" href="Style.css">');
In [37]:
import ipywidgets as widgets
from traitlets import Unicode, validate, Bool, CBool, Any, List, observe
from ipywidgets import Color
from skimage import io
from skimage.transform import resize
class ImageLabelerWidget(widgets.DOMWidget):
_view_name = Unicode('ImageLabelerView').tag(sync=True)
_view_module = Unicode('ImageLabeler').tag(sync=True)
# Atributos sincronos entre js y python
image = Unicode('blank.png').tag(sync=True)
rect = List().tag(sync=True)
rect_to_add = List().tag(sync=True)
text_to_add = List().tag(sync=True)
removed_rect = List().tag(sync=True)
# Intento de carga de imágen incorrecto notificación
error_loading = Unicode('').tag(sync=True)
# Imagen guardada correctamente notificación
saved_successfuly = Unicode('').tag(sync=True)
# Texto a incluir en el rectangulo
text = Unicode('').tag(sync=True)
Phytolith_type = Any().tag(sync=True)
def __init__(self, *pargs, **kwargs):
super(widgets.DOMWidget, self).__init__(*pargs, **kwargs)
self._rectList = []
self._removed_rectList = []
# Para patron observer
self._rectList_observers = []
self._removed_rectList_observers = []
'''Método que se encarga de recibir la notificación
de la adicción de unas nuevas coordenadas a la imagen'''
@observe('rect')
def new_rect(self, change):
rec = change["new"]
self._rectList.append(rec)
# Callback a observers
for callback in self._rectList_observers:
callback(self._rectList)
'''Método que se encarga de recibir la notificación
de la eliminación de unas nuevas coordenadas a la imagen'''
@observe('removed_rect')
def old_rect(self, change):
removed_rec = change["new"]
#print("removed_rect", removed_rec)
#Cambiamos indices
self._removed_rectList.append(removed_rec)
# Callback a observers
for callback in self._removed_rectList_observers:
callback(self._removed_rectList)
'''Método para enlazar al observer con
el atributo rectList'''
def rectList_bind_to(self, callback):
self._rectList_observers.append(callback)
'''Método para enlazar al observer con
el atributo removed_rect'''
def removed_rect_bind_to(self, callback):
self._removed_rectList_observers.append(callback)
def get_rectList(self):
return self._rectList
def set_rectList(self, value):
self._rectList = value
In [38]:
import csv, json
from datetime import datetime
''' Rescalamos las coordenadas para que coincidan
las coordenadas de la vista con las de la imagen original'''
def transform_view_coords_to_image_coords(coords, svg_h, svg_w, real_image_h, real_image_w):
# TODO Cuidado con si es menor de svg_size x svg_size
# print("\t\t>>>Coords entrantes a conversión: ", coords)
# Rescalado de la imagen en la vista
if real_image_h > real_image_w:
coef = real_image_h / svg_h
svg_image_h = svg_h
svg_image_w = round(real_image_w / coef)
else:
coef = real_image_w / svg_w
svg_image_w = svg_w
svg_image_h = round(real_image_h / coef)
# Coeficientes de rescalado
coef_h = real_image_h / svg_image_h
coef_w = real_image_w / svg_image_w
# Calculamos padding en función de
# los valores de ancho y alto de la imagen
# en la vista
svg_padding_h = (svg_h - svg_image_h) / 2
svg_padding_w = (svg_w - svg_image_w) / 2
#TODO comprobar que las coordenadas no se salen de la imagen
new_coords = []
# Por cada rectangulo generamos una nueva imagen
# siempre que se encuentre dentro de la imagen
for rect_x, rect_y, rect_height, rect_width in coords:
rect_x = round((rect_x - svg_padding_h) * coef_h)
rect_y = round((rect_y - svg_padding_w) * coef_w)
rect_height = round(rect_height * coef_h)
rect_width = round(rect_width * coef_w)
rect_x2 = rect_x+rect_height
rect_y2 = rect_y+rect_width
# print("\t\t>>>Coords pre salientes conversión: ", coords)
# print(rect_x, rect_x2, rect_y, rect_y2)
# Comprobamos que las coordenadas estan dentro de la imagen
if rect_x > 0 and rect_x2 < real_image_h \
and rect_y2 < real_image_w and rect_y > 0:
new_coords.append([rect_x, rect_x2, rect_y, rect_y2])
# else:
# print(rect_x, ">", 0," and", rect_x2, "<", real_image_h, "and", rect_y2, "<", real_image_w, "and", rect_y, ">", 0)
# print("NO CONVERTIDA: ",[rect_x, rect_x2, rect_y, rect_y2])
return new_coords
In [39]:
''' Rescalamos las coordenadas para que coincidan
las coordenadas de la vista con las de la imagen original'''
def transform_image_coords_to_view_coords(coords, svg_h, svg_w, real_image_h, real_image_w):
# Rescalado de la imagen en la vista
if real_image_h > real_image_w:
coef = real_image_h / svg_h
svg_image_h = svg_h
svg_image_w = round(real_image_w / coef)
else:
coef = real_image_w / svg_w
svg_image_w = svg_w
svg_image_h = round(real_image_h / coef)
# Coeficientes de rescalado
coef_h = real_image_h / svg_image_h
coef_w = real_image_w / svg_image_w
# Calculamos padding en función de
# los valores de ancho y alto de la imagen
# en la vista
svg_padding_h = (svg_h - svg_image_h) / 2
svg_padding_w = (svg_w - svg_image_w) / 2
new_coords = []
# Por cada rectangulo generamos una nueva imagen
# siempre que se encuentre dentro de la imagen
for rect_x, rect_y, rect_height, rect_width in coords:
rect_x = round((rect_x / coef_h) + svg_padding_h)
rect_y = round((rect_y / coef_w) + svg_padding_w)
rect_height = round(rect_height / coef_h)
rect_width = round(rect_width / coef_w)
new_coords.append([rect_x, rect_y, rect_height, rect_width])
return new_coords
In [40]:
def additional_text():
# Timestamp for jpg files
time = datetime.today()
year = time.year
month = time.month
day = time.day
hour = time.hour
minute = time.minute
return str(year) + '_' + str(month) + '_' + str(day) \
+ '_' + str(hour) + '_' + str(minute)
'''Función que genera las imágenes a partir de las coordenadas'''
def save_coords_as_images(coords, image, dest_path, image_name):
# Por cada conjunto de rectangulos generamos una nueva imagen
for rect_x, rect_x2, rect_y, rect_y2 in coords:
name = image_name + str(rect_x) + \
'X'+ str(rect_x2) + 'X2'+str(rect_y) \
+ 'Y' + str(rect_y2) + 'Y2' + ".jpg"
img = image[rect_x:rect_x2,rect_y:rect_y2]
io.imsave(dest_path+name, img, quality=100)
'''Función que genera un fichero CSV a partir de las coordenadas'''
def save_coords_as_csv(coords, dest_path, image_name):
with open(dest_path+image_name+'.csv', 'w', newline='') as csvfile:
coords_writer = csv.writer(csvfile, delimiter=',',
quotechar='|', quoting = csv.QUOTE_MINIMAL)
# Por cada conjunto de rectangulos generamos una nueva imagen
for rect_x, rect_x2, rect_y, rect_y2 in coords:
coords_writer.writerow([rect_x,rect_x2,rect_y,rect_y2])
'''Función que genera un fichero JSON a partir de las coordenadas'''
def save_coords_as_json(coords, dest_path, image_name):
with open(dest_path + image_name+'.json', 'w') as jsonfile:
coords_dict = dict()
coords_dict[image_name+'.jpg'] = coords
json.dump(coords_dict, jsonfile)
'''Función que genera todos los ficheros anteriores'''
def save_as_all_formats(coords, image, dest_path, image_name):
save_coords_as_images(coords, image, dest_path, image_name)
save_coords_as_csv(coords, dest_path, image_name)
save_coords_as_json(coords, dest_path, image_name)
In [41]:
%%javascript
//Añadimos estilo a las notificaciones:
var error_type ='danger';
var success_type ='success';
var info_type = 'info';
var notify_style = {
ele: 'body', // which element to append to
offset: {from: 'bottom', amount: 20}, // 'top', or 'bottom'
align: 'left', // ('left', 'right', or 'center')
width: 'auto',//250, // (integer, or 'auto')
delay: 4000, // Time while the message will be displayed. It's not equivalent to the *demo* timeOut!
allow_dismiss: true, // If true then will display a cross to close the popup.
stackup_spacing: 10, // spacing between consecutively stacked growls.
}
function change_style(style, type){
style['type'] = type;
}
function sucess_image_notify(image_name){
change_style(notify_style, success_type);
if (image_name != "blank.png"){
var notify_msg = "La imagen " + image_name + " ha sido cargada correctamente!";
$.bootstrapGrowl(notify_msg, notify_style);
}
}
function error_image_notify(file_name){
change_style(notify_style, error_type);
if(file_name != "blank.png"){
var notify_msg = "El fichero " + file_name + " no " +
"tiene formato de imagen. Ejemplo: jpeg, jpg, tif, tiff, png ";
$.bootstrapGrowl(notify_msg, notify_style);
}
}
function success_saving_labels_notify(file_name){
change_style(notify_style, success_type);
if(file_name != "blank.png"){
var notify_msg = " Las etiquetas para la imagen " + file_name + " han " +
"sido guardadas correctamente ";
$.bootstrapGrowl(notify_msg, notify_style);
}
}
// JS Widget
require.undef('ImageLabeler');
var startX, startY;
var count = 0;
var rect = null;
var rectsList = [];
var model;
var myThis;
function getMousePos(evt) {
// Obtenemos posición absoluta del elemento svg
var svgRef = document.getElementById("svg");
var htmlPos = svgRef.getBoundingClientRect();
return {
x: evt.clientX - htmlPos.left,
y: evt.clientY - htmlPos.top
};
}
function updateRect(eve, rect){
var pos = getMousePos(eve);
var endX = pos.x;
var endY = pos.y;
if (endX - startX > 0){
var x = startX
}else{
var x = endX;
}
if (endY - startY > 0){
var y = startY
}else{
var y = endY;
}
var width = Math.abs(endX - startX);
var height = Math.abs(endY - startY);
rect.setAttributeNS(null, 'x', x);
rect.setAttributeNS(null, 'y', y);
rect.setAttributeNS(null, 'height', height);
rect.setAttributeNS(null, 'width', width);
}
function setStyleRect(rect){
rect.setAttributeNS(null, 'fill', 'transparent');
rect.setAttributeNS(null, 'stroke', 'green');
rect.setAttributeNS(null, 'linewidth', '10px');
}
function mouseMove(eve) {
if(rect){
updateRect(eve, rect);
}
}
function mouseClick(eve) {
if (rect !== null) {
//Cada vez que finalizamos el rectangulo
// , le añadimos a la lista
//console.log(rect.x['baseVal'].value,rect.y['baseVal'].value,rect.width['baseVal'].value,rect.height['baseVal'].value);
rectsList = [];
model.set('rect',[rect.y['baseVal'].value, rect.x['baseVal'].value, rect.height['baseVal'].value, rect.width['baseVal'].value]);
var svg = document.getElementById('svg');
var x= rect.x['baseVal'].value;
var y= rect.y['baseVal'].value;
var text = model.get('text');
// Añadimos la etiqueta de texto que deseemos al rectangulo
svg.innerHTML += "<text class='text' id='" + (count-1) + "txt" +"' x='"+ x +"' y='"+ y +"' font-family='Verdana' font-size='14px'>"+ text +"</text>"
var close = document.createElementNS("http://www.w3.org/2000/svg", "text");
close.setAttribute("id","closeParent"+(count-1));
close.setAttribute("class","close");
close.setAttribute("x",x);
close.setAttribute("y",y+14);
close.setAttribute("font-family","Verdana");
close.setAttribute("font-size","15px");
close.innerHTML += "<tspan id='close" + (count-1) + "' >x</tspan>";
svg.appendChild(close);
myThis.touch();
rect = null;
//console.log("finsihed.");
} else {
var text = $(event.target);
if (text.html() != "x"){
var pos = getMousePos(eve);
startX= pos.x;
startY = pos.y;
//console.log("begun.");
if(!rect){
rect = document.createElementNS("http://www.w3.org/2000/svg", 'rect');
rect.id = 'rect' + count;
rect.setAttribute('class', 'rect');
count = count + 1;
updateRect(eve, rect);
setStyleRect(rect);
document.getElementById('svg').appendChild(rect);
}
}else{
var closeId = text.attr("id");
//console.log(closeId);
var id = closeId[closeId.length - 1];
var closeParentId = "closeParent" + id;
var rectId = "rect" + id;
var textId = id + "txt";
//Obtenemos coordenadas del rectangulo
var removed_rect = document.getElementById(rectId);
//console.log('Eliminamos rect.')
// Transmitimos al kernel, python, el
// rectangulo a eliminar
model.set('removed_rect',[removed_rect.y['baseVal'].value, removed_rect.x['baseVal'].value, removed_rect.height['baseVal'].value, removed_rect.width['baseVal'].value]);
myThis.touch();
// Eliminamos todo lo relativo al rectangulo
document.getElementById(closeParentId).remove();
document.getElementById(rectId).remove();
document.getElementById(textId).remove();
}
}
}
// Funciones para la carga y cambio de imagen
function loadImage(svg, src){
$( ".rect" ).remove();
$( ".text" ).remove();
$( ".close" ).remove();
svg.innerHTML = '<image id="image" xlink:href="'+ src +'" x="0" y="0" height="500px" width="700px"/>'
}
function changeImage(svg, el, image){
//console.log("Cambio de imagen");
//console.log(image);
$( ".rect" ).remove();
$( ".text" ).remove();
$( ".close" ).remove();
svg.innerHTML = '<image id="image" xlink:href="' + image + '" x="0" y="0" height="500px" width="700px"/>';
el = svg;
}
// Definición del Widget en javasript
define('ImageLabeler', ["jupyter-js-widgets"], function(widgets) {
var svg;
var ImageLabelerView = widgets.DOMWidgetView.extend({
// Renderizar vista
render: function() {
model = this.model;
myThis = this;
// Creamos el SVG
svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.id = 'svg';
svg.setAttribute('height', '500px');
svg.setAttribute('width', '700px');
// Asignamos listeners al SVG
svg.addEventListener("click", mouseClick, false);
svg.addEventListener("mousemove", mouseMove, false);
// Imágen
var src = "../rsc/img/family.jpg";
loadImage(svg, src);
// Listener para cambios de imagen
this.image_changed();
this.model.on('change:image', this.image_changed, this);
// Listener para dibujar rectangulos dados
// desde Python
this.model.on('change:rect_to_add', this.add_rect, this);
// Listener para intento de cambio de imagen erroneo
this.model.on('change:error_loading', this.error_loading_image, this);
// Listener para notificar guardado de las imágenes
this.model.on('change:saved_successfuly', this.success_saving_labels, this);
// Asignamos a la vista el elemento SVG
this.el = svg;
},
// Función que se lanza con el cambio de imagen
image_changed: function() {
var image = this.model.get('image');
changeImage(svg, this.el, image);
console.log(image)
var image_name = image.split(/[/]+/);
image_name = image_name[image_name.length - 1];
sucess_image_notify(image_name);
},
// Función que se lanza cuando se intenta cargar un
// fichero distinto a una imagen
error_loading_image: function() {
var file_name = this.model.get('error_loading');
var file_name = file_name.split(/[/]+/);
file_name = file_name[file_name.length - 1];
error_image_notify(file_name);
},
// Función que se lanza cuando se guardan
// las etiquetas de la imagen
success_saving_labels: function() {
//console.log('File')
var file_name = this.model.get('image');
var file_name = file_name.split(/[/]+/);
file_name = file_name[file_name.length - 1];
success_saving_labels_notify(file_name);
},
// Función par dibujar rectangulos
// con coordenadas provistas por Python
add_rect: function() {
var rect_coords = this.model.get('rect_to_add');
//console.log("add rects", rect_coords);
var text_for_coords = this.model.get('text_to_add');
//console.log("text rects", text_for_coords[0]);
for (var i = 0; i < rect_coords.length; i++) {
var new_rect_coords = rect_coords[i];
var x = new_rect_coords[1];
var y = new_rect_coords[0];
var height = new_rect_coords[2];
var width = new_rect_coords[3];
//console.log('Add', x,' ', y, ' ',height, ' ', width);
var new_rect = document.createElementNS("http://www.w3.org/2000/svg", 'rect');
new_rect.id = 'rect' + count;
new_rect.setAttribute('class', 'rect');
count = count + 1;
new_rect.setAttributeNS(null, 'x', x);
new_rect.setAttributeNS(null, 'y', y);
new_rect.setAttributeNS(null, 'height', height);
new_rect.setAttributeNS(null, 'width', width);
setStyleRect(new_rect);
document.getElementById('svg').appendChild(new_rect);
var text = text_for_coords[i];
// Añadimos la etiqueta de texto que deseemos al rectangulo
svg.innerHTML += "<text class='text' id='" + (count-1) + "txt" +"' x='"+ x +"' y='"+ y +"' font-family='Verdana' font-size='14px'>"+ text +"</text>"
var close = document.createElementNS("http://www.w3.org/2000/svg", "text");
close.setAttribute("id","closeParent"+(count-1));
close.setAttribute("class","close");
close.setAttribute("x",x);
close.setAttribute("y",y+14);
close.setAttribute("font-family","Verdana");
close.setAttribute("font-size","15px");
close.innerHTML += "<tspan id='close" + (count-1) + "' >x</tspan>";
svg.appendChild(close);
}
myThis.touch();
},
});
return {
ImageLabelerView: ImageLabelerView
};
});
In [42]:
# Inicializamos Widget etiquetador de imágenes
image_labeler = ImageLabelerWidget()
In [43]:
# Clases para la gestión de directorios
import Directory_Manager
# Creamos directorios
dir_list = ['Rondel','Bulliform',
'Bilobate','Trichomas',
'Saddle', 'Spherical',
'Cyperaceae']
dir_manager = Directory_Manager.Directory_Manager(dir_list, current_dir= dir_list[0])
In [44]:
# Añadimos un diccionario que nos permita
# añadir las coordenadas segun el tipo de fitolito
# para guardar así la imagenes en el
# directorio que corresponda
coords_dict = dict()
''' Función que indexa las coordenadas al tipo de
fitolito que estamos eligiendo, de manera que añadimos
al diccionario cada una de las coordenadas que dibujamos
correspondiendo a la carpeta en la que sera guardada'''
def update_coords_list(coords_list):
# Coordenadas a añadir
coords_to_add = coords_list[len(coords_list)-1]
# Leemos el directorio seleccionado actualmente
current_dir_path = dir_manager.get_current_dir_path()
current_dir = dir_manager.get_current_dir()
# Si existia ya, añadimos coords a la lista
if current_dir_path in coords_dict:
coords_dict[current_dir_path].append(coords_to_add)
# Sino creamos lista y añadimos coords
else:
coords_dict[current_dir_path] = []
coords_dict[current_dir_path].append(coords_to_add)
# Patrón observe sobre la lista de coordenadas
image_labeler.rectList_bind_to(update_coords_list)
In [45]:
''' Función que se encarga de eliminar del diccionario
anterior las coordenadas del rectangulo que ha sido
eliminado por el usuario'''
def remove_coords_list(coords_list):
# Coordenadas a eliminar
# TODO Tener en cuenta transformación a realizar
coords_to_delete = coords_list[len(coords_list)-1]
# Comprobamos en que clave del
# diccionario se encuentran las
# coordenadas y las eliminamos
for k in coords_dict.keys():
#print("To remove", coords_to_delete)
if coords_to_delete in coords_dict[k]:
coords_dict[k].remove(coords_to_delete)
# Patrón observe sobre la lista de coordenadas
image_labeler.removed_rect_bind_to(remove_coords_list)
In [46]:
from IPython.display import display
import fileupload
import PIL.Image
import io as io2
from skimage.color import rgb2gray
''' Función que se encarga de aplicar las operaciones
necesarias para convertir los datos obtenidos del FileUpload
en una imagen'''
def image_converter(image):
image = io2.BytesIO(image)
image = PIL.Image.open(image)
return np.array(image)
In [47]:
from ipywidgets import HBox, VBox, Label, Layout
import re
import os.path
from time import sleep
#Inicializamos Widget de File Upload
upload_widget = fileupload.FileUploadWidget()
upload_widget.description = '(50% width, 80px height) button'
# Creamos el patron para el nombre
# de una imagen
pattern = re.compile("^.*\.(jpeg|jpg|tif|tiff|png)$", re.IGNORECASE)
# TODO Cuando se cambia de imagen
# hay que asegurarse de que las
# distintas variables se inicializan
# a los valores por defecto
# Callback para el cambio de imagen
def _cb(change):
# Limpiamos variables
coords_dict.clear()
change = change['owner']
# Control de que el fichero es una imagen
# y no otro tipo de fichero
if pattern.match(change.filename):
image = image_converter(change.data)
image_name = change.filename.split(".")[0]
image_path = dir_manager.get_default_dir() + image_name + ".jpg"
# Guardamos imagen
io.imsave(image_path, image, quality=100)
# Y la cargamos
image = io.imread(image_path)
# Sincronizamos cambio
image_labeler.image = image_path
# Comprobar si la imagen había
# sido previamente cargada.
# Si es así, cargamos etiquetas previas
name = change.filename.split(".")[0]
json_path = dir_manager.get_default_dir() +\
name + '.json'
if os.path.exists(json_path):
with open(json_path) as jsonfile:
old_coords_dict = json.load(jsonfile)[name + ".jpg"]
image_h, image_w, _ = image.shape
# Añadir al diccionario actual todas las coordenadas
# existentes para no eliminarlas al volver
# a guardar imagen
coords = []
text_to_add_with_coords = []
for k, _ in old_coords_dict.items():
#Añadimos los rectangulos
for rect_x, rect_x2, rect_y, rect_y2 in old_coords_dict[k]:
coord = [[rect_x, rect_y, rect_x2 - rect_x, rect_y2 - rect_y]]
coord = transform_image_coords_to_view_coords(coord, 500, 700, image_h, image_w)[0]
# Añadimos coordenadas a la variable en ejecucuión que las maneja
if dir_manager.get_possible_dir(k) in coords_dict:
coords_dict[dir_manager.get_possible_dir(k)].append(coord)
else:
coords_dict[dir_manager.get_possible_dir(k)] = [coord]
image_labeler.text = k
#print("New rect", coord)
text_to_add_with_coords.append(k)
coords.append(coord)
#image_labeler.rect_to_add = coord
#sleep(0.05)
image_labeler.text_to_add = text_to_add_with_coords
image_labeler.rect_to_add = coords
# Reasignamos valor por defecto a texto
image_labeler.text = 'Rondel'
else:
# Sino, lanzamos error
image_labeler.error_loading = change.filename
upload_widget.observe(_cb, names='data')
In [48]:
# Selector de fitolito
btns_selector =widgets.ToggleButtons(
options= dir_list,
#description='Tipo de fitolito',
disabled=False,
# 'success', 'info', 'warning', 'danger' or ''
button_style='',
tooltip='Description',
#icon='check'
)
'''Función que se encarga de hacer los cambios
necesarios al cambiar el fitolito que se etiqueta'''
def on_phytolith_change(change):
new_dir = change['new']
dir_manager.change_dir(new_dir)
image_labeler.text = new_dir
# listener del cambio de fitolito
btns_selector.observe(on_phytolith_change,names='value')
#Asignamos al texto del etiquetador por defecto al primer elemento de los botones
image_labeler.text = dir_list[0]
In [49]:
import warnings
# Añadimos el botón que se encarga de guardar
#las imágenes en el directorio correspondiente
save_btn = widgets.Button(
description='Guardar imágenes',
disabled=False,
button_style='',
tooltip='Guardar imágenes',
icon='check'
)
#Ignoramos warnings de calidad de imagen
warnings.filterwarnings('ignore')
'''Función que se encarga de llamar a la función
de guardar las etiquetas como imágenes'''
def on_save_btn_click(ch):
#Obtenemos el nombre de la imagen
image_path = image_labeler.image
image_name = os.path.split(image_path)[1]
image_name = image_name.split(".")[0]
# Cargamos imágen
image = io.imread(image_path)
# Eliminamos fichero json e imagen previa si
# había sido previamente etiquetada
json_path = dir_manager.get_default_dir() +\
image_name + ".json"
if os.path.exists(image_path):
#print(image_path)
os.remove(image_path)
if os.path.exists(json_path):
#print(json_path)
os.remove(json_path)
image_name =additional_text() + image_name
image_path = dir_manager.get_default_dir() + image_name + ".jpg"
#print(dir_manager.get_default_dir() + image_name)
#Guardamos imagen con fingerprint
io.imsave(image_path, image, quality=100)
image_h, image_w, _ = image.shape
coords_dict_copy = dict()
for path, coords_set in coords_dict.items():
# Transformamos las coordenadas
#print("\t>>k ->",path, " : ", coords_set)
coords_set = transform_view_coords_to_image_coords(coords_set, 500, 700, image_h, image_w)
#print("\t>>Despues de conversión, k ->",path, " : ", coords_set)
# Guardamos la imagenes en sus correspondientes directorios
#save_as_all_formats(coords_set, image, path, image_name)
save_coords_as_images(coords_set, image, path, image_name)
# Realizamos una copía para la posterior realización
# del fichero json con las claves siendo el tipo de fitolito
# y no el path
key = os.path.split(os.path.split(path)[0])[1]
coords_dict_copy[key] = coords_set
#print(">JSON to save before", coords_dict)
#print(">JSON to save", coords_dict_copy)
save_coords_as_json(coords_dict_copy, dir_manager.get_default_dir(), image_name)
# Notificamos al usuario que las etiquetas
#han sido guardadas correctamente
if image_labeler.saved_successfuly == 'false':
image_labeler.saved_successfuly = 'true'
else:
image_labeler.saved_successfuly = 'false'
# Eliminamos los rectangulos que añadimos para
# evitar redundacia de coordenadas
image_labeler.set_rectList([])
save_btn.on_click(on_save_btn_click)
In [50]:
# Formato de los widgets
right_size_widget = VBox([upload_widget, btns_selector, save_btn])
right_size_widget.width = '10%'
right_size_widget.margin = '5% 5% 5% 5%'
btns_selector.padding = '10%'
btns_selector.add_class("btns_selector")
upload_widget.padding = '10%'
upload_widget.add_class('btn')
image_labeler.margin = '5% 10% 0% 0%'
upload_widget.margin = '0 0 7% 12%'
upload_widget.width = '50'
save_btn.margin = '10%'
In [51]:
w = HBox([image_labeler,right_size_widget])
w.margin = '5%'
w.add_class('widget')
w