Notas de desarrollo de OpenCV (cuarenta y tres): el hombre gordo rojo te lleva en 8 minutos para aprender más sobre la probabilidad acumulativa de transformación de la línea de Hough

Si el artículo es original, no se puede reproducir sin permiso 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/105544972
lectores, el conocimiento es infinito y la mano de obra es pobre, cambie la demanda o encuentre un profesional o investigue usted mismo

Directorio

Prólogo

Manifestación

Transformación de Hough

Resumen

Probabilidad acumulativa Transformación de línea de Hough

Resumen

Principio

1. El espacio bidimensional de una imagen en línea recta puede representarse mediante dos variables.

2. En general, para un punto (x0, y0), se puede definir uniformemente por un conjunto de líneas rectas en este punto

3. Para un punto dado (x0, y0), todas las líneas rectas que pasan a través de él en coordenadas polares al diámetro polar y al plano del ángulo polar obtendrán una curva sinusoidal

4. Realice las operaciones anteriores en todos los puntos de la imagen para obtener un conjunto de gráficos

5. De lo anterior, se puede detectar una línea recta al encontrar el número de curvas que se cruzan en un punto en el plano θ-r.

Prototipo de probabilidad acumulativa Función de transformación de Hough

Prototipo de función de datos suplementarios

Código fuente de demostración

Plantilla de proyecto: número de versión correspondiente v1.38.0

Publicación de blog de referencia


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

 

    Notas de desarrollo de OpenCV (cuarenta y tres): Red Fat Man le toma 8 minutos para obtener una comprensión profunda de la probabilidad acumulativa Transformación de línea de Hough (tanto imágenes como texto + fácil de entender + 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, se realiza 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. El artículo anterior explicaba la transformación de línea de Hough En este capítulo, explicaremos la probabilidad acumulativa de transformación de línea de Hough en la transformación de línea de Hough.

Aquí volveré a hablar sobre el principio para profundizar su comprensión. Porque la comprensión de 8 minutos de la transformación de Hough no es suficiente en el artículo anterior. La transformación de Hough es uno de los métodos de detección importantes. Para comparar los efectos de detección.

 

Manifestación

 

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:

Probabilidad acumulativa Transformación de línea de Hough

Resumen

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

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

La transformación de líneas intensas encontrará una gran cantidad de líneas, pero algunas líneas son realmente inútiles.

Principio

1. El espacio bidimensional de una imagen en línea recta puede representarse mediante dos variables.

  • En el sistema de coordenadas cartesianas: se puede expresar por pendiente de parámetro e intercepción (m, b);

  • En el sistema de coordenadas polares (el método adoptado por la transformada de Hough): se puede expresar mediante el parámetro diámetro polar y ángulo polar (r, θ);

      La transformación de Hough usa coordenadas polares para representar líneas rectas.

      Entonces la expresión de la línea recta es:

      La fórmula para r es:

2. En general, para un punto (x0, y0), se puede definir uniformemente por un conjunto de líneas rectas en este punto

      rθ = x0 * cosθ + y0 * sinθ

      Cada par (rθ, θ) representa una línea recta que pasa por el punto (x0, y0).

3. Para un punto dado (x0, y0), todas las líneas rectas que pasan a través de él en coordenadas polares al diámetro polar y al plano del ángulo polar obtendrán una curva sinusoidal

Por ejemplo, para un punto dado x0 = 8 e y0 = 6, el principio de cálculo es el siguiente:

Puede obtener la siguiente curva:

Solo dibuje ciertas condiciones, como r> 0 y 0 <θ <2π, (nota: 0 significa línea vertical, π / 2 grados significa línea horizontal);

4. Realice las operaciones anteriores en todos los puntos de la imagen para obtener un conjunto de gráficos

Si las curvas obtenidas después de las operaciones anteriores en dos puntos diferentes se cruzan en el plano θ-r, significa que pasan por la misma línea recta.

Por ejemplo, siguiendo el ejemplo anterior, continúe trazando los puntos x1 = 9, y1 = 4 y x2 = 12, y2 = 3 de la siguiente manera:

Estas tres curvas se comparan con puntos ( 0.925, 9.6 ) en el plano , y las coordenadas representan los pares de parámetros θ-r o puntos (x0, y0), (x1, y1) y (x2, y2) en el plano Línea recta, por lo que en realidad está calculando la distancia de cada ángulo de cada punto en el plano. Después de dibujarlo en una curva, si 3 puntos se cruzan, entonces los 3 puntos están en línea recta, como se muestra en la siguiente figura:

(El número de curvas que se cruzan en un punto excede el umbral (el número de puntos en la misma línea recta). Por ejemplo, en el esquema anterior, se supone que 3 puntos pueden formar una línea recta, luego pueden detectar un salto en línea recta)

5. De lo anterior, se puede detectar una línea recta al encontrar el número de curvas que se cruzan en un punto en el plano θ-r.

Cuantas más curvas se crucen en un punto, más líneas rectas representadas por el punto focal de este punto se componen de más puntos. En general, podemos definir cuántas curvas se cruzan en un punto estableciendo el umbral de puntos en una línea recta, de modo que se detecte una línea recta.

Lo anterior es lo que hace la transformación de Hough. Sigue la intersección de la curva correspondiente de cada punto en la imagen. Si el número de curvas que cruzan un punto excede el umbral (el umbral del número de puntos en la misma línea), entonces la intersección puede considerarse El par de parámetros representativos (θ, rθ) es una línea recta en la imagen original.

Prototipo de probabilidad acumulativa Función de transformación de Hough

void HoughLinesP( InputArray image,
                OutputArray lines,
                double rho,
                double theta,
                int threshold,
                double minLineLength = 0,
                double maxLineGap = 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: las líneas de tipo OutputArray, después de llamar a la función HoughLines, almacenan el vector de salida de las líneas detectadas por la transformación Hough. Cada línea consiste en un vector de dos elementos (r, θ), r representa la distancia desde el origen de las coordenadas, θ es el ángulo de rotación de la línea radianes (0 representa una línea vertical, π / 2 grados representa una línea horizontal);
  • Parámetro 3: doble tipo rho, rho es la distancia de la línea recta, si es 1 píxel, luego detecta la línea recta de longitud 1-> 2-> 3, si es 2, entonces 2-> 4-> 6 ignora 1 y 3 Demasiado
  • Parámetro cuatro: theta de tipo doble, theta es radianes, incluso si todas son líneas, entonces la precisión en radianes entre líneas y líneas, si un punto de 360 ​​grados, radianes es π, significa que comienza desde 0 °, cada π radianes (180 °, detectar una línea) ;
  • Parámetro cinco: umbral de tipo int , el parámetro umbral del plano de acumulación, es decir, el valor que debe alcanzar en el plano de acumulación al identificar una parte como una línea recta en la figura. Mayor que el valor umbral de umbral de segmento de línea puede ser detectado por el resultado y retorno a la;
  • Parámetro 6: minLineLength de tipo doble , el valor predeterminado es 0 , lo que significa que la longitud del segmento de línea más bajo, el segmento de línea más corto que este parámetro de configuración no se puede detectar;
  • Parámetro 7: maxLineGap de tipo double , el valor predeterminado es 0 , la distancia máxima permitida para conectar puntos en la misma línea;

Prototipo de función de datos suplementarios

cvRound():返回跟参数最接近的整数值,即四舍五入;
cvFloor():返回不大于参数的最大整数值,即向下取整;
cvCeil():返回不小于参数的最小整数值,即向上取整;

 

Código fuente de demostración

void OpenCVManager::testHoughLinesP()
{
    QString fileName1 =
            "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/16.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 rh0 = 1;                            // 默认1像素
    int theta = 1;                          // 默认1°
    int threshold = 100;                    // 默认检测到同一直线的100个点

    int minLineLength = 50;                 // 检测线的最小长度
    int maxLineGap = 10;                    // 同一条线点与点的最大距离

    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,
                           height * 0 + 130,
                           200,
                           &threshold2,
                           0,
                           255);
            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 - 120,
                         "rho / 100");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 50 - 120,
                           200,
                           &rh0,
                           1,
                           1000);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 100 - 120,
                         "theta = value / 2");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 130 - 120,
                           200,
                           &theta,
                           1,
                           720);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 180 - 120,
                         "min points");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 210 - 120,
                           200,
                           &threshold,
                           2,
                           300);

            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 260 - 120,
                         "minLineLength = value / 10");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 290 - 120,
                           200,
                           &minLineLength,
                           0,
                           1000);
            cvui::printf(windowMat,
                         width * 1 + 100,
                         height * 1 + 340 - 120,
                         "maxLineGap = value / 10");
            cvui::trackbar(windowMat,
                           width * 1 + 100,
                           height * 1 + 370 - 120,
                           200,
                           &maxLineGap,
                           0,
                           1000);

            // 边缘检测后,进行霍夫线检测
            // 使用霍夫线变化检测所有角度范围内的直线
            std::vector<cv::Vec2f> lines;
            cv::HoughLines(dstMat,                  // 输入8位
                           lines,                   // 输出线 std::vector<std::Vec2f>
                           rh0 / 100.0f,              // 初步像素精度
                           theta / 720.0 * CV_PI,   // 初步偏移角度精度
                           threshold,               // 必须达到的点的数量
                           0,                       // 标准霍夫变换,为0
                           0,                       // 标准霍夫变换,为0
                           0,                       // 检测角度范围最小为0
                           CV_PI);                  // 检测角度范围最大为π,即360°

            // 在图中绘制出每条线段
            dstMat = colorMat.clone();
            qDebug() << __FILE__ << __LINE__ << lines.size();
            for(int index = 0; index < lines.size(); index++)
            {
                float rho = lines[index][0];
                float theta = lines[index][1];
                cv::Point pt1;
                cv::Point pt2;
                double a = cos(theta);
                double b = sin(theta);
                double x0 = a * rho;
                double y0 = b * rho;
                // 计算出点的坐标
                pt1.x = cvRound(x0 + 1000 * (-b));
                pt1.y = cvRound(y0 + 1000 * (a));
                pt2.x = cvRound(x0 - 1000 * (-b));
                pt2.y = cvRound(y0 - 1000 * (a));
                // 画线
                cv::line(dstMat, pt1, pt2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
            }
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);


            // 使用概率霍夫线变化检测所有长度范围内的直线
            cv::Canny(srcMat, dstMat, threshold1, threshold2, apertureSize * 2 + 1);
            std::vector<cv::Vec4i> lines2;
            cv::HoughLinesP(dstMat,                 // 输入8位
                            lines2,                 // 输出线 std::vector<std::Vec4i>
                            rh0/100.0f,             // 初步像素精度
                            theta / 720.0 * CV_PI,  // 初步偏移角度精度
                            threshold,              // 必须达到的点的数量
                            minLineLength / 10.0f,  // 检测线的最小长度
                            maxLineGap / 10.0f);    // 检测线的最大距离
            // 在图中绘制出每条线段
            dstMat = colorMat.clone();
            for(int index = 0; index < lines.size(); index++)
            {
                // 画线
                cv::Vec4i line = lines2[index];
                cv::line(dstMat,
                         cv::Point(line[0], line[1]),
                         cv::Point(line[2], line[3]),
                         cv::Scalar(0, 0, 255),
                         1,
                         cv::LINE_AA);
            }
            // 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);
        }
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}

 

Plantilla de proyecto: número de versión correspondiente v1.38.0

      Número de versión correspondiente v1.38.0

 

Publicación de blog de referencia

      https://blog.csdn.net/shenziheng1/article/details/75307410

 

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 / 105544972

266 artículos originales publicados · 457 elogiados · 530,000 vistas +

Supongo que te gusta

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