0

I was trying to get the percentage of clouds in an image using OpenCV:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('path/to/img')

def create_clouds_mask(img_bgr):
    img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)  # from bgr to rgb
    rgb_white = np.asarray([255, 255, 255])   # white
    rgb_grey = np.asarray([138, 138, 138])   # grey

    # pick colors from white to grey and creates a mask
    mask = cv2.inRange(img_rgb, rgb_grey, rgb_white)

    return mask


def cloud_coverage_perc(bgr_img, mask):
    # from bgr to hsv (for comparison with the mask)
    hsv_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2HSV)
   
    res = cv2.bitwise_and(hsv_img, hsv_img, mask=mask)
    ratio = cv2.countNonZero(mask)/(hsv_img.size/3)
    perc = np.round(ratio*100, 2)  # percentage of the clouds in the image

    return res, perc

mask = create_clouds_mask(img)
res, perc = cloud_coverage_perc(img, mask)

print("Clouds perc: ", perc, "%")
plt.imshow(res)
plt.show()

the problem is that i can't find the correct range of colors, for example this image here view from the ISS

the result is the mask

it even takes the island as a part of the clouds, but if I try to higher the values of

rgb_grey = np.asarray([138, 138, 138])   # grey

then the percentage of clouds that are taken is very small.

What can I do to improve the code, so that the islands aren't a problem?

Leo Chucky
  • 31
  • 3
  • You might try taking swatches of the image from both island and cloud areas and comparing their histograms. Also, shouldn't you be converting your "white" and "grey" from BGR to HSV, the same as you're doing for the image? – Mark Lavin Jan 28 '22 at 22:13
  • 1
    **inRange spans a cube**. in RGB, that means your two limits don't span a line of gray, but a cube that has strong hues at the corners. -- do your inRange in HSL/HSV space too. select low saturation, high value, any hues (because they'll be almost random when the pixel is low saturation). – Christoph Rackwitz Jan 28 '22 at 23:18

0 Answers0