Detección de figuras geométricas
En tutoriales anteriores aprendimos a detectar líneas y círculos en una imagen, esta vez avanzaremos un poco mas y detectaremos las figuras geométricas básicas como: triángulos, cuadrados, círculos y pentágonos, haciendo uso de la librería opencv.
Previo a la detección de figuras geométricas aprenderemos a usar las funciones opencv que nos ayudaran a conseguir lo que deseamos.
Detección de contornos de una imagen
La función findContours devuelve un conjunto de puntos que representan el contorno de una imagen, esta imagen debe ser binaria, además findContours modifica la imagen por lo que debemos tener cuidado. Esta función nos servirá de mucho para la detección y reconocimiento de figuras geométricas y de otros objetos.
Una vez tengamos los contornos podemos mostrarlos usando la función drawContours esta se encargara de unir con líneas los puntos obtenidos por la función anterior, podemos indicar un grosor de línea en pixeles o indicar –1 para rellenar toda la figura.
Antes de buscar los contornos aplicaremos la función canny para buscar los bordes de la imagen. Le pasamos como parámetros la imagen de entrada, la de salida, un umbral máximo y uno mínimo.
Mat src = imread("star.png", 1); // Mostrar la imagen original imshow("Original", src); Mat canny_output; vector<vector<Point> > contours; vector<Vec4i> hierarchy; int thresh = 100; // Detectar los bordes con un umbral min = 100 y max = 200 Canny(src, canny_output, thresh, thresh * 2); // Mostrar los bordes detectados con Canny imshow("Bordes", canny_output); // Buscar los contornos de la imagen, se almacenan en contours findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); // Mostrar la Imagen modificada por la funcion findContours imshow("Modificada", canny_output); // Dibujar los contornos encontrados Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3); for (size_t i = 0; i< contours.size(); i++) { Scalar color = CV_RGB(0, 255, 0); drawContours(drawing, contours, (int)i, color, 2, 8, hierarchy, 0, Point()); } // Mostrar la imagen final imshow("Contours", drawing);
Detección de figuras simples
Para reconocer una figura geométrica haremos uso de la función approxPolyDP la cual usa el algoritmo de Douglas-Peucker para reducir el número de puntos que se aproxima a una curva.
Si tiene tres vértices de salida sabemos que es un triangulo.
Para saber si es un rectángulo se deben cumplir los siguientes parámetros:
- La función isContourConvex debe devolver true.
- Debe tener 4 vértices.
- Los ángulos deben ser de 90 grados.
Para un hexágono el número de vértices debe ser 6 y los ángulos de 120 grados.
Para un circulo tenemos las siguientes condiciones:
- Mas de 6 vértices.
- Tener diámetro de igual dimensión en todas direcciones.
for (size_t i = 0; i < contours.size(); i++) { // reducir el nuemro de puntos usando del algoritmo de Douglas-Peucker cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true); // Si no cumple con estas condiciones es un objeto invalido if (std::fabs(cv::contourArea(contours[i])) < 100 || !cv::isContourConvex(approx)) continue; // Es un triangulo if (approx.size() == 3) { setLabel(dst, "TRI", contours[i]); } else if (approx.size() >= 4 && approx.size() <= 6) { // Obtener el numero de vertices int vtc = approx.size(); // Obtener todos los angulos (cosenos) std::vector<double> cos; for (int j = 2; j < vtc + 1; j++) cos.push_back(angle(approx[j%vtc], approx[j - 2], approx[j - 1])); //Ordenar los angulos obtenidos std::sort(cos.begin(), cos.end()); // Obtener los angulos maximos y minimos double mincos = cos.front(); double maxcos = cos.back(); //Obtener los angulos y determinar el tipo de figura segun los //angulos obtenidos y el nuemero de vertices if (vtc == 4 && mincos >= -0.1 && maxcos <= 0.3) setLabel(dst, "RECT", contours[i]); else if (vtc == 5 && mincos >= -0.34 && maxcos <= -0.27) setLabel(dst, "PENTA", contours[i]); else if (vtc == 6 && mincos >= -0.55 && maxcos <= -0.45) setLabel(dst, "HEXA", contours[i]); } else { // Determinar si es un circulo double area = cv::contourArea(contours[i]); cv::Rect r = cv::boundingRect(contours[i]); int radius = r.width / 2; if (std::abs(1 - ((double)r.width / r.height)) <= 0.2 && std::abs(1 - (area / (CV_PI * std::pow(radius, 2)))) <= 0.2) setLabel(dst, "CIR", contours[i]); } }
Descargar: detector de figuras.zip
hola que tal oye ando haciendo algo parecido para detectar las placas de los carros, cuando usas lo de approxpolyDP, como obtuviste el valor: cv::arcLength(cv::Mat(contours[i]), true)*0.02 , como llegaste a eso?
ResponderEliminarsaludos
en alguna parte se explica como iniciarse en opencv?
ResponderEliminarCreo que este es un buen link :p
Eliminarhttp://acodigo.blogspot.mx/2013/05/introduccion-opencv.html
Hola, estoy buscando como detectar los contornos de un defecto de una fruta y seleccionarlo ahi el contorno es irregular. utilizando libreria Opencv solo quiero ver que funcion utilizar ?
ResponderEliminarHola,en que software esta implementando la libreria opencv
ResponderEliminarHola,en que software esta implementando la libreria opencv
ResponderEliminaramigo tengo un error en approx no me sale esa funcion
ResponderEliminarque includes tienes? agrega este include #include "opencv2/imgproc.hpp" es donde esta definida
Eliminartengo una imagen de 100 x 100. Bien mi imagen es una matriz, ahora a esta matriz de mi imagen, quiero sumarle otra matriz de 100 x 100
ResponderEliminarLa variable approx que tipo de variable es o donde esta declarada?? o como se declara??
ResponderEliminarstd::vector approx;
EliminarEsta es una variable usada para almacenar cada uno de los puntos que corresponden a las esquinas de la figura, descarga eco código completo para ver donde está declarada.
https://www.dropbox.com/sh/ycgh9u8rjxb49jt/AAABbPgE5iuW2mfFe1b7K7nWa?dl=0&preview=Deteccion_de_figuras.rar
Hola, como podría hacer esto para solo dibujar los circulos?
ResponderEliminarPara buscar cículos usas cv::HoughCircle() puedes ver un ejemplo de esto en:
Eliminarhttp://acodigo.blogspot.com/2017/09/deteccion-de-lineas-y-circulos-usando.html