Giter Site home page Giter Site logo

list index out of range about mosaic HOT 2 CLOSED

codebox avatar codebox commented on June 11, 2024
list index out of range

from mosaic.

Comments (2)

codebox avatar codebox commented on June 11, 2024

Thanks for letting me know about this problem. There are a few things that might cause this, it would be helpful to know the following values when the error happens:
len(t1), len(t2), i, len(t1[i]), len(t2[i])
if you can get me these I can investigate further

from mosaic.

danieldoyharzabal avatar danieldoyharzabal commented on June 11, 2024

I could solve the problem with a little help, also add a small GUI with TKinter, I leave the code ... greetings

# -*- coding: utf-8 -*-
"""
Created on Thu Mar 09 19:59:07 2017

@author: Daniel Doyharzabal
"""

import sys, os, tkFileDialog, unicodedata
from multiprocessing import Process, Queue, cpu_count
from Tkinter import *
from PIL import Image
WORKER_COUNT = max(cpu_count() - 1, 1) #selecciona el maximo entre 1 y 1 menos el numero de procesador 
EOQ_VALUE = None #inicializa una variable como un objeto del tipo None (nada)    
salida = 'mosaico.jpeg' #da le nombre al archivo que se crea

class TileProcessor:
    def __init__(self, tiles_directory, tamanio, ENLARGEMENT, TILE_BLOCK_SIZE):
        self.tiles_directory = tiles_directory
        self.tamanio = tamanio
        self.ENLARGEMENT = ENLARGEMENT
        self.TILE_BLOCK_SIZE = TILE_BLOCK_SIZE

    def __process_tile(self, tile_path):
        try:
            img = Image.open(tile_path)
            # los mosaicos deben ser cuadrados, entonces seleciona el minimo entre largo y ancho y los recorta
            w = img.size[0]
            h = img.size[1]
            min_dimension = min(w, h)
            w_crop = (w - min_dimension) / 2
            h_crop = (h - min_dimension) / 2 
            img = img.crop((w_crop, h_crop, w - w_crop, h - h_crop))

            large_tile_img = img.resize((self.tamanio, self.tamanio), Image.ANTIALIAS)
            small_tile_img = img.resize((self.tamanio/self.TILE_BLOCK_SIZE, self.tamanio/self.TILE_BLOCK_SIZE), Image.ANTIALIAS)

            return (large_tile_img.convert('RGB'), small_tile_img.convert('RGB'))
        except:
            return (None, None)

    def get_tiles(self):
        large_tiles = []
        small_tiles = []
        
        print 'Leyendo mosaicos de \'%s\'...' % (self.tiles_directory, )
        
        # se buscan los mosaicos recursivamente en las subcarpetas de la direccion
        for root, subFolders, files in os.walk(self.tiles_directory):
            for tile_name in files:
                tile_path = os.path.join(root, tile_name)
                large_tile, small_tile = self.__process_tile(tile_path)
                if large_tile and small_tile:
                    large_tiles.append(large_tile)
                    small_tiles.append(small_tile)
        
        print 'Se procesaron %s mosaicos.' % (len(large_tiles),)
        return (large_tiles, small_tiles)

class TargetImage:
    def __init__(self, image_path, ENLARGEMENT, TILE_BLOCK_SIZE, tamanio):
        self.image_path = image_path
        self.ENLARGEMENT=ENLARGEMENT
        self.TILE_BLOCK_SIZE=TILE_BLOCK_SIZE
        self.tamanio=tamanio
    def get_data(self):
        print 'Procesando imagen principal...'
        img = Image.open(self.image_path)
        w = img.size[0] * self.ENLARGEMENT  #tamaño ancho
        h = img.size[1]    * self.ENLARGEMENT #tamaño alto
        large_img = img.resize((w, h), Image.ANTIALIAS) #retorna una copia cambiada de tamaño y filtrada con antialias
        w_diff = (w % self.tamanio)/2
        h_diff = (h % self.tamanio)/2
        
        # si es necesario recorta la imagen ligeramente para utilizar un numero entero de mosaicos horizontales y verticales
        if w_diff or h_diff:
            large_img = large_img.crop((w_diff, h_diff, w - w_diff, h - h_diff)) #recorta la imagen de cada lado es decir 4 datos necesarios
        small_img = large_img.resize((w/self.TILE_BLOCK_SIZE, h/self.TILE_BLOCK_SIZE), Image.ANTIALIAS)
        image_data = (large_img.convert('RGB'), small_img.convert('RGB'))
        print 'Imagen principal procesada.'
        return image_data

class TileFitter:
    def __init__(self, tiles_data):
        self.tiles_data = tiles_data

    def __get_tile_diff(self, t1, t2, bail_out_value):
        diff = 0
        if len(t1) - len(t2): return -1 #parcheado
        for i in range(len(t1)):
        
            diff += ((t1[i][0] - t2[i][0])**2 + (t1[i][1] - t2[i][1])**2 + (t1[i][2] - t2[i][2])**2)
            if diff > bail_out_value:
                # sabemos que este no es el mejor encaje, entonces no tiene sentido continuar con este mosaico
                return diff 
        return diff

    def get_best_fit_tile(self, img_data):
        best_fit_tile_index = None
        min_diff = sys.maxint
        tile_index = 0

        # va a traves de cada mosaico buscando el mejor encaje para la cuadricula de la imagen representada en 'img_data'
        for tile_data in self.tiles_data:
            diff = self.__get_tile_diff(img_data, tile_data, min_diff)
            if 0 < diff < min_diff: #cambio
                min_diff = diff
                best_fit_tile_index = tile_index
            tile_index += 1

        return best_fit_tile_index

def fit_tiles(work_queue, result_queue, tiles_data):
    # Esta función se ejecuta por los procesos de trabajo, uno en cada núcleo de la CPU
    tile_fitter = TileFitter(tiles_data)

    while True:
        try:
            img_data, img_coords = work_queue.get(True)
            if img_data == EOQ_VALUE:
                break
            tile_index = tile_fitter.get_best_fit_tile(img_data)
            if tile_index:
                result_queue.put((img_coords, tile_index))
        except KeyboardInterrupt:
            break

    # deja que result handler sepa que este procesador ha terminado
    result_queue.put((EOQ_VALUE, EOQ_VALUE))

class ProgressCounter:
    def __init__(self, total):
        self.total = total
        self.counter = 0

    def update(self):
        self.counter += 1
        sys.stdout.write("Progress: %s%% %s" % (100 * self.counter / self.total, "\r"))
        sys.stdout.flush();

class MosaicImage:
    def __init__(self, original_img, tamanio):
        self.tamanio=tamanio
        
        self.image = Image.new(original_img.mode, original_img.size)
        self.x_tile_count = original_img.size[0] / self.tamanio
        self.y_tile_count = original_img.size[1] / self.tamanio
        self.total_tiles  = self.x_tile_count * self.y_tile_count
        
    def add_tile(self, tile_data, coords):
        img = Image.new('RGB', (self.tamanio, self.tamanio))
        img.putdata(tile_data)
        self.image.paste(img, coords)

    def save(self, path):
        self.image.save(path)

def build_mosaic(result_queue, all_tile_data_large, original_img_large, tamanio):
    

    mosaic = MosaicImage(original_img_large, tamanio)
    
#  parcheado   active_workers = WORKER_COUNT
    
    while True:
        try:
            img_coords, best_fit_tile_index = result_queue.get()

            if img_coords == EOQ_VALUE:
                
#  parcheado              active_workers -= 1
#  parcheado              if not active_workers:
#  parcheado                  break
                break
            else:
                
                tile_data = all_tile_data_large[best_fit_tile_index]
                mosaic.add_tile(tile_data, img_coords)

        except KeyboardInterrupt:
            break
#  parcheado     pass

    mosaic.save(salida)
    print '\nFinalizado, la imagen de salida se encuentra en', salida

def terminal(original_img, tiles, taman, TILE_BLOCK): # terminal determina la parte visual del programa en la terminal de windows
    print 'Construyendo imagen, Ctrl+C para abortar...'
    original_img_large, original_img_small = original_img
    tiles_large, tiles_small = tiles

    mosaic = MosaicImage(original_img_large, taman)

    all_tile_data_large = map(lambda tile : list(tile.getdata()), tiles_large)
    all_tile_data_small = map(lambda tile : list(tile.getdata()), tiles_small)
    

    work_queue   = Queue(WORKER_COUNT)    
    result_queue = Queue()
    
    try:
        
        # comienza el proceso de construccion del mosaico
        p=Process(target=build_mosaic, args=(result_queue, all_tile_data_large, original_img_large, taman))
        
        p.start()
        
        # comienza el proceso de encaje de los mosaicos
        for n in range(WORKER_COUNT):
            Process(target=fit_tiles, args=(work_queue, result_queue, all_tile_data_small)).start()
            print("Proceso de construccion inicializado...")

        progress = ProgressCounter(mosaic.x_tile_count * mosaic.y_tile_count)
        
        for x in range(mosaic.x_tile_count):
            for y in range(mosaic.y_tile_count):
                large_box = (x * taman, y * taman, (x + 1) * taman, (y + 1) * taman)
                small_box = (x * taman/TILE_BLOCK, y * taman/TILE_BLOCK, (x + 1) * taman/TILE_BLOCK, (y + 1) * taman/TILE_BLOCK)
                work_queue.put((list(original_img_small.crop(small_box).getdata()), large_box))
                progress.update()

    except:
        print '\nGuardando imagen parcial, espere...'

    finally:
        
        # pone estos valores especiales en cola para dejar saber a los CPU que pueden terminar
        for n in range(WORKER_COUNT):
            work_queue.put((EOQ_VALUE, EOQ_VALUE))

def mosaic(): # definicion del metodo mosaic
    tamanio   = int(entero1.get())# alto y ancho de los mosaicos en pixeles
    TILE_MATCH_RES = int(entero2.get())    # resolulcion de encaje de mosaicos (valores altos mejoran el resultado pero requieren mas procesamiento)
    ENLARGEMENT    = int(entero3.get())    # la imagen mosaico sera esta cantidad de veces mas grande (en largo y ancho) que la imagen original    
    TILE_BLOCK_SIZE = tamanio / max(min(TILE_MATCH_RES, tamanio), 1) #tamaño de bloque de mosaico
    path=tkFileDialog.askdirectory() #seleccionar carpeta de mosaicos
    label_6.config(text=path)
    archivo=tkFileDialog.askopenfilename() #seleccionar que archivo abrir como imagen principal
    label_7.config(text=archivo)
    tiles_path=path 
    img_path=archivo 

    tiles_data = TileProcessor(tiles_path, tamanio, ENLARGEMENT, TILE_BLOCK_SIZE).get_tiles() # utiliza la direccion de los mosaicos de entrada para iniciar el procesamiento

    image_data = TargetImage(img_path, ENLARGEMENT, TILE_BLOCK_SIZE, tamanio).get_data()  #
    terminal(image_data, tiles_data, tamanio, TILE_BLOCK_SIZE)
    
#-------------------------- Interfaz Grafica ----------------------------------------------#
root=Tk()
root.title("Fotomosaico con Python")
root.geometry('650x400+200+200')

label_1= Label(root, text="Recortar Mosaicos")
label_2= Label(root, text="Resolucion Mosaicos")
label_3= Label(root, text="Agrandamiento")
label_4= Label(root, text="Direccion de Mosaicos")
label_5= Label(root, text="Direccion de Imagen")
label_6= Label(root, text="...")
label_7= Label(root, text="...")
label_8= Label(root, text="...")
    
x=StringVar()
y=StringVar()
z=StringVar()

entero1= Entry(root, textvariable='x')
entero2= Entry(root, textvariable='y')
entero3= Entry(root, textvariable='z')

label_1.grid(row=0, column=0, sticky=E)
label_2.grid(row=1, column=0, sticky=E)
label_3.grid(row=2, column=0, sticky=E)
label_4.grid(row=3, column=0, sticky=E)
label_5.grid(row=4, column=0, sticky=E)
label_6.grid(row=3, column=1, sticky=W) #direccion mosaicos
label_7.grid(row=4, column=1, sticky=W) #direccion imagen
  
entero1.grid(row=0, column=1)
entero2.grid(row=1, column=1)
entero3.grid(row=2, column=1)

boton_3=Button(root, text="Aceptar", command= mosaic )
boton_3.grid(column= 4, row=5)

if __name__ == '__main__': #verifica si el modulo ha sido importado o si es ejecutado como modulo principal (main)

    root.mainloop() #ejecuta la GUI

from mosaic.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.