Para mas información:
https://twitter.com/scipyconar
Luego de haber instalado todas las bibliotecas correspondientes para nuestra Kinect .. muchos tutoriales ya hay dando vueltas [1] [2][3], Nos encontramos con PyOpenNI y PyGame para demostrar lo sencillo que es interactuar con sensores 3D en menos de 30′
Veremos rápidamente el código por bloques …
Primero que nada tenemos las clases básicas de nuestro juego, la clase Ball, que será el elemento de nuestro simple juego, BallManager que será la encargada de actualizar e instanciar todas las pelotitas deseadas, una clase para la Kinect y otra para el manejo del juego en general (Clase Game).
La clase Ball, se encarga de darle imagen, posición, velocidad y ángulo a nuestra pelota, dandole funciones como move y bounce para calcular hacia donde y cómo debe moverse.
class Ball(pygame.sprite.Sprite):
"""Ball Class for set image, speed and angle """
def __init__(self, xy, speed, angle):
pygame.sprite.Sprite.__init__(self)
self.img_load('images/sphere.png')
self.rect.centerx, self.rect.centery = xy
self.speed = speed
self.angle = angle
def move(self):
self.rect.centerx += np.sin(self.angle) * self.speed
self.rect.centery -= np.cos(self.angle) * self.speed
def bounce(self):
if self.rect.centerx > SCREEN_WIDTH - self.rect.width:
self.rect.centerx = 2*(SCREEN_WIDTH - self.rect.width) - self.rect.centerx
self.angle = -self.angle*2
elif self.rect.centerx < self.rect.width:
self.rect.centerx = 2*self.rect.width - self.rect.centerx
self.angle = -self.angle*2
if self.rect.centery > SCREEN_HEIGHT - self.rect.height:
self.rect.centery = 2*(SCREEN_HEIGHT - self.rect.height) - self.rect.centery
self.angle = np.pi - self.angle*2
elif self.rect.centery < self.rect.height:
self.rect.centery = 2*self.rect.width - self.rect.centery
self.angle = np.pi - self.angle*2
def img_load(self, filename):
self.image = pygame.image.load(filename)
self.image = pygame.transform.scale(self.image, (60,60))
self.rect = self.image.get_rect()
La clase ballManager se encarga de instanciar y actualizar la posición de todas las pelotas que tenemos en el juego ..
class BallManager(object):
""" Create and update state of balls"""
def __init__(self, numballs = 30, balls = []):
self.blist = balls
self.multiple_balls(numballs)
def update(self):
for ball in self.blist:
ball.move()
ball.bounce()
def add_ball(self, xy, speed, angle):
self.blist.append(Ball(xy, speed, angle))
def multiple_balls(self, numballs):
for i in range(numballs):
self.add_ball((np.random.randint(0, SCREEN_WIDTH),
np.random.randint(0, SCREEN_HEIGHT)),
np.random.randint(4, 20),
np.random.uniform(0, np.pi*2))
En la clase Kinect tenemos la creación de contextos y generadores para indicar cuales son los datos que queremos tomar de nuestro sensor, gracias a openni ya contamos con generadores de gestos, por lo que podemos avisar de antemano cual es el gesto que esperamos reconocer (en nuestro caso un saludo agitando la mano).
class Kinect(object):
"""Manage context and generator of the kinect"""
def __init__(self, game):
self.context = openni.Context()
self.context.init()
self.depth_generator = openni.DepthGenerator()
self.depth_generator.create(self.context)
self.depth_generator.set_resolution_preset(openni.RES_VGA)
self.depth_generator.fps = 30
self.image_generator = openni.ImageGenerator()
self.image_generator.create(self.context)
self.image_generator.set_resolution_preset(openni.RES_VGA)
self.gesture_generator = openni.GestureGenerator()
self.gesture_generator.create(self.context)
self.gesture_generator.add_gesture('Wave')
self.hands_generator = openni.HandsGenerator()
self.hands_generator.create(self.context)
self.gesture_generator.register_gesture_cb(self.gesture_detected, self.gesture_progress)
self.hands_generator.register_hand_cb(self.create, self.update, self.destroy)
self.game = game
def gesture_detected(self, src, gesture, id, end_point):
print "Detected gesture:", gesture
self.hands_generator.start_tracking(end_point)
def gesture_progress(self, src, gesture, point, progress):
pass
def destroy(self, src, id, time):
pass
def create(self, src, id, pos, time):
pass
def update(self, src, id, pos, time):
if pos != None:
for ball in self.game.ball_manager.blist:
new_rect = pygame.Rect(int(ball.rect.x), int(ball.rect.y), 60, 60)
kinect_rect = pygame.Rect(self.game.size[0]/2 - int(pos[0]), self.game.size[1]/2 - int(pos[1]), 40, 40)
print "kinect %s and ball %s" %(kinect_rect.center, new_rect.center)
if new_rect.colliderect(kinect_rect):
print "wiii %d" %(len(self.game.ball_manager.blist))
ball.kill()
pygame.draw.circle(self.game.display_surf, (0, 128, 255), (self.game.size[0]/2 - int(pos[0]), self.game.size[1]/2 - int(pos[1])), 10)
def capture_rgb(self):
rgb_frame = np.fromstring(self.image_generator.get_raw_image_map_bgr(), dtype=np.uint8).reshape(SCREEN_HEIGHT, SCREEN_WIDTH, 3)
image = cv.fromarray(rgb_frame)
cv.Flip(image, None, 1)
cv.CvtColor(cv.fromarray(rgb_frame), image, cv.CV_BGR2RGB)
self.game.frame = pygame.image.frombuffer(image.tostring(), cv.GetSize(image), 'RGB')
Vale decir que no es nada limpio en cuestiones objetosas que el update de colisiones se haga dentro de la clase Kinect, pero recuerden que la idea es mostrar que en 20 min de codeo sale andando un jueguito básico.
Y como último nuestra clase Game, que se encarga de las acciones básicas de un main de juego, el inicio, renderizado, el loop general .. etc.
class Game(object):
"""Define screen, sprites and states of the game"""
def __init__(self):
self.timer = pygame.time.Clock()
self.sprites = pygame.sprite.RenderUpdates()
self._running = True
self.display_surf = None
self.background = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
self.background.fill((0,0,0))
self.size = (SCREEN_WIDTH, SCREEN_HEIGHT)
self.frame = None
self.my_kinect = Kinect(self)
self.ball_manager = BallManager(30)
for ball in self.ball_manager.blist:
self.sprites.add(ball)
def on_init(self):
pygame.init()
self.display_surf = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
self.display_surf.blit(self.background, (0,0))
self._running = True
self.my_kinect.context.start_generating_all()
def on_event(self, event):
if event.type == pygame.QUIT:
self._running = False
def on_loop(self):
self.my_kinect.context.wait_any_update_all()
self.my_kinect.capture_rgb()
self.ball_manager.update()
def on_render(self):
self.sprites.clear(self.display_surf, self.background)
self.display_surf.blit(self.frame, (0,0))
for sprite in self.sprites:
sprite.update()
dirty = self.sprites.draw(self.display_surf)
pygame.display.update(dirty)
pygame.display.flip()
def on_cleanup(self):
pygame.quit()
def on_execute(self):
self.on_init()
while( self._running ):
for event in pygame.event.get():
self.on_event(event)
self.on_loop()
self.on_render()
self.on_cleanup()
El código completo se puede encontrar en https://github.com/celiacintas/KinectStuff/blob/master/game_colegios.py
Y un video super acelerado … porque digamos que como juego no es el más entretenido
La conferencia está orientada a la divulgación de herramientas y/o proyectos realizados con Python en el ámbito científico, académico e industrial, y sus principales objetivos incluyen:
Dar oportunidad a la divulgación del lenguaje Python en la comunidad científica argentina.
Dar a conocer y/o revisar herramientas disponibles, orientadas a problemas científicos así como a otros de naturaleza más puntual.
Mostrar bibliotecas científicas desarrolladas por la comunidad mundial.
Combinar la educación, la ingeniería y la ciencia a través de Python.
Generar un marco apropiado para concretar encuentros, foros de discusión y proyectos educativos y de investigación y desarrollo relacionados con Python.
En este caso vamos a meternos en PyOpenCL con la excusa de los mapas logísticos .
ACA tienen el código fuente de un excelente tutorial, en el cual me base.
El mapa logístico puede expresarse matematicamente como:
Habiendo dicho esto veremos el código para nuestro kernel (.cl):
/*kernel for implementing the Verhulst model.
Fractal and Chaos - Chapter 5 - Iterative Feedback Processes and Chaos. */
__kernel void verhulst(global float* alpha, global float* xd, global float* output)
{
float temp;
int idx = get_local_id(0)+get_local_size(0)*get_group_id(0);
temp = xd[0];
int i;
for(i=0;i<=idx;i++)
{
temp = alpha[0]*temp*(1-temp);
}
output[idx] = temp;
}
Y nuestro programa encargado de crear el contexto, crear buffers, etc.
# http://documen.tician.de/pyopencl/
# Ian Johnson.
#
#
# Celita changes buffers, data and parameters
# for implementation of the logistic map
#
import pyopencl as cl
import numpy
import pylab
import argparse
class CL:
def __init__(self):
self.ctx = cl.create_some_context()
self.queue = cl.CommandQueue(self.ctx)
def loadProgram(self, filename):
#read in the OpenCL source file as a string
f = open(filename, 'r')
fstr = "".join(f.readlines())
print fstr
#create the program
self.program = cl.Program(self.ctx, fstr).build()
def logisticMap(self, alpha=0.9, xd=0.2):
mf = cl.mem_flags
#initialize client side (CPU) arrays
self.alpha = numpy.array([alpha], dtype=numpy.float32)
self.xd = numpy.array([xd], dtype=numpy.float32)
self.output = numpy.zeros(50, numpy.float32)
#create OpenCL buffers
self.alpha_buf = cl.Buffer(self.ctx, mf.READ_ONLY | mf.COPY_HOST_PTR,
hostbuf=self.alpha)
self.xd_buf = cl.Buffer(self.ctx, mf.READ_ONLY | mf.COPY_HOST_PTR,
hostbuf=self.xd)
self.dest_buf = cl.Buffer(self.ctx, mf.WRITE_ONLY, self.output.nbytes)
def execute(self):
self.program.verhulst(self.queue, self.alpha.shape, None,
self.alpha_buf, self.xd_buf, self.dest_buf)
cl.enqueue_copy(self.queue, self.output, self.dest_buf)
print "alpha: ", self.alpha
print "xn: ", self.xd
print "results: ", self.output
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=
'Logistic Map with control parameter')
parser.add_argument("--alpha", dest="alpha", default=0.9,
help='This option is used to set the alpha')
args = parser.parse_args()
alphaIn = args.alpha
myLogisticMap = CL()
myLogisticMap.loadProgram("verhulst.cl")
myLogisticMap.logisticMap(alpha=alphaIn)
myLogisticMap.execute()
pylab.plot(myLogisticMap.output, 'ro-')
pylab.ylim(0, 1)
pylab.text(40, 0.2, r'$\alpha = %f$' % (myLogisticMap.alpha))
pylab.title("Successive Iterations of the logistic Map")
pylab.show()
Como se ve en el codigo se puede pasar el por parametros o dejar que se tome el por defecto …
Y como resultado veríamos algo asi …
Para mayor seguridad de código actualizado verlo ACA
🙂
En este caso haremos una breve presentación de las funcionalidades que nos otorga PyEEG para el trabajo con electroencefalogramas, fusionando con matplotlib para mostrar los resultados.
PyEGG tiene muchas funcionalidades:
En nuestro caso hicimos uso de DFA , en pocas palabras trata de cuantificar la autosemejanza de series temporales (En el link DFA esta genialmente explicado).
Los datos con los que trabajamos fueron tomados de Universidad de Bonn.
Ahora vamos al código:
**Aclaración, solo por cuestiones de ploteo se le agrego a la función dfa que devuelva otros valores mas …
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#The data analyzed in our study is available on this page.
# http://epileptologie-bonn.de/cms/front_content.php?idcat=193&lang=3
#The sampling rate of the data was 173.61 Hz. For a more
#detailed description of the data please refer to the manuscript
#Please note, however, that the time series have the spectral
#bandwith of the aquisition system, which is 0.5 Hz to 85 Hz.
from pyeeg import dfa
import pylab
from scipy import log10
from numpy import arange, loadtxt, random
from random import randrange
def randomize(data):
randomData = []
for i in range(len(data)-1):
randomData.append(data[randrange(0, len(data)-1)])
return randomData
if __name__ == "__main__":
originalData = loadtxt('F/F003.txt').T
randomData = randomize(originalData)
#get the dfa for both set of values
alphaO, forplotO, forplotNO = dfa(originalData)
alphaR, forplotR, forplotNR = dfa(randomData)
#plot the results
fig = pylab.figure()
ax = fig.add_subplot(3, 1, 1)
ori = ax.plot(log10(forplotNO), forplotO, 'b-', label = "Original Data")
ran = ax.plot(log10(forplotNR), forplotR, 'g-', label = "Random Data")
pylab.title("DFA")
pylab.legend([ori[0], ran[0]], ['Original Data','Random Data'])
pylab.text(2,3, r'$\alpha Original = %f $'%(alphaO), multialignment = 'center')
pylab.text(2,2, r'$\alpha Random = %f $'%(alphaR), multialignment = 'center')
#plot the original and randomize data
bx = fig.add_subplot(3, 1, 2)
bx.plot(randomData, 'g-')
pylab.title("Random Data")
cx = fig.add_subplot(3, 1, 3)
cx.plot(originalData, 'b-')
pylab.title("Original Data")
pylab.show()
Para observar la variación del \alpha lo que se hizo fue tomar la muestra original y transformarla en ruido blanco (el cual debe dar simil a 0.5)
Por si alguien le interesa ACA van a encontrar el pyeeg que retorna las funciones que se encuentran ploteadas, un setup.py para los herejes que lo necesiten corriendo en W$.
🙂
Esta vez haremos el descabellado intento de plotear una galaxia espiral morfológicamente mas o menos correcta, para esto haremos uso/abuso de Python seguido de sus secuaces Scipy y Mayavi. Utilizando hasta el cansancio funciones lambda, mapeos y filtros entre otros yuyos.
Para seguir adelante tenemos que refrescar que es un Automata Celular y para que servían las Coordenadas Polares .
El código se puede ver ACA al ser un poco mas extenso que los anteriores dejo el link a github.
Y se vería algo asi …
Reutilizando el código anterior con mínimas modificaciones tenemos como resultado el Conjunto de Cantor (http://es.wikipedia.org/wiki/Conjunto_de_Cantor).
Solo colocaré la parte modifcada del código anterior, no se olviden de importar mayavi!
def generar(self, nivel, cursor, distancia):
if nivel == 0:
a = (cursor.x, cursor.x, cursor.x)
b = (cursor.x + distancia*np.cos(cursor.ang),
cursor.y + distancia*np.sin(cursor.ang))
mlab.points3d(a, a, a, colormap="copper", scale_factor=.25)
cursor.x = b[0]
cursor.y = b[1]
else:
print "nivel = ", nivel
for i in self.gramatica[self.inicial]:
if i == 'A':
self.generar(nivel-1, cursor, distancia/3.0)
elif i == 'B':
cursor.x += 3*distancia
if __name__ == "__main__":
miSistema = SistemaL(gramatica = {'A':"ABA", 'B':"BBB"},
inicial = 'A',distancia = 1, nivel = 5)
miSistema.iniciar()
miSistema.generar(miSistema.nivel, miSistema.cursor, miSistema.distancia)
print "termine con todos los niveles"
mlab.show()
Y así quedaría …
btw: puede haber quedado algo residual del anterior problema 🙂
Esta vez venimos con código para generar la famosa Curva de Koch http://es.wikipedia.org/wiki/Copo_de_nieve_de_Koch , este es solo la curva..no el copo ... pero el sistema es el mismo. Como verán el código es genérico porq tiene toda la intención de usarse con otras gramáticas de Lin. .. pero para eso falta un poco de pulido. Los puntos clave pasan por la recursión, el cursor y los niveles :). Espero que les sea útil.#! /usr/bin/python2 # -*- coding: utf-8 -*- import numpy as np import pylab as pl class Cursor: def __init__(self,x,y, angulo): self.x = x self.y = y self.ang = angulo class SistemaL: def __init__(self,gramatica, inicial, distancia, nivel): self.gramatica = gramatica self.inicial = inicial self.distancia = distancia self.nivel = nivel def iniciar(self): self.cursor = Cursor(0,0,0) pl.plot([self.cursor.x, self.cursor.x+ self.distancia], [self.cursor.y, self.cursor.y]) def generar(self, nivel, cursor, distancia): if nivel == 0: a = (cursor.x, cursor.y) b = (cursor.x + distancia*np.cos(cursor.ang), cursor.y + distancia*np.sin(cursor.ang)) print a, "-->", b pl.plot([a[0],b[0]],[a[1],b[1]]) cursor.x = b[0] cursor.y = b[1] else: print "nivel = ", nivel for i in self.gramatica[self.inicial]: if i == 'F': self.generar(nivel-1, cursor, distancia/3) elif i == '+': cursor.ang = cursor.ang - np.pi/3 elif i == '-': cursor.ang = cursor.ang + np.pi/3 if __name__ == "__main__": miSistema = SistemaL(gramatica = {'F':"F-F++F-F"},inicial = 'F', distancia = 10000, nivel = 5) miSistema.iniciar() miSistema.generar(miSistema.nivel, miSistema.cursor, miSistema.distancia) print "termine con todos los niveles" pl.show()Yyyy unas imágenes de como sería nuestro resultado ...
Usando la biblioteca http://code.google.com/p/python-perceptron/ con unos minimos cambios que se pueden encontrar en mi repositorio de gitorious .. quizas solo eran necesarios para mi puntualmente … y como esta la biblioteca les sirve perfectamente …
En esta ocasión levantamos los datos de un entrenamiento en particular dado por un experto en el tema en una planilla de calculos …
los cargamos en nuestra red .. la entrenamos y la colocamos a clasificar … y para darnos una mejor idea implementamos con matplotlib un bonito gráfico
#! /usr/bin/python2
# -*- coding: utf-8 -*-
import perceptron
import xlrd
import numpy as np
from pylab import *
#---##---## ---##---##---##---##---##---##---##---##---##---##---##---
def cargarPatronEntrenamiento(path):
book = xlrd.open_workbook(path)
sheet = book.sheet_by_index(0)
patron = {}
entrada = []
for i in range(1,sheet.nrows):
entrada = []
for j in range(1,sheet.ncols):
entrada.append([sheet.cell_value(i,j)])
patron[i-1]= (np.array(entrada))
return patron
#---##---## ---##---##---##---##---##---##---##---##---##---##---##---
def entrenar(network, patron):
"""Con la matriz de entrenamiento proporcionada entrenar para modificar la
matriz de pesos"""
for j in range(50): #TODO ...
for i in patron.iterkeys():
network.learn(patron[i], i)
#---##---## ---##---##---##---##---##---##---##---##---##---##---##---
if __name__ == "__main__":
per = perceptron.Perceptron(35,23)
patron = cargarPatronEntrenamiento("../data/entrenamiento.xls")
entrenar(per, patron)
forPlot = []
for i in patron.iterkeys():
output = per.classify(patron[i])
forPlot.append(float(output[1]))
ylim(0.20,1.0)
xticks( arange(0,23), ('C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8',
'C9', 'C10', 'C11', 'C12', 'C13', 'D1',
'D2', 'D3', 'D4', 'D5','D6', 'D7', 'D8',
'D9', 'D10', 'D11') )
#Estos son valores fijos dados por el experto en tema
plot(arange(0,23),[0.80,0.80,0.60,0.60,0.80,0.80,0.80,0.80,
0.60,0.60,0.6,0.60,0.80,0.80,0.80,0.80,0.80,
0.70,0.70,0.50,0.50,0.50,0.50,],'x-',
label='Confianza proporcionada por humano')
plot(arange(0,23),forPlot,'o-',label='Estimados por la red' )
y = []
for i in range(23):
y.append(0.40)
#este es el limite de confianza que suponemos ... (un poco bajo para que queden bien las estadisticas :P)
plot(arange(0,23),y,'-',label=u'Límite de confianza')
xlabel(u'Vértebras')
ylabel('Porcentaje de confianza')
title(u'Predicciones de posicionamiento de vértebras')
legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
show()
Y la salida quedaría algo asi …
A continuación veamos un ejemplo de una BN con su respectivas tablas de probabilidad…
Teniendo una idea general de la red bayesiana que queremos realizar (usemos la imagen como guía), pasemos a la implementación…
from pyAgrum import BayesNet, LabelizedVar, LazyPropagation
#Creamos nuestra red bayesiana vacia
myBN = BayesNet("Noche Calurosa")
#Cargamos los nodos
n = myBN.add(LabelizedVar('n','noche calurosa?',2))
c = myBN.add(LabelizedVar('c','cerveza?',2))
h = myBN.add(LabelizedVar('h','helado?',2))
a = myBN.add(LabelizedVar('a','llamar amigos?',2))
#LabelizedVar(nombre,comentario,cantidad de variables)
#insertamos los arcos
arcos = [(n,c),(n,h),(c,a),(h,a)]
for a in arcos:
myBN.insertArc(a)
#Ahora cargamos nuestras tablas de probabilidades.
myBN.cpt(n)[:] = [0.5,0.5]
myBN.cpt(c)[:] = [[0.5,0.5],
[0.1,0.9]]
myBN.cpt(h)[:] = [[0.8,0.2],
[0.3,0.7]]
#otra forma de cargar la tabla puede ser:
bn.cpt(a)[0,0,:] = [1,0]
bn.cpt(a)[0,1,:] = [0.05,0.95]
bn.cpt(a)[1,0,:] = [0.90,0.10]
bn.cpt(a)[1,1,:] = [0.010,0.99]
Este código respecta a la creación de nuestra red bayesiana, más adelante veremos como realizar la inferencia y trabajar con
la evidencia.