Mie Ago 06, 2008 5:17 pm
|
 |
Zeokat
Perlero Frecuente

|
Registrado: 22 Ago 2006
Mensajes: 117
|
|
| Detectar número de figuras |
|
|
Bien, tengo una imagen como la siguiente:
¡Ojo! en la imagen de ejemplo hay 3 figuras, pero podría haber más o menos.
Necesito separar las figuras, cada una en una imagen diferente.
Tengo una idea de cómo podría hacerlo. Quizás leyendo los píxeles según lineas verticales y en la primera aparición de un píxel "no blanco" será el principio de la primera figura.
Mientras estoy sobre la figura (al ir escaneado los píxeles en líneas verticales) siempre habrá algún píxel "no blanco" y sabré que llego al final de la primera figura con la primera línea vertical que tenga en su totalidad píxeles "blancos"... y esto tendría que hacerlo tantas veces como fuese necesario para saber dónde empieza y termina cada figura.
No sé cómo meterle mano a este problema, a ver si alguien se le ocurre una solución.
De momento sólo tengo lo siguiente:
| Perl: | #!/usr/bin/perl -w
use strict;
use GD;
my $file = $ARGV[0];
chomp($file);
GD:: Image-> trueColor(1);
my $image = newFromJpeg GD:: Image($file);
(my $width, my $height) = $image-> getBounds();
for my $i ( 0 .. $width- 1 ) {
for my $j (0 .. $height- 1) {
my $index = $image-> getPixel($i, $j);
if ($index != 16777215) { #Si el pixel no es blanco
...................... # No se como seguir...
|
Gracias de antemano. |
|
|
|

Mie Ago 06, 2008 6:23 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
| Vas muy bien... solo necesitas una bandera que indique cuándo estás en una zona blanca y cuándo en una figura. Y un contador que sume las veces que pasen de uno a otro (pero no de otro a uno). |
|

Mie Ago 06, 2008 7:15 pm
|
 |
Zeokat
Perlero Frecuente

|
Registrado: 22 Ago 2006
Mensajes: 117
|
|
|
|
|
Mmm... creo que me he explicado mal, el título da lugar a confusión.
Necesito saber cuántas figuras hay, pero al mismo tiempo necesito separar cada figura en una imagen diferente, por lo que he de conocer la coordenada $i donde empieza cada figura y la coordenada $i donde termina y luego ir copiando entre esos dos valores y pegando en una nueva imagen.
El problema está en obtener las coordenadas principio-fin de cada figura.
Y por supuesto ya que estoy saber el número de figuras.
Llevo ahí bloqueado bastante tiempo, lo de obtener esas coordenadas me ha levantado un ligero dolor de cabeza, jeje, mañana recién levantado vuelvo a indagar porque ahora estoy bloqueado. |
|

Jue Ago 07, 2008 9:06 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
Ya lo he hecho: he 'aplanado' la imagen: por cada columna veo si tienen algún píxel negro. Si lo tiene, la marco como '1' y si no, como '0'. Finalmente, solo hay que contar los tramos de '1' (que son las columnas con figura). Las coordenadas de inicio y fin de figura son fáciles de sacar.
Naturalmente, solo es válido si las figuras están 'separadas' por al menos una columna.
Seguro que hay más formas de hacerlo. |
|
Jue Ago 07, 2008 11:17 am
|
 |
Zeokat
Perlero Frecuente

|
Registrado: 22 Ago 2006
Mensajes: 117
|
|
|
|
|
Sé que lo que tengo que hacer es ir leyendo por columnas la imagen, ahí está mi problema... ¿cómo?, sé que cuando $j = $height-1, habrá finalizado la columna.
He probado cosas pero sin éxito, no consigo leer columna a columna.  |
|
Jue Ago 07, 2008 11:44 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
Pero si el doble bucle for que has escrito antes sí que lo hace...
Variando $i y $j estás mirando todos los píxeles. Como el bucle interior es el $j, getPixel() está recorriendo toda la columna, para cada fila. |
|
Jue Ago 07, 2008 12:46 pm
|
 |
Zeokat
Perlero Frecuente

|
Registrado: 22 Ago 2006
Mensajes: 117
|
|
|
|
|
Sí, sí, sí, eso ya lo tenía en cuenta y de hecho hasta lo comprobé pintando las $i y las $j.
Bueno lo único que consigo es obtener los valores de $i en los que hay píxeles "no blancos", pero sigo sin conseguir mi objetivo.
| Perl: | my @x_no;
for my $i ( 0 .. $width- 1 ) {
for my $j (0 .. $height- 1) {
my $index = $image-> getPixel($i, $j);
if ($index != 16777215 && $i != $x_no[$ #x_no]) {
push (@x_no, $i);
}
}
}
#Comprobacion
foreach my $elemento(@x_no) {
print "$elemento\n";
} |
|
|

Jue Ago 07, 2008 2:02 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
Necesitas meter 'más información' dentro del bucle.
Esta es una posible solución, aunque no es muy sencilla.
- Actualización: Programa eliminado porque tenía errores. Buscar siguiente versión más abajo -
La salida es
| Código: |
explorer@casa:~/Documents/Desarrollo> ./kk.pl ejemploai5.jpg
000000111111111111110000000000000000011111111111111100000000000000011111111111111000000000
000000000011111111112222222222333333333344444444445555555555666666666677777777778888888888
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
Hay 3 figuras
Posición inicial: 6
Posición inicial: 37
Posición inicial: 67
Posición final: 19
Posición final: 51
Posición final: 80 |
Actualización: Expresiones regulares más sencillas.
Actualización: Se descubrió que había un fallo en el caso de que existiese una figura en la última columna. La solución fue añadir un '0' al final y simplificar aún más la segunda regex.
Ultima edición por explorer el Vie Ago 08, 2008 11:11 am, editado 4 veces |
|

Jue Ago 07, 2008 3:06 pm
|
 |
Zeokat
Perlero Frecuente

|
Registrado: 22 Ago 2006
Mensajes: 117
|
|
|
|
|
Madre mía, explorer, ahora entiendo porqué no daba con la solución. En este código hay cosas nuevas para mi.
Voy a analizarlo línea a línea con calma para entenderlo al 100%.
Gracias de nuevo, explorer... o quizás San explorer, te tendré que hacer un monumento cuando termine la carrera
Saludos. |
|
Jue Ago 07, 2008 3:20 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
| Esa solo es una de las múltiples formas de solucionarlo... tu vas muy bien con tu propia solución. Hay muchas más... |
|

Jue Ago 07, 2008 7:09 pm
|
 |
Zeokat
Perlero Frecuente

|
Registrado: 22 Ago 2006
Mensajes: 117
|
|
|
|
|
Conseguí hacer lo siguiente...
| Perl: | my @x_no = (9); #Le doy valor 9 inicial, porq sino me lanza un warning undef, no se si hay otra forma de solucionarlo
for my $i ( 0 .. $width- 1 ) {
for my $j (0 .. $height- 1) {
my $index = $image-> getPixel($i, $j);
if ($index != 16777215 && $i != $x_no[$ #x_no]) {
push (@x_no, $i);
}
}
}
shift(@x_no); #quito el elemento q era basura
my @coordenadas;
push(@coordenadas, $x_no[0]); #pongo el principio de la primera figura
for my $i (0 .. $ #x_no) {
if (defined($x_no[$i+ 1]) && $x_no[$i]+ 1 < $x_no[$i+ 1]) { #Comparando diferencias entre las coordenadas, si se "alejan" 1 o mas esque hay una linea blanca por el medio
push(@coordenadas, $x_no[$i], $x_no[$i+ 1]);
}
}
push(@coordenadas, $x_no[$ #x_no]); #pongo el final del ultimo caracter
#Compruebo.
foreach my $elemento (@coordenadas) {
print "$elemento\n";
} |
Bien tengo el array @coordenadas con la coordenada principio/fin de cada figura.
Ahora tendría que manejar los elementos del array de dos en dos (principio_carácter-fin_carácter), para crear nuevas imágenes en las qué pintar cada figura de forma individual. A ver si lo soluciono... |
|

Vie Ago 08, 2008 11:09 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
Hay unos errores en mi programa, y muy graves.
1.- la función trueColor() solo sirve para indicar que vamos a crear la imagen usando componentes de color, y no un sistema de paleta de colores. Pero en este caso no estamos creando una imagen, sino que la estamos leyendo. Así que esta función no nos sirve.
2.- la función getPixel() no devuelve el color (en sus componentes rojo, verde y azul), sino el índice dentro de la paleta de colores de a qué color pertenece ese pixel. Hay que usar la función rgb() para conocer sus componentes.
Analizando la imagen, resulta que las figuras (obviando los bordes) se componen del color número 0, que corresponde, en la paleta, a un nivel de rojo de 4, 2 de verde y 4 de azul (sería el color #040204).
Entonces, no vamos a usar la paleta de colores, sino que tenemos que analizar las componentes de color de cada píxel. Y consideraremos, en este caso, que los píxeles de las figuras serán aquellos que tengan componentes inferiores o iguales, numéricamente, a 4.
Entonces, el programa queda así:
| Perl: | #!/usr/bin/perl
use strict;
use warnings;
use GD;
use constant LIMITE_COLOR => 0x04;
my $fichero_imagen = $ARGV[0] or die "Uso: $0 <imagen a procesar>\n";
my $gd_imagen = GD:: Image-> new($fichero_imagen);
my ($ancho, $alto) = $gd_imagen-> getBounds();
print "Dimensiones: $ancho x $alto\n";
## Leemos la imagen, aplanándola, a una lista, representando cada una de las columnas.
## Un '1' es que sí había píxeles negros (figura)
## Un '0' es que no había
my $columnas;
## Para todas las columnas
for my $i ( 0 .. $ancho - 1 ) {
my $hay_pixeles_de_figura; # Hay o no hay
## Para todas las filas de esa columna
for my $j (0 .. $alto - 1) {
my $color_pixel_paleta = $gd_imagen-> getPixel($i, $j);
my ($color_pixel_rojo, $color_pixel_verde, $color_pixel_azul) = $gd_imagen-> rgb($color_pixel_paleta);
#my $color_pixel = uc sprintf "%02x%02x%02x", $color_pixel_rojo, $color_pixel_verde, $color_pixel_azul;
#print ">$i;$j: $color_pixel_paleta: ($color_pixel_rojo, $color_pixel_verde, $color_pixel_azul) $color_pixel\n";
if ( $color_pixel_rojo <= LIMITE_COLOR
and $color_pixel_verde <= LIMITE_COLOR
and $color_pixel_azul <= LIMITE_COLOR
) {
$hay_pixeles_de_figura = 1; # ponemos la bandera a 1
last; # no necesitamos mirar más
}
}
## Guardamos el resultado de esa columna, como un dígito
$columnas .= ($hay_pixeles_de_figura) ? 1 : 0;
}
print "$columnas\n";
$columnas .= 0; # Para ayudar a la segunda regex, en caso de
# que exista una figura en la última columna
## Ayudas visuales
for my $x ( 0 .. length($columnas) - 1) {
print int $x++ / 10;
}
print "\n";
for my $x ( 0 .. length($columnas) - 1) {
print $x++ % 10;
}
print "\n";
## Ahora averiguamos cuántas figuras hay
my $numero_figuras = () = $columnas =~ / 1+/g; # Buscamos cuántos bloques de '1' hay
print "Hay $numero_figuras figuras\n";
## Y ahora hay que saber en qué posiciones empiezan y terminan
if ($numero_figuras) {
## Lo que hacemos es buscar la combinación '01' para saber el comienzo
while ( $columnas =~ m/ (^| 0)1/g ) {
print "Posición inicial: ";
print pos($columnas)- 1;
print "\n";
}
## y la combinación '10' para saber el final de cada figura
while ( $columnas =~ m/ 10/g ) {
print "Posición final: ";
print pos($columnas)- 2;
print "\n";
}
}
__END__ | La salida es la misma que antes.
El porqué funcionaba antes es porque, por pura coincidencia, el color que obteníamos con getPixel() era el 0 (número de color 0 dentro de la paleta de colores) y ese valor se comparaba con lo que creíamos que eran los componentes de color de las figuras (NEGRO => 0x000000). Como numéricamente son iguales, pues entonces obteníamos la salida correcta. Pero era pura casualidad. No estaba asegurado que funcionara de la misma manera con otras imágenes.
Como ejemplo relacionado con tu código (que también está mal), estás mirando si el valor de getPixel() coincide con 0xFFFFFF. Bueno, pues resulta que la imagen del ejemplo, los píxeles de color blanco, en realidad, no son blancos, sino que tienen de valor 0xFCFEFC, correspondiente al color 34 de la paleta de colores, siendo ese número (34) el valor que te está devolviendo getPixel().
El ejercicio debería indicar si debemos mirar las componentes de color o la paleta de colores. Y qué color (o qué componentes) son las que definen a las figuras. Como mínimo, indicar la diferencia entre figura y fondo. |
|

Sab Ago 09, 2008 6:23 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4142
Ubicación: Valladolid, España
|
|
|
|
|
Esta es otra solución, parecida a la que intentas tu. Se trata de ir recordando en dónde nos encontramos en cada momento.
| Perl: | #!/usr/bin/perl
use GD;
use strict;
use warnings;
use diagnostics;
## Inicialización
my $fichero_imagen = $ARGV[0] or die "Uso: $0 <imagen a procesar>\n";
my $gd_imagen = GD:: Image-> new($fichero_imagen);
my ($ancho, $alto) = $gd_imagen-> getBounds();
print "Dimensiones: $ancho x $alto\n";
## Contadores e indicadores
my $numero_figuras;
my $estamos_en_figura;
my $hay_pixeles_de_figura;
## Proceso
$estamos_en_figura = 0;
for my $i (0 .. $ancho- 1) {
$hay_pixeles_de_figura = 0;
for my $j (0 .. $alto - 1) {
if ($gd_imagen-> getPixel($i, $j) == 0) { # Si el pixel es el negro
$hay_pixeles_de_figura++;
}
}
if ($hay_pixeles_de_figura) {
if (! $estamos_en_figura) {
$estamos_en_figura = 1;
print "Inicio: $i\n";
}
}
else {
if ($estamos_en_figura) {
$estamos_en_figura = 0;
print "Final : ", $i- 1, "\n";
$numero_figuras++;
}
}
}
if ($estamos_en_figura) {
print "Final : ", $ancho- 1, "\n";
$numero_figuras++;
}
print "Hay $numero_figuras figuras\n";
__END__ | La salida es:
| Código: |
Dimensiones: 90 x 25
Inicio: 6
Final : 19
Inicio: 37
Final : 51
Inicio: 67
Final : 80
Hay 3 figuras |
Notar que estamos suponiendo que las figuras se componen de píxeles del color número 0 de la paleta de colores. |
|

Powered by phpBB © 2001, 2005 phpBB Group
|