Как обнаружить Солнце с космического неба в OpenCv?

Мне нужно обнаружить Солнце с космического неба.

Это примеры входных изображений:

У меня такие результаты появляются после морфологической фильтрации (open операция за два раза)

Вот код алгоритма этой обработки:

// Color to Gray
cvCvtColor(image, gray, CV_RGB2GRAY);

// color threshold
cvThreshold(gray,gray,150,255,CV_THRESH_BINARY);

// Morphologic open for 2 times
cvMorphologyEx( gray, dst, NULL, CV_SHAPE_RECT, CV_MOP_OPEN, 2);

Разве это не слишком тяжелая обработка для такой простой задачи? А как найти центр Солнца? Если я найду белые точки, то я найду белые точки большой Земли (левый верхний угол на первом примере изображения)

Пожалуйста, посоветуйте мне, пожалуйста, мои дальнейшие действия по обнаружению Солнца.

ОБНОВЛЕНИЕ 1:

Пробуем алгоритм получения centroid по формуле: {x,y} = {M10/M00, M01/M00}

CvMoments moments;
cvMoments(dst, &moments, 1);
double m00, m10, m01;

m00 = cvGetSpatialMoment(&moments, 0,0);
m10 = cvGetSpatialMoment(&moments, 1,0);
m01 = cvGetSpatialMoment(&moments, 0,1);

// calculating centroid
float centroid_x = m10/m00;
float centroid_y = m01/m00;

    cvCircle( image, 
              cvPoint(cvRound(centroid_x), cvRound(centroid_y)), 
              50, CV_RGB(125,125,0), 4, 8,0);

И где Земля на фото, я получил такой результат:

Итак, центроид на Земле.:(

ОБНОВЛЕНИЕ 2:

Попытка cvHoughCircles:

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* circles = cvHoughCircles(dst, storage, CV_HOUGH_GRADIENT, 12, 
                                dst->width/2, 255, 100, 0, 35);

if ( circles->total > 0 ) {
    // getting first found circle
    float* circle = (float*)cvGetSeqElem( circles, 0 ); 

    // Drawing:
    // green center dot
    cvCircle( image, cvPoint(cvRound(circle[0]),cvRound(circle[1])), 
          3, CV_RGB(0,255,0), -1, 8, 0 ); 
    // wrapping red circle
    cvCircle( image, cvPoint(cvRound(circle[0]),cvRound(circle[1])), 
        cvRound(circle[2]), CV_RGB(255,0,0), 3, 8, 0 ); 
}

Первый пример: бинго, а второй - нет;(

Я пробовал другую конфигурацию cvHoughCircles() - не могу найти конфигурацию, подходящую для каждого моего примера фотографии.

Update3:

matchTemplate подход работал для меня (ответ mevatron). Работало с большим количеством тестов.

3 ответа

Решение

Как насчет простого matchTemplate подход. Я использовал этот шаблон изображения:

И он обнаружил 3 из 3 изображений солнца, которые я пробовал:

Это должно работать из-за того, что круги (в вашем случае солнце) вращательно инвариантны, и, поскольку вы находитесь очень далеко от солнца, это также должно быть примерно масштабно инвариантно. Таким образом, сопоставление с шаблоном будет работать очень хорошо здесь.

Наконец, вот код, который я использовал для этого:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
    /// Load image and template
    string inputName = "sun2.png";
    string outputName = "sun2_detect.png";
    Mat img   = imread( inputName, 1 );
    Mat templ = imread( "sun_templ.png", 1 );

    /// Create the result matrix
    int result_cols =  img.cols - templ.cols + 1;
    int result_rows = img.rows - templ.rows + 1;

    Mat result( result_cols, result_rows, CV_32FC1 );

    /// Do the Matching and Normalize
    matchTemplate(img, templ, result, CV_TM_CCOEFF);
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

    Point maxLoc;
    minMaxLoc(result, NULL, NULL, NULL, &maxLoc);

    rectangle(img, maxLoc, Point( maxLoc.x + templ.cols , maxLoc.y + templ.rows ), Scalar(0, 255, 0), 2);
    rectangle(result, maxLoc, Point( maxLoc.x + templ.cols , maxLoc.y + templ.rows ), Scalar(0, 255, 0), 2);

    imshow("img", img);
    imshow("result", result);

    imwrite(outputName, img);

    waitKey(0);

    return 0;
}

Надеюсь, вы найдете это полезным!

Простое дополнение к вашему коду - отфильтровать объекты по размеру. Если вы всегда ожидаете, что Земля будет намного больше Солнца или Солнце будет иметь почти одинаковую площадь на каждом снимке, вы можете отфильтровать ее по площади.

Попробуйте Blob детектор для этой задачи.

И обратите внимание, что может быть полезно применить морфологическое открытие / закрытие вместо простой эрозии или расширения, так что ваше солнце будет иметь почти одинаковую площадь до и после обработки.

Подход цветовой сегментации

Выполните цветовую сегментацию на изображениях, чтобы идентифицировать объекты на черном фоне. Вы можете идентифицировать солнце в соответствии с его областью (учитывая, что оно однозначно идентифицирует его, и, соответственно, не меняется в основном по изображениям). Более сложный подход может вычислить моменты изображения, например, моменты объектов. Смотрите эту страницу для этих функций.

Используйте алгоритм классификации по вашему выбору, чтобы выполнить фактическую классификацию найденных объектов. Самый простой подход заключается в ручном указании порогов, соответственно. диапазоны значений, которые работают для всех (большинства) комбинаций вашего объекта / изображения.

Вы можете вычислить фактическую позицию из необработанных моментов, поскольку для кругового солнца позиция равна центру масс

Centroid: {x, y } = { M10/M00, M01/M00 }

Подход к краевой карте

Другим вариантом будет преобразование окружности, если карта ребер, мы надеемся, что вернутся некоторые подходящие круги (по положению и радиусу). Вы можете выбрать солнечный круг в соответствии с ожидаемым радиусом (если вам повезет, его максимум).

Другие вопросы по тегам