You just need to play with the findContours() and findNonZero() functions.
Have a look, on the code below:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
// Load source image
string filename = "cloud.png";
Mat src = imread(filename);
// Check if image is loaded fine
if(!src.data)
cerr << "Problem loading image!!!" << endl;
// Show source image
imshow("src", src);
// Transform source image to gray if it is not
Mat gray;
if (src.channels() == 3)
{
cvtColor(src, gray, CV_BGR2GRAY);
}
else
{
gray = src;
}
// Show gray image
imshow("gray", gray);
// Transform it to binary and invert it. White on black is needed.
Mat bw;
threshold(gray, bw, 40, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
vector<Point> black_pixels; // output, locations of non-zero pixels
cv::findNonZero(bw, black_pixels);
cout << "Cloud all black pixels: " << black_pixels.size() << endl; // amount of black pixels is returned from the size
// Show binary image
imshow("binary", bw);
vector<Vec4i> hierarchy;
vector<vector<Point> > contours;
// extract only the external blob
findContours(bw.clone(), contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
Mat mask = Mat::zeros(bw.size(), CV_8UC1);
// draw the contours as a solid blob, and create a mask of the cloud
for(size_t i = 0; i < contours.size(); i++)
drawContours(mask, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
imshow("mask", mask);
vector<Point> all_pixels; // output, locations of non-zero pixels
cv::findNonZero(mask, all_pixels);
cout << "Cloud all pixels: " << all_pixels.size() << endl; // amount of all pixels is returned from the size
int white_pixels = all_pixels.size() - black_pixels.size(); // amount of white pixels is returned from the subtraction of all - black ;-)
cout << "Cloud all white pixels: " << white_pixels << endl;
waitKey(0);
return 0;
}