Detecção de Cantos com Precisão Subpixel em OpenCV

A detecção de cantos em imagens frequentemente fornece coordenadas inteiras, o que é insuficiente para aplicações que exigem alta precisão, como calibração de câmeras, reconstrução 3D e rastreamento visual. O OpenCV oferece o método cornerSubPix, que refina coordenadas inteiras de cantos para valores reais com precisão subpixel por meio de iteração de mínimos quadrados.

Princípio do Refinamento Subpixel

O algoritmo parte de uma coordenada inicial inteira próxima ao canto real. Considera-se uma janela ao redor do ponto e analisam-se os gradientes locais. Em regiões homogêneas, o gradiente é próximo de zero. Próximo a uma aresta, o gradiente é perpendicular à direção da aresta. A posição refinada é encontrada resolvendo um sistema de equações que minimiza o produto escalar entre os gradientes e os vetores que apontam do centro para os pixels vizinhos. A solução deste sistema fornece a posição do canto em coordenadas reais.

Definindo Critérios de Convergência

A iteração é controlada por um objeto cv::TermCriteria:

cv::TermCriteria criterio(
    cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER,
    maxIteracoes,
    precisao
);

Os parâmetros são: tipo de critério (contagem máxima de iterações, precisão ou ambos), número máximo de iterações e limiar de precisão desejado.

Função cornerSubPix

cv::cornerSubPix(
    imagemCinza,
    cantos,
    cv::Size(janelaX, janelaY),
    cv::Size(zonaMortaX, zonaMortaY),
    criterio
);

Os parâmetros são:

  • imagemCinza: imagem de entrada em escala de cinza.
  • cantos: vetor de cv::Point2f com as coordendaas iniciais e refinadas.
  • winSize: metade do tamanho da janela de busca ao redor de cada canto.
  • zeroZone: metade da zona morta central, usada para evitar singularidades na matriz de autocorrelação.
  • criteria: critérios de parada do processo ietrativo.

Exemplo Completo

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

int main()
{
    cv::Mat original = cv::imread("imagem.jpg");
    if (original.empty())
    {
        std::cerr << "Erro ao carregar a imagem." << std::endl;
        return -1;
    }

    cv::resize(original, original, cv::Size(640, 480));

    cv::Mat cinza;
    cv::cvtColor(original, cinza, cv::COLOR_BGR2GRAY);

    std::vector<cv::Point2f> candidatos;
    cv::goodFeaturesToTrack(
        cinza,
        candidatos,
        80,
        0.01,
        10.0,
        cv::noArray(),
        3,
        false,
        0.04
    );

    cv::TermCriteria criterio(
        cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER,
        30,
        0.001
    );

    cv::cornerSubPix(
        cinza,
        candidatos,
        cv::Size(5, 5),
        cv::Size(-1, -1),
        criterio
    );

    cv::Mat saida = original.clone();
    for (size_t i = 0; i < candidatos.size(); ++i)
    {
        cv::circle(saida, candidatos[i], 4, cv::Scalar(0, 0, 255), -1);
        std::cout << "Canto " << i
                  << ": (" << candidatos[i].x
                  << ", " << candidatos[i].y << ")" << std::endl;
    }

    cv::imshow("Cantos Subpixel", saida);
    cv::waitKey(0);

    return 0;
}

Tags: OpenCV C++ Shi-Tomasi cornerSubPix Subpixel Detection

Publicado em 6-23 05:26