Monografias.com > Sin categoría
Descargar Imprimir Comentar Ver trabajos relacionados

Procesamiento global en OpenCV (página 2)




Enviado por Pablo Turmero



Partes: 1, 2

Monografias.com
Y lógico entre una imagen y otra (o una constante) a nivel de bits:
void bitwise_and (Mat src1, Mat src2, Mat dest, [ Mat máscara = NULO ] );
? si máscara(x,y)?0 entonces dest(x,y):= src1(x,y) AND src2(x,y)
O lógico entre una imagen y otra (o una constante) a nivel de bits:
void bitwise_or (Mat src1, Mat src2, Mat dest, [ Mat máscara = NULO ] );
? si máscara(x,y)?0 entonces dest(x,y):= src1(x,y) OR src2(x,y)
O exclusivo entre una imagen y otra (o una constante) a nivel de bit:
void bitwise_xor (Mat src1, Mat src2, Mat dest, [ Mat máscara = NULO ] );
? si máscara(x,y)?0 entonces dest(x,y):= src1(x,y) XOR src2(x,y)
Negación lógica de una imagen, a nivel de bits:
void bitwise_not (Mat src, Mat dest, [ Mat máscara = NULO ] );
? si máscara(x,y)?0 entonces dest(x,y):= NOT src(x,y)
Ejemplo. Vale para invertir una imagen: bitwise_not(img, img);

Monografias.com
Comparación entre una imagen y un valor constante:
void inRange (Mat src, Mat lowerb, Mat upperb, Mat dst);
? dest(x,y):= (lowerb(x,y) <= src(x,y) <= upperb(x,y))
Comprueba, para cada píxel de la imagen, si su valor está entre el límite inferior (lowerb) y el superior (upperb), que pueden ser imágenes o constates (esclares).
El resultado es una imagen binaria, 8U, con 0 ó 255 (todos los bits a 1).
Si src es multicanal, comprueba todos los canales están en el rango.
Umbralización/binarización de una imagen:
double threshold (Mat src, Mat dst, double thresh, double maxval, int tipo);
Umbraliza la imagen según el método dado en tipo y el umbral es thresh.
P.ej., THRESH_BINARY para binarizar con umbral 128:threshold(A, C, 128, 255, THRESH_BINARY);
? C(x,y):= si A(x,y) > 128 entonces 255 si no 0
La umbralización se hace con un valor constante. Para un método más avanzado ver adaptiveThreshold. El umbral se calcula para cada píxel, usando una vecindad local (adaptativo).

Monografias.com
Máximo entre dos imágenes o entre imagen y un valor constante:
void max (Mat src1, Mat src2, Mat dest);
dest(x,y):= max {src1(x,y), src(x,y)}
En imágenes multicanal, calcula el máximo para cada uno de los canales.
Mínimo entre dos imágenes o entre imagen y un valor constante:
void min (Mat src1, Mat src2, Mat dest);
dest(x,y):= min {src1(x,y), src(x,y)}
Potencia, exponencial y logaritmo de los píxeles de una imagen:
void pow (Mat A, double p, Mat C); ? C(x,y):= A(x,y)p
void exp (Mat A, Mat C); ? C(x,y):= eA(x,y)
void log (Mat A, Mat C); ? C(x,y):= loge |A(x,y)|
Para evitar saturación y pérdida de información, es conveniente transformar las profundidad a reales de 32 o 64 bits.
Ejemplo. Transformación de gamma de una imagen img:
Mat im32F;
img.convertTo(im32F, CV_32F, 1.0/255.0);
pow(im32F, ui->doubleSpinBox->value(), im32F);
im32F.convertTo(img, CV_8U, 255);

Monografias.com
Multiplicar dos imágenes:
void multiply (Mat src1, Mat src2, Mat dest, [double scale=1, int tipo=-1] );
dest(x,y):= src1(x,y)*src2(x,y)*scale
El valor scale permite evitar problemas de saturación.
El valor tipo permite cambiar el tipo de datos de salida.
src1 y src2 pueden ser escalares. Y se puede usar modo in-place.
Ejemplo: multiplicar dos imágenes de 8 bits:multiply(im1, im2, resultado, 1./255);
Dividir una imagen por otra:
void divide (Mat src1, Mat src2, Mat dest, [double scale=1, int tipo=-1] );
dest(x,y):= scale*src1(x,y)/src2(x,y)
Las mismas opciones y parámetros que en la anterior función.
Tener cuidado con los problemas de saturación. Puede ser adecuado usar enteros con signo.
Ejemplo:
divide(im1, im2, resultado, 255.0);

Monografias.com
Observar el estilo de programación usando estas funciones.
Por ejemplo, queremos implementar la operación: R(x,y):= A(x,y)·(255-N(x,y))/255 + B(x,y)·N(x,y)/255
void Combina (Mat A, Mat B, Mat N, Mat &R);
Implementación 1.
multiply(B, N, B, 1./255);
bitwise_not(N, N);
multiply(A, N, A, 1./255);
R= A+B;
Implementación 2.
Vec3b pA, pB, pN, pR;
R.create(A.size(), A.type());
for (int y=0; y(y, x);
pB= B.at(y, x);
pN= N.at(y, x);
for (int c= 0; c<3; c++)
pR[c]= (pA[c]*(255-pN[c])+pB[c]*pN[c])/255.0;
R.at(y, x)= pR;
}
Esto es más sencillo y eficiente, porque las opera-ciones están optimizadas
Esto es menos eficiente (~2 veces más lento) y menos recomendable
Aunque no del todo correcto, porque modifica las imágenes de entrada A, B y N…

Monografias.com
Operaciones con histogramas
En OpenCV los histogramas son de tipo Mat siendo la profundidad float y de 1 canal. Por lo tanto, podemos usar las operaciones lineales (suma, resta, producto, etc.) y el acceso y modificación con at.
El número de dimensiones del histograma depende de los que queramos calcular (hist. de 1 canal, de 2 canales, etc.).
El tamaño del histograma (bins) también puede cambiar, según la resolución que queramos (desde 2 hasta 256).
Tenemos también una operación de ecualización del histograma: equalizeHist.
Otra cuestión relacionada son las tablas de transformación (look-up table, o LUT), para realizar una transformación de curva tonal arbitraria.

Monografias.com
Propiedades de un histograma:
Número de dimensiones (dims). Normalmente tendremos 1 dimensión (escala de grises), 2 dimensiones (histogramas conjuntos de dos canales) o como mucho 3 (de triplas R,B,G).
Para cada dimensión, número de celdas (histSize). Normalmente será una potencia de 2, como 256, 64, 32…
Rango de valores correspondientes a cada celda (ranges), (normalmente el hist. es uniforme, y los valores son informes).
Ejemplos.
Histograma de 1 dimensión y 4 celdas
Histograma de 2 dimensiones, con tamaños 3 y 2

Monografias.com
Calcular el histograma de una imagen:
void calcHist (Mat* images, int nimages, const int* canales, Mat mask,Mat hist, int dims, int* histSize, float** ranges,[ bool uniform= true, bool acumular= false] );
images: array de imágenes sobre las que se calcula el histograma. Normalmente será una sola imagen de 1 o 3 canales. Si hay varias, todas ellas deben tener el mismo tamaño.
nimages: número de imágenes que hay en el anterior array.
canales: array con los números de los canales sobre los que se quiere calcular el histograma. Los canales están numerados 0, 1, …
mask: máscara opcional. Si vale noArray(), no se usa. En otro caso, debe ser una imagen de 1 canal y profundidad 8U.
hist: histograma resultante, de profundidad float.
dims: número de dimensiones del histograma. Debe coincidir con el tamaño del array canales (por ejemplo, si dims=3, deben indicarse 3 canales).
histSize: tamaño (número de bins) en cada una de las dimensiones.
ranges: rango para cada dimensión. Normalmente (con histograma uniforme) será un array de arrays con valores {0, 256}.
uniform: indica si las celdas se distribuyen el rango uniformemt. (es lo normal).
acumular: permite acumular los valores entre distintas llamadas a la función.

Monografias.com
Ejemplo 1. Calcular el histograma unidimensional del nivel de gris de una imagen “a.jpg” en color. El resultado se escribe en salida debug:
Mat img= imread("a.jpg", 1);
Mat gris;
Mat hist;
cvtColor(img, gris, CV_BGR2GRAY); // Conversión a gris
int canales[1]= {0};
int bins[1]= {256};
float rango[2]= {0, 256};
const float *rangos[]= {rango};
calcHist(&gris, 1, canales, noArray(), hist, 1, bins, rangos);
for (int i= 0; i<256; i++)
qDebug("Celda %d: %g", i, hist.at(i));

Observar el acceso a las celdas del histograma con:
hist.at(posición)

Monografias.com
Ejemplo 2. Calcular el histograma bidimensional de los canales (R,G) de una imagen “a.jpg” en color, con 64×64 celdas. El resultado se pinta en una imagen:
Mat img= imread("a.jpg", 1);
Mat hist;
int canales[2]= {2, 1}; // El 2 es el canal R, y el 1 es el canal G
int bins[2]= {64, 64};
float rango[2]= {0, 256};
const float *rangos[]= {rango, rango};
calcHist(&img, 1, canales, noArray(), hist, 2, bins, rangos);

// Operaciones para pintar el histograma
Mat pinta(64, 64, CV_8UC1);
double minval, maxval;
minMaxLoc(hist, &minval, &maxval); // Para escalar el color entre blanco y negro
for (int r= 0; r<64; r++)
for (int g= 0; g<64; g++)
pinta.at(r, g)= 255-255*hist.at(r, g)/maxval;
namedWindow("Histograma R-G", 0);
imshow("Histograma R-G", pinta);

Monografias.com
Normalizar un histograma: conseguir que la suma de todas las celdas sea un valor dado (por ejemplo, que sumen 100).
Si se conoce el número de píxeles de la imagen, se puede hacer con una simple ponderación: hist*= 100.0/img.size().area();
Si no se conoce, se puede calcular la suma total de las celdas:hist*= 100.0/norm(hist, NORM_L1);
Obtener máximo y mínimo de un histograma:
void minMaxLoc (Mat h, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, Mat mask=noArray());
Dado el histograma, calcula el mínimo (minVal), el máximo (maxVal), el índice de la celda mínima (minLoc) y máxima (maxLoc).
Ver un uso en el ejemplo anterior.
También puede aplicarse esta función sobre imágenes, para buscar el píxel más claro y/o más oscuro.
Ecualizar el histograma de una imagen:
void equalizeHist (Mat src, Mat dst);
La imagen debe ser de 1 solo canal y 8U.
Otras funciones interesantes: compareHist (comparar histogramas), normalize (normalizar los niveles de gris de una imagen, usando diferentes criterios).

Monografias.com
Las tablas de transformación (look-up table, LUT) son tablas que definen funciones discretas de la forma:
f: [0…255] ? R
Esto nos permite construir cualquier curva tonal arbitraria.
En OpenCV, una LUT es una matriz de tipo Mat:
Mat lut(1, 256, CV_8UC1);
1 fila y 256 columnas. El número de canales puede ser 1 o 3.
La profundidad puede cambiar (8U, 8S, 16U, 32F, …)
Aplicar una transformación de tabla LUT:
void LUT (Mat src, Mat lut, Mat dest);
La profundidad de entrada, src, debe ser 8 bits (con o sin signo), y la de salida (en dest y en lut) puede ser cualquiera.
Si la imagen src tiene 1 canal, lut debe ser de 1 canal. Si src tiene 3 canales, lut puede ser de 1 canal (aplicar la misma transformación a todos los canales) o de 3 canales (como si fueran 3 tablas LUT, una para cada canal).

Monografias.com
Ejemplo 1. Aplicar una ecualización conjunta del histograma a una imagen “a.jpg” en color, usando calcHist y LUT:

Mat img= imread(“a.jpg", 1);
imshow("Entrada", img);
Mat gris, hist;
cvtColor(img, gris, CV_BGR2GRAY);
int canales[1]= {0}, bins[1]= {256};
float rango[2]= {0, 256};
const float *rangos[]= {rango};
calcHist(&gris, 1, canales, noArray(), hist, 1, bins, rangos);
hist*= 255.0/norm(hist, NORM_L1);
Mat lut(1, 256, CV_8UC1);
float acum= 0.0;
for (int i= 0; i<256; i++) {
lut.at(0, i)= acum;
acum+= hist.at(i);
}
Mat res;
LUT(img, lut, res);
imshow("Ecualizada", res);

Partes: 1, 2
 Página anterior Volver al principio del trabajoPágina siguiente 

Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

Categorias
Newsletter