Cloud extraction from sky image

asked 2016-04-02 20:00:51 -0600

rca gravatar image

I'm trying to achieve clouds extraction from a sky image(which I get from camera/video) with my limited OpenCV knowledge.

In the code example below, I'm splitting the image to it's channels such as BGR, and I'm getting grayscale image by blue-red channels difference. Then I put threshold on this grayscale image to create cloud area mask(in fact, it gives sky areas and I invert it). After these steps, finally I put the mask on the actual image which is show the real cloud areas according to the threshold limit. It works as expected for whitish/grayish clouds but it doesn't for the bluish ones. After some additional checks about sky characteristics such as NBRR(Normalised Blue-Red Ratio) and saturation, I got better results but still not best in my opinion due to threshold values need to be changed image to image.

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);

Sample output :

image description

Any idea about how to improve the technique? Also, in step two, I need to calculate move direction for each cloud.

edit retag flag offensive close merge delete

Comments

1

may you can find something in this paper

LBerger gravatar imageLBerger ( 2016-04-03 05:57:06 -0600 )edit

thank you but I checked it already.

rca gravatar imagerca ( 2016-04-03 15:18:09 -0600 )edit
1

Max RGB of GIMP seems worth to try

sturkmen gravatar imagesturkmen ( 2016-04-03 15:54:39 -0600 )edit

Can you post original image?

LBerger gravatar imageLBerger ( 2016-04-04 02:07:41 -0600 )edit

It's just a video frame, you can download by this link.

rca gravatar imagerca ( 2016-04-04 05:44:43 -0600 )edit

About your program you can split your image in three plane use function divide after use threshold function. It is much faster for real time processing Try something like this :

int main(int argc, char* argv[])
{
    Mat im=imread("maxresdefault.jpg");
    Mat imHSV;
    Mat dst;
    cvtColor(im,imHSV,CV_BGR2HSV);
    vector<Mat> plan;
    split(imHSV,plan);
    inRange(plan[1],0,40,dst);
    imshow("inrange",dst);
    imshow("original",im);
    waitKey();
    return 0;
}

PS I'm not a specialist of HSV space

LBerger gravatar imageLBerger ( 2016-04-04 07:03:30 -0600 )edit

Hello, Did you solve this by any chance? I am having the same issue. Could you please help me out

Bhargavi gravatar imageBhargavi ( 2018-03-17 08:17:01 -0600 )edit