lunes, 31 de diciembre de 2007

Detección de tumores en mamografías en c#

Basado en la tesis doctoral de una profesora de la universidad mi salón y yo llegamos a conjuntos de algoritmos desarrollados en C# para la detección de tumores en mamografías

Todo el proyecto se dividio en cinco, lo que me toco a mi equipo es binarzación, etiquetación, deteccion de área mayor y corte de la imagen, todos los métodos se explicaran conforme vaya apareciendo. Cabe mencionar que el código esta muy desordenado debido a la falta de tiempo, y hay algunos métodos que no utilizamos, y otros que no funcionan con todas las mamografías (falta de tiempo, uds saben como buen mexicano todo lo dejamos hasta el final), por lo que las sugerencias son aceptadas:

Esta es la clase Form1 que consta de varios botones como se podrán dar cuenta en los métodos

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Proyecto_Etapa1
{
public partial class Form1 : Form
{
private int[,]arreglo;
private Metodos m;//variable del tipo métodos clase que se pondra después
private Bitmap binarizada;
private Bitmap imagen;
private Bitmap cortada;
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)//Cual mamografía vamos a estudiar
{

OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = Application.StartupPath+"\\Imagenes\\";
ofd.Title = "Seleccionar una imagen";
if (ofd.ShowDialog() == DialogResult.OK)
{
string cadena = ofd.FileName;
pictureBox1.Image = Image.FromFile(cadena);
imagen = new Bitmap(pictureBox1.Image);
m = new Metodos(imagen);
binarizada = m.Binarizar();

pictureBox1.Image = binarizada;//muestra la imagen binarizada

}

}

private void btnOriginal_Click(object sender, EventArgs e)
{//este método regresa de la binarizada a la original
int cont_x = -1, cont_y = -1;
Bitmap imagen1 = imagen;
Bitmap imagen2 = cortada;

for (int i = 1; i < imagen1.Height-1; i++)
{
cont_x++;
cont_y = -1;
for (int j = 1; j < imagen1.Width-1; j++)
{
cont_y++;
int componentes = (int)(imagen2.GetPixel(j,i).B + imagen2.GetPixel(j,i).G + imagen2.GetPixel(j, i).R)/3;
if (componentes==255)
{
imagen2.SetPixel(j,i, imagen1.GetPixel(j,i));
}

}
}
pictureBox1.Image = imagen2;
}

private void QuitaNegros_Click(object sender, EventArgs e)
{
bool lado = m.Ubicacion();
Bitmap imagen2 = binarizada;
int etiqueta = 1;
int bandera = 0;
int cont = 0;
int[,] arreglo = new int[imagen2.Height,imagen2.Width ];
for (int i = 1; i < imagen2.Height - 1; i++)//Primera barrida de derecha a izq
{
for (int j = 1; j < imagen2.Width - 1; j++)
{

}
}
}
public void Colindantes(int y, int x,bool lado)//se buscan colindantes segun el lado de la mama
{
if (lado)
{
if (arreglo[x, y - 1] != 0)
{
arreglo[x, y] = arreglo[x, y - 1];
return;
}
if (arreglo[x - 1, y] != 0)
{
arreglo[x, y] = arreglo[x - 1, y];
return;
}
if (arreglo[x - 1, y - 1] != 0)
{
arreglo[x, y] = arreglo[x - 1, y - 1];
return;
}
if (arreglo[x - 1, y + 1] != 0)
{
arreglo[x, y] = arreglo[x - 1, y + 1];
return;
}
}
else
{
if (arreglo[x, y - 1] != 0)
{
arreglo[x, y] = arreglo[x, y - 1];
return;
}
if (arreglo[x + 1, y-1] != 0)
{
arreglo[x, y] = arreglo[x + 1, y-1];
return;
}
if (arreglo[x + 1 , y] != 0)
{
arreglo[x, y] = arreglo[x - 1, y - 1];
return;
}
if (arreglo[x + 1, y + 1] != 0)
{
arreglo[x, y] = arreglo[x + 1, y + 1];
return;
}
}

}

private void Form1_Load(object sender, EventArgs e)
{

}

private void button3_Click(object sender, EventArgs e)
{//esta método corta a la imagen para trabajar con una imagen más chica
//y así hacer el programa más eficiente
cortada = m.Corte(binarizada);
pictureBox1.Image = cortada;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.InitialDirectory = Application.StartupPath.ToString();
saveFileDialog1.Filter = "Bitmap Files (*.bmp)|*.bmp|Jpeg files (*jpg)|*.jpg|All valid files (*.bmp/*.jpg)|*.bmp/*.jpg";
saveFileDialog1.FilterIndex = 1;
saveFileDialog1.RestoreDirectory = true;
if (DialogResult.OK == saveFileDialog1.ShowDialog())
{
cortada.Save(saveFileDialog1.FileName);
}
}

private void button2_Click(object sender, EventArgs e)
{

}

private void button4_Click(object sender, EventArgs e)
{
pictureBox1.Image = m.Eliminacion_pectoral(cortada);
}

private void button2_Click_1(object sender, EventArgs e)
{

pictureBox1.Image = m.etiquetar(imagen);
}
}
}


Clase Métodos:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Proyecto_Etapa1
{
public class Metodos
{


private Bitmap imagen; //Variable donde se guarda la imágen a ser procesada (origen)
private Bitmap resultado; //variable donde se guarda la imagen procesada (resultado)
private int ancho, alto, max;
private int[,] matriz; //Matriz de valores de grises para la imagen a ser proces(origen)
private int[] histo = new int[256]; //Matriz del histograma
private int aux = 0;
private float a = 0, b = 0;
private int[,] matriz_binarizada_cortada;
private int largo_imagen_cortada,alto_imagen_cortada;

//Propiedad para leer la imagen
public Bitmap Imagen
{
get
{
return imagen;
}
}

public Metodos(Bitmap IMAGEN)
{
int gris; //Variable que contiene el valor de gris de cada pixel
Color pixel; //Variable que contiene el color de cada pixel
imagen = IMAGEN; //La imágen que ingreso en el método, se guarda en la variable global
ancho = imagen.Width; //Guardo el ancho de la imagen
alto = imagen.Height; //Guardo el Alto de la imagen
matriz = new int[ancho, alto]; //Dimensiono la matriz

//For anidado que recorre todos los pixeles de la imagen
for (int y = 0; y < alto; y++)
{
for (int x = 0; x < ancho; x++)
{
pixel = imagen.GetPixel(x, y); //Guardo el color del pixel
gris = (int)(pixel.R + pixel.B + pixel.G) / 3; //Saco el valor de gris haciendo promedio entre la componente Rojo, verde y Azul
matriz[x, y] = gris; //Guardo los valores en la matriz
histo[gris] += 1; //Guardo valores de la matriz histograma
if (histo[gris] > max) max = histo[gris]; //Separo en la variable MAX el valor más alto de l histograma
}
}

}



public Bitmap Binarizar()
{

resultado = new Bitmap(ancho, alto); //Asigno la misma altura y ancho de la imagen origen
{
int cont=0;//Sacamos promedio de histograma sin incluir negros para el umbral de binarizacion
for (int i = 0; i < ancho; i++)
{
for (int j = 0; j < alto; j++)
{
if (matriz[i, j] != 0)
{
aux += matriz[i, j];
cont++;
}
}
}
aux = aux / cont;
MessageBox.Show("Promedio Histograma: " + aux.ToString());
}
//For anidado para binarizacion
for (int y = 1; y < imagen.Height - 1; y++)
{
for (int x = 1; x < imagen.Width - 1; x++)
{
int componentes = (int)(imagen.GetPixel(x, y).B + imagen.GetPixel(x, y).G + imagen.GetPixel(x, y).R) / 3;
if (componentes < aux)
{
resultado.SetPixel(x, y, Color.Black);
}
else
resultado.SetPixel(x, y, Color.White);
//Imprimo pixel por pixel la nueva imagen
}
}
return(resultado);

}

public Bitmap etiquetar(Bitmap enviada)
{//este método ayuda para detectar el área mayor (mama) para quitar el ruido de la imagen
//tenemos algunos problemas en este método no siempre etiqueta bien sugerencias aceptadas
Bitmap original = new Bitmap(enviada);
int[,] array = new int[original.Width, original.Height];
int etiqueta = 1;
for (int y = 1; y < original.Width - 1; y++)
{
for (int x = 1; x < original.Height - 1; x++)
{
float componentes = (original.GetPixel(y, x).B + original.GetPixel(y, x).G + original.GetPixel(y, x).R) / 3;
//primer if verifica que los colindantes sean puros pixeles sin etiquetar en este caso el pixel estaria rodeado de puros pixeles negros, de ser asi se incrementa el valor de la etiqueta y se etiqueta el pixel
if (componentes != 0 && array[y, x + 1] != etiqueta && array[y, x + 1] == 0 && array[y + 1, x + 1] != etiqueta && array[y + 1, x + 1] == 0 && array[y + 1, x - 1] != etiqueta && array[y + 1, x - 1] == 0 && array[y + 1, x] != etiqueta && array[y + 1, x] == 0 && array[y - 1, x] != etiqueta && array[y, x - 1] != etiqueta && array[y - 1, x - 1] != etiqueta && array[y - 1, x + 1] != etiqueta && array[y - 1, x - 1] == 0 && array[y, x - 1] == 0 && array[y - 1, x + 1] == 0 && array[y, x - 1] == 0)
{
etiqueta++;
array[y, x] = etiqueta;
original.SetPixel(y, x, Color.DeepSkyBlue);
}
//segundo if verifica que al menos uno de los pixeles colindantes al pixel que estamos leyendo tenga etiqueta de ser asi le asigna la misma etiqueta al pixel que estamos leyendo
if (componentes != 0 && array[y - 1, x] != 0 || componentes != 0 && array[y - 1, x - 1] != 0 || componentes != 0 && array[y, x - 1] != 0 || componentes != 0 && array[y - 1, x + 1] != 0)
{
array[y, x] = etiqueta;
original.SetPixel(y, x, Color.Blue);
}
}
}
for (int y = original.Width - 1; y > 1; y--)
{
for (int x = original.Height - 1; x > 1; x--)
{
float componentes = (original.GetPixel(y, x).B + original.GetPixel(y, x).G + original.GetPixel(y, x).R) / 3;
if (componentes != 0 && array[y, x] != etiqueta)
{
array[y, x] = array[y - 1, x];
original.SetPixel(y, x, Color.Aquamarine);
}


}
}

return (original);
}

public bool Ubicacion()
{//detecta que mama es (izquierda o derecha) funciona para otros métodos
bool resultado1=false;
long contizq=0, contder=0;
for (int i = 1; i <= (int) (ancho/2)-1; i++)//cortamos la imagen a la mitad y contamos los blancos
{
for (int j = 1; j < alto-1; j++)
{
int componentes = (int)(resultado.GetPixel(i,j).B + resultado.GetPixel(i,j).G + resultado.GetPixel(i,j).R)/3;
if (componentes == 255) contizq++;
}
}

for (int i = ancho / 2; i < ancho; i++)
{
for (int j = 0; j < alto; j++)
{
int componentes=(int)(resultado.GetPixel(i,j).B + resultado.GetPixel(i,j).G + resultado.GetPixel(i,j).R)/3;
if (componentes == 255) contder++;
}
}
if (contder < contizq) resultado1 = true;//La mama estará del lado izq
return (resultado1);
}

public Bitmap Eliminacion(int[,] arr)//Etiquetado y Eliminacion de blancos fuera del area mayor
{
//arr es el arreglo de etiquetas asignadas a cada pixel
int aux=0;
int etiqueta=-1;
int[] cantidad_etiquetas = new int[300];//La casilla indica la etiqueta, la info nos dice cuantas etiquetas
for (int i = 0; i < ancho; i++)
{
for (int j = 0; j < alto; j++)
{
aux = arr[i, j];
cantidad_etiquetas[aux] = cantidad_etiquetas[aux] + 1;//Sumamos cuantas etiquetas tenemos
}
}
aux = 0;
for (int i = 0; i < cantidad_etiquetas.Length; i++)
{
if (cantidad_etiquetas[i] > aux && cantidad_etiquetas[i]!=0)
{
aux = cantidad_etiquetas[i];//Cual es el cuerpo mayor
etiqueta = i;//recordar que la casilla es la etiqueta
}
}

for (int i = 1; i < ancho-1; i++)
{
for (int j = 1; j < alto - 1; j++)
{
if (arr[i, j] != 0 && arr[i, j] != etiqueta)
resultado.SetPixel(i, j, Color.Black);//Afuera de area mayor los ponemos negros
}
}
return (resultado);
}

public Bitmap Corte(Bitmap binarizada)//hacemos una imagen mucho más pequeña
{
Color[,] colores_original;
int max_x=0, max_y = 0;//Maximos y minimos del tamaño de la imagen
int min_x=1025, min_y = 1025;
int largo1,alto1=0, cont_x=-1,cont_y=-1;
int[,] arr = new int[ancho, alto];
Bitmap imagen_cortada;
for (int i = 1; i < ancho - 1; i++)//Recorremos la imagen binarizada
{ //Guardamos los pixeles binarizados en un arreglo para un mejor manejo
for (int j = 1; j < alto - 1; j++)
{
arr[i,j] = (int)(binarizada.GetPixel(i, j).B + binarizada.GetPixel(i, j).G + binarizada.GetPixel(i, j).R) / 3;
}
}
{//Corte
for (int i = 0; i < ancho; i++)
{
for (int j = 0; j < alto; j++)
{
if (arr[i, j] == 255)//sacamos max y min de las filas/columnas en blancos
{
if (i > max_x) max_x = i;
if (i < min_x) min_x = i;
if (j > max_y) max_y = j;
if (j < min_y) min_y = j;
}
}
}
largo1=(max_x - min_x);
largo_imagen_cortada = largo1;
alto1=(max_y - min_y);
alto_imagen_cortada = alto1;
imagen_cortada = new Bitmap(largo1,alto1);
colores_original = new Color[largo1, alto1];
matriz_binarizada_cortada = new int[largo1, alto1];
for (int x = min_x; x < max_x; x++)
{
cont_x++;
cont_y = -1;
for (int y =min_y; y < max_y; y++)
{
cont_y++;
colores_original[cont_x, cont_y] = imagen.GetPixel(x, y);
//la imagen es mas grande por eso recorremos de los minimos a los maximos y se los asig-
//namos al arreglo de colores del tamaño de la imagen cortada
}
}
for (int i = 0; i < largo1; i++)
{
for (int j = 0; j < alto1; j++)
{
imagen_cortada.SetPixel(i, j, colores_original[i, j]);
//asignamos los pixeles originales a la imagen cortada
matriz_binarizada_cortada[i, j] = (int)(imagen_cortada.GetPixel(i, j).B +
imagen_cortada.GetPixel(i, j).R +
imagen_cortada.GetPixel(i, j).G) / 3;
}
}
}
return (imagen_cortada);
}

public void Minimos_Cuadrados()
{//se intenta quitar el pectoral mayor por medio de reducción por medio de mínimos cuadrados
//este no funciona nada aunque la idea es buena
int cont=0, x=0, y=50;
int[] puntos_x = new int[10];
int[] puntos_y = new int[10];
bool lado = Ubicacion();
if (lado)
{
do
{
if (matriz_binarizada_cortada[x + 1, y] == 0)
{
puntos_x[cont] = x;
puntos_y[cont] = y;
x = 0;
y += 5;
cont++;
}
else x++;
}
while (cont < 10);
}
else
{
x = largo_imagen_cortada;//es igual al largo de la imagen cortada
do
{
if (matriz_binarizada_cortada[x - 1, y] == 0)
{
puntos_x[cont] = x;
puntos_y[cont] = y;
x = largo_imagen_cortada;
y += 5;
cont++;
}
else x--;
}
while (cont < 10);
}

int sum_x=0,sum_y=0,sum_x_cuadrada=0,sum_xy=0,sum_x2=0;
for (int i = 0; i < 10; i++)
{
sum_x += puntos_x[i];
sum_y -= -puntos_y[i];
sum_x_cuadrada += puntos_x[i]*puntos_x[i];
sum_xy += puntos_x[i] * -puntos_y[i];
}
sum_x2 = sum_x * sum_x;
a=((10*sum_xy)-(sum_x*sum_y))/((10*sum_x_cuadrada)-sum_x2);
b = ((sum_x_cuadrada * sum_y) - (sum_x * sum_y)) / ((10 * sum_x_cuadrada) - (sum_x2));
MessageBox.Show("a vale = " + a.ToString() + " b vale= " + b.ToString());
}

public Bitmap Eliminacion_pectoral(Bitmap cortada)
{//se eliminan los pixeles del pectoral mayor
Minimos_Cuadrados();
float operacion = 0;
for (int x = 0; x < largo_imagen_cortada; x++)
{
for (int y = 0; y < alto_imagen_cortada; y++)
{
a = a * -1;
operacion = y + (a * x);
if (operacion > b) cortada.SetPixel(x, y, Color.Black);
}
}
return (cortada);
}



}



}

Estos algoritmos fueron diseñaos enteramente por nosostros.
Aclaraciones:
1) no hay pasos atras por lo que recomiendo hacer copias de las imagenes anteriormente, y trabajar con dos variables dentro del código (una donde se guarda la original y otra donde se trabaja con la imagen)
2) en form1 necesitaran dos images box
3) el resto del codigo lo tienen los otros equipos, esta es la primera parte por lo que solo preparamos la mamografia para futura revisión hecha por los otros equipos
4) la tesis doctoral en la que nos basamos, esta hecha en matlab, exelente lenguaje para el manejo de imagenes.
5) los minimos cuadrados necesitan una muy buena revisión. Se trata de generar un recta para borrar el pectoral mayor con una fórmula que ya tenemos establecida en el código, el problema es q la fórmula trabaja con puntos sobre la recta y nosotros trabajamos en posiciones de pixeles dentro de una matriz.
6) les recuerdo que es como un "borrador" de programa, necesita los detalles para que funcione al 100 y se vea "bonito"

Sudoku en java

Este es un programa hecho en java para resolver sudokus, por medio de fuerza bruta.
Lo que hace es tomara a cada cuadrito (lugar donde va el número) como un TDA árbol con nueve hijos (1,2,3,4,5,6,7,8,9), por lo tanto tendremos 81 árboles con sus respectivos hijos.
Lo que prosigue es recorrer la fila, la columna y la matriz del cudrito quitando los números ya existenetes en la fila, columna y en la matriz, reduciendo los hijos del cuadrito. Llegaremos a un punto donde el cuadrito tendra un solo hijo, este se imprime y se vuelve a recorrer todo el algoritnmo (fuerza bruta). Cabe mencionar que el algoritmo no resuelve todos los sudokus. Veamos el código:

private boolean Resuelve() {//metodo que resuelve
String txtAlmacen="", txtLinea="";
boolean seAgrega=false;
int cont=1;
for (int i=0;i<9;i++)//recorre toda la matriz =81
for (int j=0;j<9;j++) {
raiz=new Nodo();//genera 81 variables
raiz.cuadro = arreglo[i][j];
if (raiz.cuadro == 0) {
raiz.posible = QuitaHijos(raiz,i,j);//quita hijos
for (int k=0;k<9;k++) {
if (raiz.posible[k] !=0) {//es un posible
txtLinea+=raiz.posible[k]+" ";
}
}
//si solo hay un numero en el arreglo lo guardamos directo en el arreglo
if (txtLinea.length()==2) {
seAgrega=true;
raiz.cuadro=Integer.parseInt(txtLinea.substring(0,1));//recordar # y espacio
txtLinea+="\n Asignado el valor al tablero";
jTable1.setValueAt(raiz.cuadro,i,j);
arreglo[i][j] = raiz.cuadro;
}
txtAlmacen+="Cuadro "+(cont++)+": "+txtLinea+"\n";
txtLinea="";
}
else txtAlmacen+="Cuadro "+(cont++)+": "+raiz.cuadro+" YA FIJO\n";
txtHijos.setText(txtAlmacen);
}
if(seAgrega) return true;
else return false;
}
El método resuelve basicamente checa los posibles números que van en el cuadrito.

Ahora checamos el método quita hijos:


public int[] QuitaHijos (Nodo cuadro, int fila, int columna) {
for (int h=0; h<9;h++) {
if (arreglo[fila][h] != 0) {//hay numero ¿cual?
int num = arreglo[fila][h];
cuadro.posible[num-1]=0;
}

if (arreglo[h][columna] != 0) {//hay numero ¿cual?
int num = arreglo[h][columna];
cuadro.posible[num-1]=0;
}
}
int iniFila=0, iniColum=0, finFila=0, finColum=0;//Checamos en que sub-matriz estamos
//sirve para el ciclo for posteriro
if (fila<3 && columna<3) {iniFila=0; iniColum=0; finFila=3; finColum=3;}
if (fila<3 && columna>2 && columna<6) {iniFila=0; iniColum=3; finFila=3; finColum=6;}
if (fila<3 && columna>5 && columna<9) {iniFila=0; iniColum=6; finFila=3; finColum=9;}
if (fila>2 && fila<6 && columna<3) {iniFila=3; iniColum=0; finFila=6; finColum=3;}
if (fila>2 && fila<6 && columna>2 && columna<6) {iniFila=3; iniColum=3; finFila=6; finColum=6;}
if (fila>2 && fila<6 && columna>5 && columna<9) {iniFila=3; iniColum=6; finFila=6; finColum=9;}
if (fila>5 && columna<3) {iniFila=6; iniColum=0; finFila=9; finColum=3;}
if (fila>5 && columna>2 && columna<6) {iniFila=6; iniColum=3; finFila=9; finColum=6;}
if (fila>5 && columna>5 && columna<9) {iniFila=6; iniColum=6; finFila=9; finColum=9;}
for(int i=iniFila;i < finFila;i++)
for(int j=iniColum;j < finColum;j++) {
int num= arreglo[i][j];
if(num!=0)
cuadro.posible[num-1]=0;
}
return cuadro.posible;
}


Estos son los dos método escenciales para la solución, el resto depende de ustedes

sábado, 6 de octubre de 2007

NFL

NFL



Okland Raiders v.s. New England Patriots