2016-03-31 6 views
3

Ich versuche mit meinem begrenzten OpenCV-Wissen Wolken aus einem Himmelsbild (welches ich von Kamera/Video erhalte) zu extrahieren.Bild der Himmelsanalyse mit OpenCV

Im folgenden Codebeispiel spalte ich das Bild auf seine Kanäle wie BGR, und ich bekomme Graustufenbild durch blau-roten Kanalunterschied. Dann setze ich den Schwellenwert auf dieses Graustufenbild, um eine Wolkenbereichsmaske zu erstellen (tatsächlich gibt es Himmelsbereiche und ich invertiere sie). Nach diesen Schritten lege ich schließlich die Maske auf das eigentliche Bild, welches die realen Wolkenbereiche gemäß dem Grenzwert zeigt. Es funktioniert wie erwartet für weißliche/gräuliche Wolken, aber nicht für die bläulichen Wolken.

cv::Mat ch[3], img_gray, img_element, img_brdiff; 
img_element = getStructuringElement(MORPH_RECT, Size(6, 6), Point(6, 6)); 
img_brdiff = cv::Mat::zeros(img_frame.size(), CV_8UC3); 
cv::split(img_frame, ch); 
cv::absdiff(ch[2], ch[0], img_brdiff); 
cv::threshold(img_brdiff, img_gray, 35, 255, CV_THRESH_BINARY_INV);  
cv::morphologyEx(img_gray, img_gray, cv::MORPH_CLOSE, img_element); 
//cv::medianBlur(img_gray, img_gray, 3); 
img_frame.copyTo(img_final, img_gray); 
cv::imshow("in", img_frame); 
cv::imshow("out", img_final); 

Jede Idee, wie die Technik zu verbessern? In Schritt zwei muss ich auch die Bewegungsrichtung für jede Wolke berechnen.

Hier sind meine Bilder Beispiele.

enter image description here

enter image description here

aktualisieren

Nach einigen zusätzlichen Kontrollen über Himmel Merkmale wie NBRR (Normalized Blau-Rot-Verhältnis), Sättigung, bekam ich bessere Ergebnisse aber noch nicht am besten in meine meinung ... Erweiterter Beispielcode ist unten.

const int BINARY_TH = 35; 
const double SAT_FIX_TH = 0.3; 
const double NBRR_FIX_TH = 0.4; 

cv::Mat ch[3], img_gray, img_element, img_brdiff; 
img_element = getStructuringElement(MORPH_RECT, Size(6, 6), Point(6, 6)); 
img_brdiff = cv::Mat::zeros(img_frame.size(), CV_8UC3); 
cv::split(img_frame, ch); 
cv::absdiff(ch[2], ch[0], img_brdiff); 
cv::threshold(img_brdiff, img_gray, BINARY_TH, 255, CV_THRESH_BINARY_INV);  
cv::morphologyEx(img_gray, img_gray, cv::MORPH_CLOSE, img_element); 

double r, b, g, nbrr, sat; 
for(int y = 0; y < img_frame.rows; y++) 
{ 
    for(int x = 0; x < img_frame.cols; x++) 
    { 
     b = img_frame.at<Vec3b>(y,x)[0]; 
     g = img_frame.at<Vec3b>(y,x)[1]; 
     r = img_frame.at<Vec3b>(y,x)[2]; 

     nbrr = (b - r)/(b + r); 
     sat = 1.0 - (std::min(b, std::min(g, r))/std::max(b, std::max(g, r))); 

     if(nbrr < NBRR_FIX_TH && 
      sat < SAT_FIX_TH 
      ) 
      img_gray.at<uchar>(y, x) = (uchar)255; 
    } 
} 

cv::medianBlur(img_gray, img_gray, 3); 

img_frame.copyTo(img_final, img_gray); 
cv::imshow("in", img_frame); 
cv::imshow("out", img_final); 
+3

Sie hätten mehr Glück auf dem opencv-Forum - das ist eine sehr breite Frage mit keiner richtigen Antwort – chris

Antwort

0

Ich denke, Sie hätten bessere Ergebnisse, wenn Sie einen Schwellenwert für den Farbverlauf verwenden. Sie müssten den blauen Kanal dafür behalten. Ich kann Ihnen kein Codebeispiel geben, da ich nicht weiß, wie man opencv benutzt, aber es muss jede Menge Beispiele online geben.

Haben Sie auch versucht, Ihr Bild in Graustufen zu transformieren?

+0

In meinem Codebeispiel spalte ich das Bild auf seine Kanäle wie BGR, und ich bekomme Graustufen Bild von blau-roten Kanälen Unterschied. Dann setze ich den Schwellenwert auf dieses Graustufenbild, um eine Wolkenbereichsmaske zu erstellen (tatsächlich gibt es Himmelsbereiche und ich invertiere sie). Nach diesen Schritten lege ich schließlich die Maske auf das eigentliche Bild, welches die realen Wolkenbereiche gemäß dem Grenzwert zeigt. Ahh außer diesen bläulichen Wolkenregionen. :) – rca

+0

Alles klar, danke für die Erklärungen. Ich denke immer noch, dass Sie einen Gradienten anstelle einer einfachen Schwelle verwenden sollten, sollte es bessere Ergebnisse auf den dunklen Wolken geben. Sie können Ihr Bild auch vor dem Berechnen des Farbverlaufs tiefpassfiltern, um den Geräuschpegel zu senken und somit ein saubereres Ergebnis zu erzielen. – Antoine

+0

Vielen Dank für Ihr Interesse. Aber ich verstehe nicht, wie ein Gredient als Schwelle verwendet? Das Problem besteht darin, dass ein Teil der Wolken wie ein Himmel aussieht und eine höhere blaue Dichte hat, weshalb sie im Algorithmus nicht als Wolke durchgehen können. – rca