1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
|
.. TUTORIAL:Introduction to the surfarray module
.. include:: ../../reST/common.txt
*************************************************
Tutoriales de Pygame - Introducción a Surfarray
*************************************************
.. currentmodule:: surfarray
Introducción a Surfarray
========================
.. rst-class:: docinfo
:Autor: Pete Shinners
:Contacto: pete@shinners.org
:Traducción al español: Estefanía Pivaral Serrano
Introducción
------------
Este tutorial intentará presentar tanto Numpy como el módulo de surfarray
de pygame a los usuarios. Para principiantes, el código que utiliza surfarray
puede ser bastante intimidante. Pero en realidad, hay sólo unos pocos conceptos
que entender y estarás listo para empezar. Con el uso del módulo de surfarray
es posible realizar operaciones a nivel de píxeles desde el código Python
sencillo. El rendimiento puede llegar a ser bastante cercano al nivel de hacer
el código en C.
Puede que solo desees ir directamente a la sección *"Examples"* para tener
una idea de lo que es posible con este módulo, y luego comenzar desde el
principio aquí para ir avanzando.
Ahora bien, no voy a engañarte para que pienses que todo va a ser muy sencillo.
Lograr efectos avanzados modificando los valores de píxeles puede ser complicado.
Solo dominar NumPy requiere aprendizaje. En este tutorial me centraré en lo
básico y utilizaré muchos ejemplos en un intento de sembrar las semillas de la
sabiduría. Después de haber terminado el tutorial, deberías tener una comprensión
básica de cómo funciona el surfarray.
NumPy
-----
Si no tenés instalado el paquete NumPy de python,
necesitarás hacerlo. Podés descargar el paquete dede la página de
descargas de NumPy en
`NumPy Downloads Page <http://www.scipy.org/scipylib/download.html>`_
Para asegurarte que Numpy esté funcionando correctamente,
deberías obtener algo como esto desde prompt (inteprete) interactivo de Python.::
>>> from numpy import * #importar numeric
>>> a = array((1,2,3,4,5)) #crear un array
>>> a #mostrar array
array([1, 2, 3, 4, 5])
>>> a[2] #index al array
3
>>> a*2 #nuevo array con valores dobles
array([ 2, 4, 6, 8, 10])
Como se puede ver, el módulo NumPy nos proporciona un nuevo tipo de data, el *array*.
Este objeto mantiene un array de tamaño fijo, y todos los valores que contiene en su
interior son del mismo tipo. Los arrays (matrices) también pueden ser multidimensionales,
que es como las usaremos con imágenes.
Hay un poco más de información, pero es suficiente para empezar.
Si mirás al último comando de arriba, verás que las operaciones matemáticas en
los array de NumPy se aplican para todos los valores del array. Esto se llama
"element-wise operations" (operaciones elemento a elemento). Estos arrays
también pueden dividirse en listas normales. La sintaxis de la división es la
misma que se usa en objetos Python estándar.
*(así que estudia si es necesario)*.
Aquí hay algunos ejemplos más de arrays que funcionan. ::
>>> len(a) #obtener el tamaño del array
5
>>> a[2:] #elementos a partir del 2
array([3, 4, 5])
>>> a[:-2] #todos excepto los últimos 2
array([1, 2, 3])
>>> a[2:] + a[:-2] #agregar el primero y último
array([4, 6, 8])
>>> array((1,2,3)) + array((3,4)) #agregar arrays de tamaños incorrectos
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (3,) (2,)
Obtenemos un error con el último comando, porque intentamos sumar dos arrays
que tienen tamaños diferentes. Para que dos arrays operen entre sí, incluyendo
operaciones comparaciones y asignaciones, deben tener las mismas dismensiones.
Es muy importante saber que los nuevos arrays creados a partir de cortar el
original hacen referencia a los mismos valores. Por lo tanto, cambiar los valores
en una porción de la división también cambia los valores originales. Es importante
cómo se hace esto. ::
>>> a #mostrar nuestro array inicial
array([1, 2, 3, 4, 5])
>>> aa = a[1:3] #dividir al medio 2 elementos
>>> aa #mostrar la división
array([2, 3])
>>> aa[1] = 13 #cambiar el valor en la división
>>> a #mostrar cambio en el original
array([ 1, 2, 13, 4, 5])
>>> aaa = array(a) #copiar el array
>>> aaa #mostrar copia
array([ 1, 2, 13, 4, 5])
>>> aaa[1:4] = 0 #configurar los valores medios a 0
>>> aaa #mostrar copia
array([1, 0, 0, 0, 5])
>>> a #mostrar nuevamente el original
array([ 1, 2, 13, 4, 5])
Ahora vamos a ver pequeños arrays con dos dimensiones.
No te preocupes demasiado, comenzar es lo mismo que tener una tupla de dos dimensiones
*(una tupla dentro de otra tupla)*.
Empecemos con los arrays de dos dimensiones. ::
>>> row1 = (1,2,3) #crear una tupla de valores
>>> row2 = (3,4,5) #otra tupla
>>> (row1,row2) #mostrar como una tupla de dos dimensiones
((1, 2, 3), (3, 4, 5))
>>> b = array((row1, row2)) #crear un array en 2D
>>> b #mostrar el array
array([[1, 2, 3],
[3, 4, 5]])
>>> array(((1,2),(3,4),(5,6))) #mostrar el nuevo array en 2D
array([[1, 2],
[3, 4],
[5, 6]])
Ahora, con estos arrays bidimensionales *(de ahora en más "2D")* podemos
indexar valores específicos y hacer cortes ambas dimensiones. Simplemente
usando una coma para separar los índices, nos permite buscar/cortar
en múltiple dimensiones. Simplemente usando "``:``" como un índex
*(o no proporcionando suficiente índices)* nos devuelve todos los valores
en esa dimensión. Veamos cómo funciona esto. ::
>>> b #mostrar nuestro array desde arriba
array([[1, 2, 3],
[3, 4, 5]])
>>> b[0,1] #indexar un único valor
2
>>> b[1,:] #dividir la segunda fila
array([3, 4, 5])
>>> b[1] #dividir la segunda fila (igual que arriba)
array([3, 4, 5])
>>> b[:,2] #dividir la última columna
array([3, 5])
>>> b[:,:2] #dividir en un array de 2x2
array([[1, 2],
[3, 4]])
De acuerdo, mantente conmigo acá, esto es lo más díficil que puede ponerse.
Al usar NumPy hay una característica más para la división. La división de arrays
también permite especificar un *incremento de divsión*. La sintaxis para una
división con incremento es ``start_index : end_index : increment``. ::
>>> c = arange(10) #como el rango, pero crea un array
>>> c #muestra el array
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> c[1:6:2] #divide valores impares desde el 1 al 6
array([1, 3, 5])
>>> c[4::4] #divide cada 4to valor, empezando por el 4
array([4, 8])
>>> c[8:1:-1] #divide 1 al 8, de atrás para adelante /// invertido
array([8, 7, 6, 5, 4, 3, 2])
Bien, eso es todo. Hay suficiente información acá para que puedas empezar
a usar Numpy con el módulo surfarray. Ciertamente hay mucho más en
NumPy, pero esto es solo una introducción. Además, ¿queremos pasar a cosas
divertidas, no?
Importar Surfarray
------------------
Para usar el módulo surfarray necesitamos importarlo. Dado que ambos, tanto
surfarray y NumPy, son componentes opcionales para pygame es bueno asegurarse
de que se importen correctamente antes de usarlos. En estos ejemplos voy a
importar NumPy en una variable llamada *N*. Esto permitirá saber qué funciones
estoy usando son del paquete de NumPy.
*(y es mucho más corto que escribir NumPy antes de cada función)* ::
probá:
import numpy as N
import pygame.surfarray as surfarray
except ImportError:
raise ImportError, "NumPy and Surfarray are required."
Introducción a Surfarray
------------------------
Hay dos tipos principales de funciones en surfarray. Un conjunto de funciones
para crear un array que es una copia de los datos de píxeles de la superficie
(surface). Las otras funciones crean una copia referenciada de los datos de
píxeles del array, de modo que los cambios en el array afectan directamente a
la surface original. Hay otras funciones que permiten acceder a cualquier valor
alfa por pixel, como arrays junto con algunas otras funciones útiles.
Veremos estas otras funciones más adelante.
Al trabajar con estos arrays de surface, existen dos formas de representar
los valores de píxeles. En primar lugar, pueden representarse como enteros
mapeados. Este tipo de array es un array simple en 2D con un solo entero que
representa el valor de color mapeado de la superficie. Este tipo de array es
últil para mover partes de una imagen al rededor de la pantalla.
El otro tipo de array utiliza tres valores RGB para representar el color de
cada píxel. Este tipo de array hace que sea extremadamente sencillo realizar
efectos que cambian el color de cada píxel. Este tipo de array es también un
poco más complicado de manejar, ya que es esencialmente un array numérico 3D.
Aún así, una vez que ajustas tu mente en el modo adecuado, no es mucho más
difícil que usar un array 2D normal.
El módulo NumPy utiliza los tipos de números naturales de la máquina para
representar los valores de los datos, por lo que un array de NumPy puede consistir
de enteros de 8-bits, 16-bits y 32-bits.
*(los array también pueden usar otro tipos como flotantes y dobles, pero para la
manipulación de imágenes principalmente necesitamos preocuparnos por los tipos
de enteros)*.
Debido a esta limitación de tamaños de los enteros, debes tener un poco más de cuidado
para asegurarte de que el tipo de arrays que hacen referencia a los datos de píxeles se
pueda mapear correctamente con un tipo adecuado de datos. Las funciones que crean estos
arrays a partir de las superficies son:
.. function:: pixels2d(surface)
:noindex:
Crea una matriz 2D *(valores de píxeles enteros)* que hace referencia a los datos
originales de la superficie.
Esto funcionará para todos los formatos de surface excepto el de 24-bit.
.. function:: array2d(surface)
:noindex:
Crea un array 2D *(valores de píxeles enteros)* que es copiada desde cualquier
tipo de superficie.
.. function:: pixels3d(surface)
:noindex:
Crea un array 3D *(valores de píxeles RGB)* que hacen referencia a los datos originales
de la superficie.
Esto solo funcionará en superficies de 24-bit y 32-bit que tengan el formato RGB o BGR.
.. function:: array3d(surface)
:noindex:
Crea un array 3D *(valores de píxeles RGB)* que se copia desde cualquier tipo
de surface.
Aquí hay una pequeña tabla que podría ilustrar mejor qué tipos de funciones
se deben usar en cada surface. Como se puede observar, ambas funciones
de array funcionarán con cualquier tipo de surface.
.. csv-table::
:class: matrix
:header: , "32-bit", "24-bit", "16-bit", "8-bit(c-map)"
:widths: 15, 15, 15, 15, 15
:stub-columns: 1
"pixel2d", "yes", , "yes", "yes"
"array2d", "yes", "yes", "yes", "yes"
"pixel3d", "yes", "yes", ,
"array3d", "yes", "yes", "yes", "yes"
Ejemplos
--------
Con esta información, estamos preparados para comenzar a probar cosas con los
arrays de surface. A continuación encontrarán pequeñas demostraciones que
crean un array de NumPy y los muestran en pygame. Estas diferentes pruebas
se encuentran en el ejemplo arraydemo.py. Hay una función simple llamada
*surfdemo_show* que muestra un array en la pantalla.
.. container:: examples
.. container:: example
.. image:: ../../reST/tut/surfarray_allblack.png
:alt: allblack
::
allblack = N.zeros((128, 128))
surfdemo_show(allblack, 'allblack')
Nuestro primer ejemplo crea un array completamente negro. Siempre
que se necesite crear una nueva matriz numérica de un tamaño específico,
es mejor usar la función ``zeros``. Aquí creamos un array 2D de todos
ceros y lo mostramos.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_striped.png
:alt: striped
::
striped = N.zeros((128, 128, 3))
striped[:] = (255, 0, 0)
striped[:,::3] = (0, 255, 255)
surfdemo_show(striped, 'striped')
Aquí estamos tratando con un array 3D. Empezamos creando una imagen
completamente roja. Luego cortamos cada tercera fila y le asignamos a un
color azul/verde. Como pueden ver, podemos tratar los arrays 3D casi
exactamente de la misma manera que los arrays 2D, solo asegúrense de
asignarles 3 valores en lugar de un único entero mapeado.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_rgbarray.png
:alt: rgbarray
::
imgsurface = pygame.image.load('surfarray.png')
rgbarray = surfarray.array3d(imgsurface)
surfdemo_show(rgbarray, 'rgbarray')
Aquí cargamos una imagen con el módulo de imagen, luego lo convertimos
en un array 3D de elementos de color RGB enteros. Una copia RGB
de una surface siempre tiene los colores dispuestos como a[r,c,0] para
el componente rojo, a[r,c,1] para el componente verde, y a[r,c,2] para
el azul. Esto se puede usar sin importar cómo se configuren los píxeles
del surface original, a diferencia de un array 2D que es una copia de
los píxeles de la surface :meth:`mapped <pygame.Surface.map_rgb>` (raw).
Usaremos esta imagen en el resto de los ejemplos.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_flipped.png
:alt: flipped
::
flipped = rgbarray[:,::-1]
surfdemo_show(flipped, 'flipped')
Aquí volteamos la imagen verticalmente. Todo lo que necesitamos para esto
es tomar el array de la imagen original y cortarlo usando un incremento
negativo.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_scaledown.png
:alt: scaledown
::
scaledown = rgbarray[::2,::2]
surfdemo_show(scaledown, 'scaledown')
Basado en el último ejemplo, reducir una imagen escalar es bastante lógico.
Simplemente cortamos todos los píxeles usando un incremento de 2 vertical
y horizontalmente.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_scaleup.png
:alt: scaleup
::
shape = rgbarray.shape
scaleup = N.zeros((shape[0]*2, shape[1]*2, shape[2]))
scaleup[::2,::2,:] = rgbarray
scaleup[1::2,::2,:] = rgbarray
scaleup[:,1::2] = scaleup[:,::2]
surfdemo_show(scaleup, 'scaleup')
Aumentar la escala de la imagen requiere un poco más de trabajo, pero es
similar al escalado previo hacia abajo, lo hacemos todo con cortes. Primero,
creamos un array que tiene el doble del tamaño de nuestro original. Primero
copiamos el array original en cada otro píxel del nuevo array. Luego lo
hacemos de nuevo para cada otro píxel, haciendo las columnas impares. En
este punto, tenemos la imagen escalada correctamente en sentido horizontal,
pero las otras filas son negras, por lo que simplemente debemos copiar cada
fila a la que está debajo. Entonces tenemos una imagen duplicada en tamaño.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_redimg.png
:alt: redimg
::
redimg = N.array(rgbarray)
redimg[:,:,1:] = 0
surfdemo_show(redimg, 'redimg')
Ahora estamos usando arrays 3D para cambiar los colores.
Acá establecemos todos los valores en verde y azul en cero.
Esto nos deja solo con el canal rojo.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_soften.png
:alt: soften
::
factor = N.array((8,), N.int32)
soften = N.array(rgbarray, N.int32)
soften[1:,:] += rgbarray[:-1,:] * factor
soften[:-1,:] += rgbarray[1:,:] * factor
soften[:,1:] += rgbarray[:,:-1] * factor
soften[:,:-1] += rgbarray[:,1:] * factor
soften //= 33
surfdemo_show(soften, 'soften')
Aquí realizamos un filtro de convulción 3x3 que suavizará nuestra
imagen. Parece que hay muchos pasos aquí, pero lo que estamos haciendo
es desplazar la imagen 1 píxel en cada dirección y sumarlos todos juntos
(con algunas multiplicaciones por ponderación). Luego se promedian todos
los valores. No es Gaussiano, pero es rápido. Un punto con los arrays
NumPy, la precisión de las operaciones aritméticas está determinada por
el array con el tipo de datos más grande. Entonces, si el factor no se
declarara como un array de 1 elemento de tipo numpy.int32, las
multiplicaciones se realizarían utilizando numpy.int8, el entero de
8 bits de cada elemento rgbarray. Esto causará una truncación de
valores. El array de suavizado también debe declararse con un tamaño
de entero más grande que rgbarray para evitar la truncación.
.. container:: break
..
.. container:: example
.. image:: ../../reST/tut/surfarray_xfade.png
:alt: xfade
::
src = N.array(rgbarray)
dest = N.zeros(rgbarray.shape)
dest[:] = 20, 50, 100
diff = (dest - src) * 0.50
xfade = src + diff.astype(N.uint)
surfdemo_show(xfade, 'xfade')
Por último, estamos realizando una transición gradual entre la imagen original y
una imagen de color azul sólido. No es emocionante, pero la imagen de destino
podría ser cualquier cosa, y cambiar el multiplicador 0.50 permitirá elegir
cualquier paso en una transición lineal entre dos imágenes.
.. container:: break
..
Con suerte, a estas alturas estás empezando a ver cómo surfarray puede ser
utilizado para realizar efectos especiales y transformaciones que sólo son
posibles a nivel de píxeles. Como mínimo, se puede utilizar surfarray para
realizar muchas operaciones del tipo Surface.set_at() y Surface.set_at()
rápidamente. Pero no creas que esto ha terminado, todavía queda mucho
por aprender.
Bloqueo de Superficie (Surface)
-------------------------------
Al igual que el resto de pygame, surfarray bloqueará cualquier Surface que
necesite para acceder a los datos de píxeles. Sin embargo, hay un elemento
más a tener en cuenta; al crear los array de *pixeles*, la surface
original quedará bloqueada durante la vida útil de ese array de píxeles.
Es importante recordarlo. Asegurate de *"eliminar"* el array de píxeles o
de dejarlo fuera del alcance *(es decir, cuando la funcion vuelve, etc.)*.
También hay que tener en cuenta que realmente no querés hacer muchos
*(si es que alguno)* accesos directos a píxeles en la surface del hardware
*(HWSURFACE)*. Esto se debe a que los datos de la surface se encuentra en
la tarjeta gráfica, y transferir cambios de píxeles a través del bus
PCI/AGP no es rápido.
Transparencia
-------------
El módulo surfarray tiene varios métodos para acceder a los valores alpha/colorclave
de una Surface. Ninguna de las funciones alpha se ve afectada por la transparencia
general de una Surface, solo por los vaores de los píxeles. Aquí está la lista de
esas funciones.
.. function:: pixels_alpha(surface)
:noindex:
Crea un array 2D *(valores enteros de píxeles)* que hace referencia a
los datos alpha de la surface original.
Esto solo funcionará en imágenes de 32-bit con un componente alfa de
8-bit.
.. function:: array_alpha(surface)
:noindex:
Crea un array 2D *(valores enteros de píxeles)* que se copia desde
cualquier tipo de surface.
Si la surface no tiene valores alfa,
el array tendrá valores completamten opacos *(255)*.
.. function:: array_colorkey(surface)
:noindex:
Crea un array 2D *(valores enteros de píxeles)* que está establecida
como transparente *(0)* donde el color de ese píxel coincide con el
color clave de la Surface.
Otras Funciones de Surfarray
----------------------------
Solo hay algunas otras funciones disponibles en surfarray. Podés obtener una lista
mejor con mayor documentación en :mod:`surfarray reference page <pygame.surfarray>`.
Sin embargo, hay una función muy útil.
.. function:: surfarray.blit_array(surface, array)
:noindex:
Esto transferirá cualquier tipo de array de surface 2D o 3D a una
Surface con las mismas dimensiones.
Este blit de surfarray generalmente será más rápido que asignar un
array a la de pixeles referenciado.
Sin embargo, no debería ser tan rápido como el blitting normal de
surface, ya que esos están muy optimizados.
NumPy más Avanzado
------------------
Hay un par más de cosas que deberías saber sobre los arrays Numpy. Cuando se
trata de arrays muy grandes, como los que son de 640x480, hay algunas cosas
adicionales sobre las que debes tener cuidado. Principalmente, mientras que
usar los operadores como + y * en los arrays los hace fáciles de usar, también
es muy costoso en arrays grandes. Estos operadores deben hacer nuevas copias
temporales del array, que luego generalmente se copian en otro array. Esto
puede requerir mucho tiempo. Afortunadamente, todos los operadores de Numpy
vienen con funciones especiales que pueden realizar la operación *"in place*"
(en su lugar). Por ejemplo, en lugar de usar ``screen[:] = screen + brightmap``
podrías querer usar ``add(screen, brightmap, screen)`` que es más rápido.
De todos modos, debes leer la documentación UFunc de Numpy para obtener más
información sobre esto. Es importante cuando se trata de los arrays.
Otra cosa a tener en cuenta al trabajar con arrays NumPy es el tipo de datos
del array. Algunos de los arrays (especialmente el tipo de píxeles mapeado)
a menudo devuelven arrays con un valor sin signo en 8-bits. Estos arrays se
desbordarán fácilmente si no tienes cuidado. NumPy usará la misma coerción
que se encuentra en los programas en C, por lo que mezclar una operación con
números de 8 bits y 32 bits dará como resultado números de 32 bits. Puedes
convertir el tipo de datos del array, pero definitivamente debes ser consciente
de qué tipos de arrays tienes, si NumPy se encuentra en una situación en la que
se arruinaría la precisión, lanzará una excepción.
Por último, debes tenér en cuenta que al asignar valores en los arrays 3D,
estos deben estar entre 0 y 255, de lo contrario se producirá alguna
truncación indefinida.
Graduación
----------
Bueno, ahí está. Mi breve introducción a NumPy y surfarray.
Espero que ahora veas lo que es posible, y aunque nunca los uses por
ti mismo, no tengas miedo cuando veas código que los use. Echale un
vistazo al ejemplo vgrade para ver más sobre los arrays numéricos. También,
hay algunos demos *"flame"* que usan surfarray para crear un efectp de
fuego en tiempo real.
Lo mejor que podés hacer es probar alguna cosas por tu cuenta. Ve despacio
al principio y ve construyendo poco a poco, ya he visto algunas cosas geniales
con surfarray, como gradientes radiales y más.
Buena suerte.
|