====== OpenCV 2 ====== * [[http://opencv.willowgarage.com/wiki/|Wiki de OpenCV]] ===== Básico ===== ==== Imágenes ==== Crear una imágen: cv::Mat img; Leer imágen de un fichero: img = cv::imread("opencv.jpg"); Crear una imágen reservando el espacio (la siguiente es una en escala de grises): cv::Mat img(240, 320, CV_8U, cv::Scalar(100)); === Propiedades y funciones útiles de una imágen === * El tamaño de una imágen lo sabremos mediante ''size()'': std::cout << " " << img.size().width << " " << img.size().height << std::endl; * También podemos saber el tamaño de una imágen mediante sus propiedades ''cols'' y ''rows''. * Podemos saber si una imágen es correcta mediante... if (!img.data) { // imágen incorrecta * Para saber el número de canales de una imágen (1 si es en escala de grises o 3 si es en color): ''image.channels()'' * Copiar una imágen: ''imagen.copyTo(imagen_copia)''. O ''Mat imagen_copia = imagen.clone();''. * Para volver a asignar un tamaño a una imagen: ''result.create(image.rows, image.cols, image.type())'' ==== Acceso a los píxels ==== === Accediendo mediante número de fila\columna === OpenCV trata los píxels de una imágen como una matriz. Si la imágen es de 8 bits (nivel de grises) la matriz será de un valor entre 0 y 255, si es RGB contendrá tres valores de 0 a 255. * Para acceder a un píxel de una imagen en escala de grises (y ponerlo en blanco) haremos: ''image.at(col, row) = 255;'' * Para acceder a un píxel de una imagen en RGB (y ponerlo en blanco) haremos: image.at(col, row)[0] = 255; image.at(col, row)[1] = 255; image.at(col, row)[2] = 255; * Para acceder a los píxels de la imágen ya sabiendo desde el principio de qué modo es no es necesario usar el método ''at'', podremos usar la clase ''Mat_'' y haremos: cv::Mat_ im2 = image; im2(50, 100) = 0; === Accediendo mediante punteros === * Podemos recoger los píxels de una línea en formato array de bytes (donde cada píxel son, por ejemplo si es RGB, tres bytes): ''uchar* data = image.ptr(row);'' Una imagen puede tener //padded píxels//, estos son píxels que se agregan al final de las líneas de la matriz para que el procesador pueda recorrerla de una forma más eficiente. Si no los tuviese la imágen puede ser recorrida desde 0 hasta el número de píxels recorriendo algo así: ''uchar *data = imagen.data''. Para saber si la imagen puede ser recorrida de esta forma el método ''imagen.isContinuous()'' devolverá ''true''. * Para saber cuantos bytes hay en una fila podemos hacer: ''img.step''. * Para saber el número total de píxels haremos: ''img.total()''. * Para saber cuantos bytes ocupa un píxel haremos: ''img.elemSize()''. === Accediendo mediante iteradores === cv::Mat_::iterator it= image.begin(); cv::Mat_::iterator itend= image.end(); for (; it!= itend; ++it) { (*it)[0]= (*it)[0]/div*div + div/2; (*it)[1]= (*it)[1]/div*div + div/2; (*it)[2]= (*it)[2]/div*div + div/2; } === Otros === * Podemos asignar una fila con un solo valor, por ejemplo asignar la fila 0 el color negro: ''result.row(0).setTo(cv::Scalar(0));''. O un color rgb con: ''cv::Scalar(r,g,b)''. * Al asignar un valor a un píxel podemos utilizar ''*pixel = cv::saturate_cast(valor)'', con esto conseguimos que ''valor'' no supere 255, no sea menor que 0 o, si el decimal, se redondee. * Crear una máscara a partir de una imágen en escala de grises: ''cv::Mat mask = cv::imread("logo.bmp", 0)'' ==== Highgui y funciones de ayuda ==== //Highgui// es un conjunto de funciones de ayuda a la edición de imágenes. * **Crear una ventana**: ''cv::namedWindow("identificador")''. * Cuando creemos ventanas tendremos que decir que no se cierren automáticamente; podemos hacer esto pidiendo una tecla mediante: ''std::waitKey(0)''. * **Mostrar una imagen** sobre una ventana creada: ''cv::imshow("identificador", imágen)''. * **Guardar una imagen** ''cv::imwrite(ruta, imagen)''. Según la extensión que pongamos en la ruta de la imágen (.bmp, .jpg...) así será el formato de esta. ==== Otras clases ==== * ''cv::Vec3b'' permite definir un píxel con tres unsigned chars. ===== Image Processing ===== ==== Funciones útiles ==== * Hacer **flip** de una imagen: ''cv::flip(imagen1, imagen_resultado, modo)''. Donde modo puede ser 0 (vertical), 1 (horizontal) o un número negativo (para horizontal y vertical). === Cambiar espacio de colores === La función ''cv::ctColor'' permite cambiar el espacio de color de una imágen a otro. Se le pasa la imágen que queremos convertir, la imágen donde queremos convertirla y el tipo de conversión. \\ El tipo de conversión puede ser ''CV_BGR2Gray'' (a grises), ''CV_BGR2Lab'' (a //CIE L*a*b// que es un espacio de color donde es más fácil hacer distancias (euclídeas) entre píxels)... converted.create(image.rows,image.cols,image.type()); cv::cvtColor(image, converted, CV_BGR2Lab); ==== Histogramas ==== ===== Operadores ===== ==== Operadores entre imágenes ==== * Podemos combinar dos imágenes: ''cv::add(image1, image2, result)'' * Podemos combinar dos imágenes según pesos: ''cv::addWeighted(image1, 0.7, image2, 0.9, 0.0, result);'' * Podemos multiplicar una imagen por un escalar (k): ''cv::add(image1, cv::Scalar(k), result);'' * Podemos combinar la primera imagen con un escalar y luego sumar la segunda: ''cv::scaleAdd(image1, k, image2, result)'' * Podemos aplicar un operador según la máscara: ''cv::add(image1, image2, result, mask)'' * Podemos usar operaciones de bitwise: ''cv::bitwise_and'', ''cv::bitwise_or'', ''cv::bitwise_xor'' y ''cv::bitwise_not''. * Podemos usar otras funciones a parte del ''add'' tales como: ''cv::substract'', ''cv::absdiff'', ''cv::multiply'' y ''cv::divide''. * Existen otros operadores que únicamente se aplican a una imagen: ''cv::sqrt'', ''cv::pow'', ''cv::abs'', ''cv::cuberoot'', ''cv::exp'' y ''cv::log''. En OpenCV existe sobreescritura de operadores, podemos aplicar los operadores bitwise (''& \ ^ ~ ''), los de comparación (''< <= == != > >='')... result = 0.7 * image1 + 0.9 * image2; ==== Operadores de matrices ==== * Invertir una matriz: ''mat.inv()''. * Trasponer la matriz: ''mat.t()''. * Sacar el determinante: ''mat.determinant()'' * Encontrar el vector normal: ''mat.norm()'' * Cross-product: ''v1.cross(v2)'' * Dot-product: ''v1.dot(v2)'' ==== Especificar la región donde operar ==== === ROIs === Las ROI (//Region Of Interest//) son porciones de la imágen a partir de la cual podríamos aplicar un operador, para definirlas indicamos la posición mediante un objeto ''cv::Rect'', mediante dos ''cv::Range'' o indicando un rango de filas\columnas: cv::Mat roi1 = image(cv::Rect(385, 270, img2.cols, img2.rows)); cv::Mat roi2 = image(cv::Range(270, 270 + img2.rows), cv::Range(385, 385 + img2.cols)); cv::Mat roi3 = image.rowRange(start, end); cv::Mat roi4 = image.colRange(start, end); imgLogo.copyTo(roi1, mask); === Canales === Para aplicar un operador a un solo canal deberemos separar la imagen en sus canales (''split''), aplicar el operador sobre este y luego volver a unirlos (''merge''): std::vector planes; // crea un vector de 3 imagenes cv::split(image1,planes); // divide la imagen de 3 canales en 3 imágenes de 1 canal planes[0]+= image2; // operamos sobre uno de los canales cv::merge(planes,result); // unimos los canales ===== Filtros ===== ==== Crear un filtro ==== Un filtro con un kernel como el que sigue... | 0 | -1 | 0 | | -1 | 5 | -1 | | 0 | -1 | 0 | ... Significa que el píxel actual se multiplicará por 5, y el de arriba, el de abajo, el de la derecha y el da la izquierda por -1 y se sumarán. El código para su aplicación podría ser el siguiente: cv::Mat_::const_iterator it= image.begin()+image.step; cv::Mat_::const_iterator itend= image.end()-image.step; cv::Mat_::const_iterator itup= image.begin(); cv::Mat_::const_iterator itdown= image.begin()+2*image.step; result.create(image.size(), image.type()); cv::Mat_::iterator itout= result.begin()+result.step; for ( ; it!= itend; ++it, ++itup, ++itdown) { *itout= cv::saturate_cast(*it *5 - *(it-1)- *(it+1)- *itup - *itdown); } Aún así OpenCV permite utilizar la función ''cv::filter2D'' que aplica a una imágen un filtro definido en una matriz. Por ejemplo aplicar el anterior kernel sería: cv::Mat kernel(3,3,CV_32F,cv::Scalar(0)); kernel.at(1,1)= 5.0; kernel.at(0,1)= -1.0; kernel.at(2,1)= -1.0; kernel.at(1,0)= -1.0; kernel.at(1,2)= -1.0; cv::filter2D(image,result,image.depth(),kernel); ===== Notas ===== ==== Notas ==== * Podemos cargar una imágen ''IplImage'' (de OpenCV v.1) utilizando el constructor (algo así: ''cv::Mat img(iplimg, true)'', donde el segundo parámetro indica si se realiza una copia de la imágen. ==== Ejemplos ==== === Abrir, flip, mostrar y guardar === #include #include #include int main(int argc, char** argv) { cv::Mat img, result; img = cv::imread("opencv.jpg"); cv::flip(img, result, 1); cv::namedWindow("test"); cv::imshow("test", result); cv::waitKey(0); cv::imwrite("test.bmp", result); return 1; } ==== Instalación y uso en Linux ==== * Vamos a la [[http://opencv.willowgarage.com/wiki/|wiki de OpenCV]] y nos descargamos la última release. Descomprimimos el archivo descargado nos colocamos en la ruta y hacemos: $ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX= . $ make $ sudo make install === Uso con Eclipse === Una vez creado el proyecto necesitaremos agregar la ruta de las cabeceras a partir de ''propiedades -> C/C++ Build -> Directories'' y agregar ahí la ruta (en mi caso ''/include/opencv2''). Luego en ''Libraries'' tendremos que agregar la ruta (''/lib'') y las librarías: ''opencv_core, opencv_imgproc, opencv_highgui, opencv_ml, opencv_video, opencv_features2d, opencv_calib3d, opencv_objdetect, opencv_contrib, opencv_legacy, opencv_flann''. \\ Después haremos botón derecho sobre el proyecto y ''Build -> All''. ==== Documentos ==== * {{fw:ocv2:opencv_tutorials.pdf|Tutoriales oficiales}}.