Herramientas de usuario

Herramientas del sitio


fw:opencv2

¡Esta es una revisión vieja del documento!


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<uchar>(col, row) = 255;
  • Para acceder a un píxel de una imagen en RGB (y ponerlo en blanco) haremos:
image.at<cv::Vec3b>(col, row)[0] = 255;
image.at<cv::Vec3b>(col, row)[1] = 255;
image.at<cv::Vec3b>(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_<uchar> 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<uchar>(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_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
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<uchar>(valor), con esto conseguimos que valor no supere 255, no sea menor que 0 o, si el decimal, se redondee.

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.

Image Processing

  • 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).

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

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):

 

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_<uchar>::const_iterator it= image.begin<uchar>()+image.step;
cv::Mat_<uchar>::const_iterator itend= image.end<uchar>()-image.step;
cv::Mat_<uchar>::const_iterator itup= image.begin<uchar>();
cv::Mat_<uchar>::const_iterator itdown= image.begin<uchar>()+2*image.step;
result.create(image.size(), image.type());
cv::Mat_<uchar>::iterator itout= result.begin<uchar>()+result.step;
for ( ; it!= itend; ++it, ++itup, ++itdown) {
  *itout= cv::saturate_cast<uchar>(*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<float>(1,1)= 5.0;
kernel.at<float>(0,1)= -1.0;
kernel.at<float>(2,1)= -1.0;
kernel.at<float>(1,0)= -1.0;
kernel.at<float>(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 <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
 
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 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/opencv2.1309624747.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)