Как обнаружить Солнце с космического неба в 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 }
Подход к краевой карте
Другим вариантом будет преобразование окружности, если карта ребер, мы надеемся, что вернутся некоторые подходящие круги (по положению и радиусу). Вы можете выбрать солнечный круг в соответствии с ожидаемым радиусом (если вам повезет, его максимум).