Module intersection
[hide private]
[frames] | no frames]

Source Code for Module intersection

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  #    intersection.py 
  5  #        
  6  #    Copyright 2010 Victor Ramirez <virako.9@gmail.com> 
  7  #        
  8  #    This program is free software: you can redistribute it and/or modify 
  9  #    it under the terms of the GNU General Public License as published by 
 10  #    the Free Software Foundation, either version 3 of the License, or 
 11  #    (at your option) any later version. 
 12  # 
 13  #    This program is distributed in the hope that it will be useful, 
 14  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  #    GNU General Public License for more details. 
 17  # 
 18  #    You should have received a copy of the GNU General Public License 
 19  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 20   
 21   
 22  from opencv.highgui import * 
 23  from opencv.cv import * 
 24  from opencv import * 
 25  #from math import * 
 26  from tablero import Tablero 
 27  from check_stone import check_stone 
 28  from cte import * 
 29  from notation import notation 
 30   
 31   
 32   
33 -def contador(lista, num, indice = 0):
34 cont = 0 35 for l in lista: 36 if l[indice] == num: 37 cont += 1 38 return cont
39 40 41
42 -class Intersection:
43 """ Contiene todos los datos de las intersecciones de un tablero y las 44 funciones necesarias para encontrarlas. 45 Parámetros necesarios: 46 *image: la imagen del tablero que queremos tratar. 47 *template: el template que vamos a pasarle a la imagen. 48 *size: el tamaño del tablero para saber cuantas intersecciones buscar. 49 """ 50
51 - def __init__(self, image, template = "images/tplPoint.png", size = SIZE):
52 """Inicializamos la imágen, el template y algunas variables. 53 @param image: imagen donde se buscarán las intersecciones del tablero o 54 cadena con el directorio donde se encuentra la imagen. 55 @type image: L{IplImage} or C{str} 56 @keyword template: imagen de la plantilla que buscaremos en la imagen. 57 @type template: C{str} 58 @keyword size: el tamaño del tablero 59 @type size: C{int} 60 @return: None 61 @rtype: None 62 """ 63 64 if type(image) == str: 65 self.img = cvLoadImageM(image, CV_LOAD_IMAGE_GRAYSCALE) 66 else: 67 self.img =cvCreateImage((image.width,image.height), IPL_DEPTH_8U, 1) 68 cvCvtColor(image, self.img, CV_BGR2GRAY) 69 70 self.tpl = cvLoadImageM(template, CV_LOAD_IMAGE_GRAYSCALE) 71 self.size = size 72 self.intersections = [] 73 self.tpl_size = [self.tpl.height, self.tpl.width] # tamaño del template 74 self.tablero = Tablero(self.size) 75 self.num_jugada = 1 76 self.color = BLACK # color de comienzo 77 self.player_pass = 0
78
79 - def detect_intersections(self, threshold=0.7):
80 """ Función recursiva que detecta las intersecciones del tablero usando 81 un template y un valor umbral, el cual iremos variando para 82 hasta obtener el resultado deseado. 83 @keyword threshold: Umbral para usar la búsqueda del template. 84 @type threshold: float. 85 """ 86 i = self.intersections 87 88 #Creamos imágenes auxiliares para utilizar filtros (Canny y Smooth) 89 img_aux = cvCreateImage((self.img.width, self.img.height), \ 90 self.img.depth, self.img.nChannels) 91 img_aux_2 = cvCreateImage((self.img.width, self.img.height), \ 92 self.img.depth, self.img.nChannels) 93 94 tpl_aux = cvCreateImage((self.tpl.width, self.tpl.height), \ 95 self.tpl.depth, self.tpl.nChannels) 96 tpl_aux_2 = cvCreateImage((self.tpl.width, self.tpl.height), \ 97 self.tpl.depth, self.tpl.nChannels) 98 99 # funcion Canny para detectar bordes de la imagen y Smooth para suavizar 100 cvCanny(self.img, img_aux_2, 50,55,3) 101 cvSmooth(img_aux_2, img_aux, 3) 102 cvCanny(self.tpl, tpl_aux_2, 50,55,3) 103 cvSmooth(tpl_aux_2, tpl_aux, 3) 104 105 # creamos una nueva imagen para comparar el resultado 106 w = self.img.width - self.tpl.width + 1 107 h = self.img.height - self.tpl.height + 1 108 res = cvCreateImage( cvSize(w,h), IPL_DEPTH_32F, 1) 109 110 # realizamos una plantilla coincidente 111 cvMatchTemplate(img_aux, tpl_aux, res, CV_TM_SQDIFF_NORMED) 112 113 # ahora buscamos los objetos coincidentes, variamos threshold al gusto 114 for y in range(res.height - 1) : 115 for x in range(res.width - 1): 116 # obtenemos un elemento 117 s = cvGet2D(res, y, x) 118 if s[0] < threshold: 119 i.append(((x + x + self.tpl.width)/2, \ 120 (y + y + self.tpl.height)/2)) 121 122 # Eliminamos intersecciones inválidas comparando los puntos encontrados 123 repeated = [] 124 for u in range(len(i)-1): 125 for v in range(len(i)-1): 126 # Comprobamos que la distancia entre intersecciones sea mayor 127 # que la mitad de un cuadrado, para eliminar las repetidas 128 if (u < v and abs(i[u][0] - i[v][0]) < self.tpl.width/2 \ 129 and abs(i[u][1] - i[v][1]) < self.tpl.height/2 \ 130 and repeated.count(i[v]) != 1): 131 repeated.append(i[v]) 132 133 for d in repeated: 134 i.remove(d) 135 136 if self.size**2 >= len(i) >= (self.size**2)*(2/3.0): 137 print "el numero de intersecciones es ", len(i) 138 self.i = i 139 return i 140 elif len(i) > self.size**2: 141 threshold = threshold - 0.05 142 elif len(i) < (self.size**2)*(2/3.0): 143 threshold = threshold + 0.05 144 145 if threshold >= 1.0 or threshold < 0.3: 146 print "Inténtalo de nuevo, haz otra foto" 147 mal = True 148 return -1 149 150 return self.detect_intersections(threshold)
151 152
153 - def paint_save_intersection(self):
154 """Función que pinta y guarda las intersecciones para chequeos.""" 155 for p in self.i: 156 cvCircle(self.img, cvPoint(p[0],p[1]), 5, cvScalar(255,0,0,0), 1, 8, 0) 157 #try: cvSaveImage("images/intersecciones.png", self.img) 158 #except: print "Error al guardar la imagen de diferencia. " # para chequeo 159 return self.img
160 161
162 - def media(self): # TODO buscar los errores
163 """ Hallamos la media de todas las filas y columnas. """ 164 165 # medias de las columnas 166 x_min = [self.img.width for x in xrange(self.size)] 167 x_min.append(0) 168 x_media = [0 for x in xrange(self.size + 1)] 169 verticales = [[] for x in xrange(self.size)] 170 171 # medias de las filas 172 y_min = [self.img.height for x in xrange(self.size)] 173 y_min.append(0) 174 y_media = [0 for x in xrange(self.size + 1)] 175 horizontales = [[] for x in xrange(self.size)] 176 177 for tam in range(self.size): 178 # hallamos la x minima y la y minima 179 for i in self.intersections: 180 if i[0] < x_min[tam] and i[0] > x_min[tam-1]: # x 181 x_min[tam] = i[0] 182 if i[1] < y_min[tam] and i[1] > y_min[tam-1]: # y 183 y_min[tam] = i[1] 184 185 # 186 for i in self.intersections: 187 if (i[0] >= x_min[tam] and i[0] < x_min[tam] + self.tpl.width/2.0): # x 188 verticales[tam].append(i) 189 if x_media[tam] < i[0]: 190 x_media[tam] = i[0] 191 192 if (i[1] >= y_min[tam] and \ 193 i[1] < y_min[tam] + self.tpl.height/2.0): # y 194 horizontales[tam].append(i) 195 if y_media[tam] < i[1]: 196 y_media[tam] = i[1] 197 x_min[tam] = x_media[tam] 198 y_min[tam] = y_media[tam] 199 200 # Guardamos las intersecciones en el tablero 201 for x in range(len(x_media)-1): 202 for y in range(len(y_media)-1): 203 self.tablero.matriz[x][y][0] = x_media[x] 204 self.tablero.matriz[x][y][1] = y_media[y] 205 # Pintamos 206 cvCircle(self.img, cvPoint(x_media[x], y_media[y]), 2, \ 207 cvScalar(255,0,0,0), 1, 8, 0) 208 return self.img 209 210
211 - def search_intersection(self, points):
212 """Busca el punto donde se encuentra la piedra para añadirlo al archivo 213 sgf. 214 @param points: intersecciones donde puede encontrarse la piedra. 215 @type points: C{list(tuples*)} 216 @return: Tupla que contiene: 217 Cadena con la intersección donde se encuentra la piedra. 218 Color de la piedra. 219 Boleano para saber si hemos terminado la partida. 220 @rtype: C{tuple(str, int, bool} # Los candidatos los hemos dividido en dos, los que estaban en 221 # intersecciones libres, y los que estaban en ocupadas. 222 """ 223 224 candidates = [] 225 self.tablero.get_square() # Obtenemos el tamaño de los cuadrados 226 sgf_stone = "" 227 ocupadas = [] 228 libres = [] 229 230 # De la lista de circunferencias que pasamos por parámetro a la función 231 # buscamos los candidatos que se encuentren en intersecciones correctas 232 if len(points) != 0: 233 for point in points: 234 candidate = [-1, -1] # inicializamos a -1 para comprobar fallos 235 for diagonal in range(19): 236 point_diagonal = self.tablero.matriz[diagonal][diagonal] 237 if abs(point_diagonal[0]-point[0]) < self.tablero.square[0]/2: 238 candidate[0] = diagonal 239 if abs(point_diagonal[1]-point[1]) < self.tablero.square[1]/2: 240 candidate[1] = diagonal 241 242 if (candidate[0] != -1 and candidate[1] != -1): 243 candidates.append((candidate[0], candidate[1])) 244 else: 245 print "Punto", point, "eliminado" 246 print "Hay ", len(candidates), "piedras candidatas" 247 248 # Una vez obtenidos los candidatos, los recorremos para comprobar 249 # que no son piedras que ya estaban puestas, o si son piedras que ya 250 # estaban puestas, comprobar si han sido capturadas 251 # Los candidatos los dividimos en dos, los que están en 252 # intersecciones libres, y los que están en intersecciones ocupadas. 253 for cand in candidates: 254 ocupado = (self.tablero.matriz[cand[0]][cand[1]][2].values()[-1] != SPACE) 255 if ocupado: 256 ocupadas.append(cand) 257 print "OCUPADA", cand[0]+1, cand[1]+1 258 else: 259 libres.append(cand) 260 print "LIBRE", cand[0]+1, cand[1]+1 261 262 # Si solo nos hemos quedado con una piedra libre, la añadimos 263 if len(libres) == 1: 264 self.tablero.matriz[libres[0][0]][libres[0][1]][2].update({self.num_jugada:self.color}) 265 sgf_stone = notation((libres[0][0], libres[0][1])) 266 # en el caso de habernos quedado sin ninguna, pasamos (aunque puede 267 # ser que en vez de pasar no se haya detectado la piedra) 268 elif len(libres) == 0: 269 self.player_pass += 1 270 print "El jugador ha pasado o la piedra no se ha encontrado. \ 271 No existian piedras libres" 272 # en el caso de obtener más de una piedra en huecos libres pueden 273 # suceder dos cosas: 274 # * que se nos haya olvidado pulsar el reloj, y haya dos piedras 275 # * que hayamos encontrado piedras erróneas 276 else: 277 if self.player_pass == 1: # TODO si ocurre esto, modificar el sgf 278 print "La piedra anterior no se había pasado" 279 else: 280 print "Demasiados huecos libres: ", len(libres) 281 exit(0) 282 283 # Los candidatos que se encuentran en posiciones ocupadas 284 # tenemos que recorrerlos todos y comprobar que si las piedras 285 # han sido capturarlas para eliminarlas del tablero o no 286 for o in ocupadas: 287 if check_stone(self.tablero, o, self.color): 288 print "Piedra capturada", o 289 self.tablero.matriz[cand[0]][cand[1]][2].update({self.num_jugada:SPACE}) 290 else: 291 print "Hemos comprobado que era Falsa la piedra que podia ser capturada ^^ ", o 292 293 else: # No existian cincunferencias donde buscar 294 self.player_pass += 1 295 print "El jugador ha pasado o la piedra no se ha encontrado.\ 296 No existian cincunferencias donde buscar." 297 298 # Comprobamos cuantas veces ha pasado el jugador para saber si ha 299 # terminado la partida. 300 if self.player_pass == 2: 301 r_tupla = (sgf_stone, self.color, True) 302 else: 303 r_tupla = (sgf_stone, self.color, False) 304 305 self.num_jugada += 1 306 # intercambia entre negra y blanca 307 if self.color == BLACK: self.color = WHITE 308 elif self.color == WHITE: self.color = BLACK 309 310 return r_tupla
311