Notas de desarrollo de OpenCV (44): El hombre gordo rojo te lleva en 8 minutos a comprender la transformación del círculo de Hough en profundidad (con imágenes y texto + fácil de entender + código fuente del programa)

Si el artículo es original, no se puede reproducir sin permiso La
dirección del blog original del blogger: https://blog.csdn.net/qq21497936 La
navegación del blog original del blogger: https://blog.csdn.net/qq21497936/article/details / 102478062
Dirección del blog de este artículo: https://blog.csdn.net/qq21497936/article/details/105575546
lectores, el conocimiento es infinito y la mano de obra es pobre, cambie la demanda o busque un profesional o investigue

Directorio

Prólogo

Manifestación

Transformación de Hough

Resumen

Hough Circle Transform

Resumen

Principio

1. El espacio bidimensional de una imagen circular puede representarse mediante un sistema de coordenadas cartesianas

2. Principio de formación de la curva tridimensional.

3. La base para juzgar el círculo.

Principio de gradiente de Hough

Ventajas del método de gradiente de Hough

Desventajas del método de gradiente de Hough

Prototipo de función de transformación de círculo de Hough

Código fuente de demostración

Plantilla de ingeniería: número de versión correspondiente v1.39.0


Columna de desarrollo de OpenCV (haga clic en el portal)

 

    Notas de desarrollo de OpenCV (44): El hombre gordo rojo te lleva en 8 minutos a comprender la transformación del círculo de Hough en profundidad (con imágenes y texto + fácil de entender + código fuente del programa)

 

Prólogo

      Hombre gordo rojo también viene! ! !

Después de la eliminación de ruido y la detección de bordes, es la extracción de características. Uno de los métodos básicos para identificar gráficos es la transformación de Hough. La transformación de Hough es una tecnología de extracción de características en el procesamiento de imágenes.

 

Manifestación

      Los dos primeros Demos no son muy precisos, porque el autor amplió la imagen original, lo que provocó que el círculo original se deformara un poco. El último se dibujó solo según la resolución escalada.

 

Transformación de Hough

Resumen

      Hough Transform (Transformación Hough) es una tecnología de extracción de características en el procesamiento de imágenes.El proceso de modificación calcula el valor máximo local del resultado acumulativo en un espacio de parámetros para obtener un conjunto que se ajusta a la forma específica como resultado de la Transformación Hough.

      La clásica transformación de Hough se usa para detectar líneas rectas en la imagen, luego se extendió al reconocimiento de objetos de formas arbitrarias, principalmente círculos y elipses.

      La transformación de Hough usa la transformación entre dos espacios de coordenadas para mapear una curva o una línea recta con la misma forma en un espacio a un punto en otro control de coordenadas para formar un pico, convirtiendo así el problema de detectar cualquier forma en un problema de pico estadístico .

      La transformación de Hough en OpenCV se divide en dos tipos, y la transformación de línea se divide en tres tipos, como se muestra a continuación:

Hough Circle Transform

Resumen

      Transformación de círculo de Hough, puede saber por el nombre que en realidad es un círculo. Obviamente, es un método para encontrar un círculo. Aquí prestamos especial atención. Antes de usar la transformación de círculo de Hough, es necesario preprocesar la imagen: reducción de ruido, procesamiento de detección de bordes , La transformación de círculo de Hough solo busca círculos y solo puede reconocer imágenes binarias de borde, por lo que la entrada solo se puede binarizar (imágenes de 8 bits de un solo canal).

      La transformación de círculo de Hough encontrará una gran cantidad de círculos, pero algunos círculos son realmente inútiles y, al igual que la transformación de línea de Hough, pueden producir datos "ruidosos".

Principio

1. El espacio bidimensional de una imagen circular puede representarse mediante un sistema de coordenadas cartesianas

  • En el sistema de coordenadas cartesianas (el método adoptado por la transformación del círculo de Hough): puede haber un centro circular (a, b), y el radio r representa;

La forma del círculo en el sistema de coordenadas cartesianas:

La formula es:

Y

Por lo tanto, en un sistema de coordenadas tridimensional compuesto de abr, un punto puede definir un círculo de manera única.

2. Principio de formación de la curva tridimensional.

Todos los círculos que pasan un cierto punto en el sistema de coordenadas cartesianas xy se asignan al sistema de coordenadas abr como una curva tridimensional.

Todos los círculos que pasan por todos los píxeles distintos de cero en el sistema de coordenadas xy constituyen muchas curvas tridimensionales en el sistema de coordenadas abr.

3. La base para juzgar el círculo.

La ecuación circular de todos los puntos en el mismo círculo en el sistema de coordenadas xy es la misma, y ​​se asignan al mismo punto en el sistema de coordenadas abr, por lo que en el sistema de coordenadas abr, debe haber un total de curvas N0 del círculo. Intersecar Al juzgar el número de intersecciones (acumulativas) de cada punto en abr, un punto mayor que cierto umbral se considera un círculo.

Lo anterior es el algoritmo estándar de transformación de círculo de Hough. El problema es que su superficie de acumulación es un espacio tridimensional, lo que significa que requiere más costo computacional que la transformación de línea de Hough.

Opencv Hough Circle Transform optimiza la transformación estándar de Hough Circle. Utiliza el "método de gradiente de Hough". Su idea de detección es atravesar y acumular el centro del círculo correspondiente a todos los puntos distintos de cero, y considerar el centro del círculo.

El centro del círculo debe estar en el vector módulo de cada punto del círculo, es decir, en la línea vertical perpendicular al punto y pasando por la tangente del punto, la intersección de los vectores módulo en estos círculos es el centro del círculo.

El método de gradiente de Hough es encontrar estos puntos centrales y hacer un juicio final de acuerdo con el umbral de acuerdo con el número de intersecciones de los vectores de módulo en el "punto central".

Principio de gradiente de Hough

  1. Primero realice la detección de bordes en la imagen, como el uso de la detección de bordes astutos;
  2. Para cada punto distinto de cero en la imagen de borde, se considera el gradiente local, es decir, la función Sobel () se usa para calcular la derivada de Sobel en las direcciones x e y para obtener el gradiente;
  3. Usando el gradiente obtenido, cada punto en la línea especificada de alguna tasa se acumula en el acumulador, donde la pendiente es la distancia desde un valor máximo especificado hasta el valor máximo especificado;
  4. Al mismo tiempo, marque cada posición de píxel que no sea cero en la imagen de borde;
  5. Seleccione los centros candidatos de estos puntos en el acumulador bidimensional, de modo que todos los centros sean mayores que un umbral dado y mayores que todos sus vecinos. Los centros de estos candidatos están dispuestos en orden descendente de valor acumulado, y el centro del lado que soporta el píxel aparece primero;
  6. Para cada centro, considere todos los píxeles distintos de cero;
  7. En este caso, los píxeles se organizan de acuerdo con su distancia desde el centro, y desde la distancia más pequeña hasta el radio más grande, se selecciona un radio soportado por un píxel distinto de cero;
  8. Si un centro es totalmente compatible con píxeles distintos de cero de la imagen de borde, y hay suficiente distancia al centro seleccionado anteriormente, entonces se mantendrá;

Ventajas del método de gradiente de Hough

      El algoritmo es eficiente y puede resolver el problema disperso e inestable que genera mucho ruido en el acumulador tridimensional y hace que los resultados sean inestables;

Desventajas del método de gradiente de Hough

  • El uso de derivados de Sobel para calcular puede causar más ruido;
  • En la imagen de borde, todo el píxel distinto de cero se considera como el centro candidato, por lo que establecer el valor del acumulador en un nivel bajo hará que el punto aumente, por lo que la cantidad de cálculo es grande y el algoritmo consume demasiado tiempo;
  • Los centros están dispuestos en orden ascendente de sus acumuladores asociados, y si el nuevo centro está demasiado cerca del punto central previamente aceptado, el punto no será retenido, lo que es equivalente a un círculo concéntrico que solo retiene el círculo de radio más grande;

Prototipo de función de transformación de círculo de Hough

void HoughCircles( InputArray image,
                OutputArray circles,
                int method,
                double dp,
                double minDist,
                double param1 = 100,
                double param2 = 100,
                int minRadius = 0,
                int maxRadius = 0);
  • Parámetro 1: imagen de tipo InputArray, imagen de origen de 8 bits, imagen binaria de un solo canal. Puede cargar cualquier imagen original y modificarla a este formato mediante la función, luego completarla aquí;
  • Parámetro dos: círculos de tipo OutputArray, vector de círculo de salida, cada vector incluye tres elementos de punto flotante : abscisa central del círculo, ordenada central del círculo y radio del círculo;
  • Parámetro tres: método de tipo int, que es un algoritmo que utiliza la detección de círculo de transformación Hough;

Número de serie

Enumeración

Valor

Descripción

1

HOUGH_STANDARD

0 0

CV_HOUGH_STANDARD-Transformación de Hough tradicional o estándar (SHT). Cada segmento de línea está representado por dos números de punto flotante (ρ, θ), donde ρ es la distancia entre la línea y el origen (0,0), y el ángulo entre el segmento de línea θ y el eje x. Por lo tanto, el tipo de matriz debe ser del tipo CV_32FC2;

2

HOUGH_PROBABILISTIC

1

CV_HOUGH_PROBABILISTIC- Probabilistic Hough Transform ( PPHT ). Si la imagen contiene algunos segmentos lineales largos, la eficiencia es mayor. Devuelve el segmento del segmento en lugar del segmento completo. Cada segmento está representado por un punto inicial y un punto final, por lo que el tipo de matriz (o secuencia creada) es del tipo CV_32SC4 ;

3

HOUGH_MULTI_SCALE

2

Variante multiescala de la transformación tradicional de Hough . Segmento que codifica la CV_HOUGH_STANDARD consistente

4 4

HOUGH_GRADIENT

3

Básicamente 21HT

  • Parámetro 4: Doble tipo dp, dp: Encuentre la resolución acumulativa del centro del arco. Este parámetro permite crear un acumulador con una resolución menor que la imagen de entrada. (Esto se debe a que hay razones para creer que los círculos presentes en la imagen disminuirán naturalmente en la misma cantidad que el ancho y la altura de la imagen). Si dp se establece en 1, la resolución es la misma; si se establece en un valor mayor (como 2), la resolución del acumulador se verá reducida por este efecto (la mitad en este caso); el valor de dp no puede ser mayor que 1 Pequeño
  • Parámetro cinco: minDist de tipo doble , precisión, este parámetro es la distancia mínima entre dos círculos diferentes que el algoritmo puede distinguir claramente;
  • Parámetro seis: doble tipo param1 , el valor predeterminado es 100 , utilizado para el límite superior del umbral de borde de Canny , el límite inferior se establece en la mitad del límite superior ;
  • Siete parámetros: Doble tipo param2 , el valor predeterminado es 100 , en el caso del gradiente de Hough, que es el centro de fase de detección de umbral acumulador del círculo. Cuanto más pequeño es, más círculos que no existen pueden detectarse, y cuantos más círculos puedan pasar la detección, más cerca estará el prototipo perfecto;
  • Parámetro ocho: minRadius de tipo int , el valor predeterminado es 0 , el radio mínimo del círculo de detección;
  • Parámetro 9: int type maxRadius , el valor predeterminado es 0 , el radio máximo del círculo de detección, cuando 0 , el máximo es el tamaño de la matriz de píxeles;

 

Código fuente de demostración

void OpenCVManager::testHoughCircles()
{
    QString fileName1 =
            "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/17.jpg";
    cv::Mat srcMat = cv::imread(fileName1.toStdString());
    int width = 400;
    int height = 300;

    cv::resize(srcMat, srcMat, cv::Size(width, height));
    cv::Mat colorMat = srcMat.clone();

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3),
                                srcMat.type());

    cv::cvtColor(srcMat, srcMat, CV_BGR2GRAY);

    int threshold1 = 200;
    int threshold2 = 100;
    int apertureSize = 1;

    int dp = 10;            // 默认1像素
    int minDist = 10;       // 默认1°
    int minRadius = 0;
    int maxRadius = 0;

    while(true)
    {
        qDebug() << __FILE__ << __LINE__;
        windowMat = cv::Scalar(0, 0, 0);

        cv::Mat mat;
        cv::Mat dstMat;
        cv::Mat grayMat;

        // 转换为灰度图像
        // 原图先copy到左边
        cv::Mat leftMat = windowMat(cv::Range(0, srcMat.rows),
                                    cv::Range(0, srcMat.cols));
        cv::cvtColor(srcMat, grayMat, CV_GRAY2BGR);
        cv::addWeighted(leftMat, 0.0f, grayMat, 1.0f, 0.0f, leftMat);

        {
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 0 + 20,
                         "threshold1");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 0 + 50,
                           200,
                           &threshold1,
                           0,
                           255);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 0 + 100, "threshold2");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           srcMat.cols * 0 + 130,
                           200,
                           &threshold2,
                           0,
                           255);

            qDebug() << __FILE__ << __LINE__;
            cv::Canny(srcMat, dstMat, threshold1, threshold2, apertureSize * 2 + 1);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));

            cv::cvtColor(dstMat, grayMat, CV_GRAY2BGR);
            cv::addWeighted(mat, 0.0f, grayMat, 1.0f, 0.0f, mat);

            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 20 - 80,
                         "dp = value / 10");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 50 - 80,
                           200,
                           &dp,
                           1,
                           1000);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 100 - 80,
                         "minDist = value / 2");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 130 - 80,
                           200,
                           &minDist,
                           1,
                           720);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 180 - 80,
                         "minRadius");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 210 - 80,
                           200,
                           &minRadius,
                           0,
                           100);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 260 - 80,
                         "maxRadius");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 290 - 80,
                           200,
                           &maxRadius,
                           0,
                           1000);
            // 边缘检测后,进行霍夫圆检测
            std::vector<cv::Vec3f> circles;
            cv::HoughCircles(dstMat,
                             circles,
                             cv::HOUGH_GRADIENT,
                             dp / 10.0f,
                             minDist / 10.0f,
                             200,
                             100,
                             minRadius,
                             maxRadius);
            // 在图中绘制出每条线段
            dstMat = colorMat.clone();
            for(int index = 0; index < circles.size(); index++)
            {
                cv::Point center(cvRound(circles[index][0]),
                                 cvRound(circles[index][1]));
                int radius = cvRound(circles[index][2]);
                // 绘制圆心
                cv::circle(dstMat, center, 3, cv::Scalar(255, 255, 255));
                // 绘制圆
                cv::circle(dstMat, center, radius, cv::Scalar(0, 0, 255));
            }
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);


            // 在图中绘制出每条线段
            for(int index = 0; index < circles.size(); index++)
            {
                cv::Point center(cvRound(circles[index][0]),
                                 cvRound(circles[index][1]));
                int radius = cvRound(circles[index][2]);
                // 绘制圆心
                cv::circle(grayMat, center, 3, cv::Scalar(255, 255, 255));
                // 绘制圆
                cv::circle(grayMat, center, radius, cv::Scalar(0, 0, 255));
            }
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, grayMat, 1.0f, 0.0f, mat);
        }
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}

 

Plantilla de ingeniería: número de versión correspondiente v1.39.0

      Número de versión correspondiente v1.39.0

 

La dirección del blog del blogger original: https://blog.csdn.net/qq21497936 La
navegación del blog del blogger original: https://blog.csdn.net/qq21497936/article/details/102478062
La dirección del blog de este artículo: https: // blog .csdn.net / qq21497936 / article / details / 105575546

268 artículos originales publicados · Me gusta 466 · Visitas 540,000+

Supongo que te gusta

Origin blog.csdn.net/qq21497936/article/details/105575546
Recomendado
Clasificación