¡Esta es una revisión vieja del documento!
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));
size():std::cout << " " << img.size().width << " " << img.size().height << std::endl;
cols y rows.if (!img.data) { // imágen incorrecta
image.channels()imagen.copyTo(imagen_copia). O Mat imagen_copia = imagen.clone();.result.create(image.rows, image.cols, image.type())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.
image.at<uchar>(col, row) = 255;image.at<cv::Vec3b>(col, row)[0] = 255; image.at<cv::Vec3b>(col, row)[1] = 255; image.at<cv::Vec3b>(col, row)[2] = 255;
at, podremos usar la clase Mat_ y haremos:cv::Mat_<uchar> im2 = image; im2(50, 100) = 0;
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.
img.step.img.total().img.elemSize().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; }
result.row(0).setTo(cv::Scalar(0));. O un color rgb con: cv::Scalar(r,g,b).*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.cv::Mat mask = cv::imread(“logo.bmp”, 0)Highgui es un conjunto de funciones de ayuda a la edición de imágenes.
cv::namedWindow(“identificador”). std::waitKey(0).cv::imshow(“identificador”, imágen).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.cv::flip(imagen1, imagen_resultado, modo). Donde modo puede ser 0 (vertical), 1 (horizontal) o un número negativo (para horizontal y vertical).cv::add(image1, image2, result)cv::addWeighted(image1, 0.7, image2, 0.9, 0.0, result);cv::add(image1, cv::Scalar(k), result);cv::scaleAdd(image1, k, image2, result)cv::add(image1, image2, result, mask)cv::bitwise_and, cv::bitwise_or, cv::bitwise_xor y cv::bitwise_not.add tales como: cv::substract, cv::absdiff, cv::multiply y cv::divide.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;
mat.inv().mat.t().mat.determinant()mat.norm()v1.cross(v2)v1.dot(v2)
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);
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<cv::Mat> 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
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);
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.#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; }
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX= . $ make $ sudo make install
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.