ailsa_naismith
ailsa_naismith

Reputation: 343

Python recursive function for appending variable

I am attempting to assess a series of images in a folder for cloud coverage using OpenCV. I have determined a very simple binary threshold for whether an image contains cloud: in a subset of the image, "summit_roi", if the number of individual pixels with value < 50 is greater than 2000, the image is cloud-free (Each image is a .png file of 512h x 644w pixels with each pixel having a value between 0 and 256).

I would like to loop through the images one-by-one and return an individual value of 0 or 1 for each image where "1" is cloud-free and "0" is cloudy. Then I would like to append each individual value to a variable that, once the script has run through the folder of images, will return a single value of the total number of images in the folder with value 1 (e.g. the variable returns 52 if there are 52 cloud-free images).

I am having difficulty in writing a loop that would return this variable. Any help appreciated. Apologies if my question is too similar to previously posted questions, but I haven't found any! Here's what I have so far:

#loop through image_path_list to open each image
for imagePath in image_path_list:
    image = cv2.imread(imagePath, 0)
    print(image.shape)

    #create ROI
    #ROI formula: roi = image[y:y+h, x:x+w]
    summit_roi = image[100:200, 250:450]
    #draw ROI rectangle on image
    #draw rectangle formula: cv2.rectangle(img, (x1, y1), (x2, y2), (255,0,0), 2)
    cv2.rectangle(image,(250,100), (450,200), (255,0,0), 2)

    #determine various image details
    #print('Shape of summit ROI array is', np.shape(summit_roi))
    counts = (summit_roi < 50).sum()
    print('Sum of pixels with value < 50 is', counts)

#create function to count images meeting threshold conditions
def cloud_detector(counts):   
    cloud_list = []   
    for imagePath in image_path_list:
        if counts > 2000:
            return [1]    
            cloud_list.append(cloud_detector(counts))
        else:
            return []

print(cloud_list)  

I have tagged this post with recursion as I believe I may be missing some code where the function calls itself (and therefore is updated with each successive image), but don't understand how I can call it correctly. Again, help appreciated!

Upvotes: 0

Views: 80

Answers (2)

Prune
Prune

Reputation: 77837

No recursion needed; you've already done that hard parts of accessing and counting the pixels you need. Starting here:

counts = (summit_roi < 50).sum()

Let's work both ways to get the result you want. First, let's work with counts to neatly get the results for one image:

dark_pixel_count = (image[100:200, 250:450] < 50).sum()

Now, add the check against 2000 for your Boolean decision of whether there's a cloud:

is_cloud = (image[100:200, 250:450] < 50).sum() > 2000

Note how I'm adding a new clause or clarification at each step, re-naming the result. You can do all of this with successive steps and intermediate variable names; that's good for debugging. Some one-line computations are more "Pythonic".

is_cloud is a simple Boolean (True / False). Next, back up and get the image more directly from the source. Where we have

for imagePath in image_path_list:
    image = cv2.imread(imagePath, 0)
    is_cloud = (image[100:200, 250:450] < 50).sum() > 2000

make the substitution for image

    is_cloud = (cv2.imread(imagePath, 0) [100:200, 250:450] < 50).sum() > 2000

Now, let's get a list of all the cloud detection, iterating over the input set:

is_cloud_list = [ (cv2.imread(imagePath, 0) [100:200, 250:450] < 50).sum() > 2000
                   for imagePath in image_path_list ]

This gives us a list of Booleans, one for each image. Now, we just count how many are True:

cloud_count = [ (cv2.imread(imagePath, 0) [100:200, 250:450] < 50).sum() > 2000
                 for imagePath in image_path_list ].count(True)

Does this solve the problem?

Upvotes: 1

theherk
theherk

Reputation: 7546

I think, though I don't fully understand the intent, that this is more complex than necessary. Why not forgo the function entirely.

I suggest you simply modify:

  • Remove the function.
  • Precede the code with cloud_count = 0.
  • Follow the counts declaration in the for loop with the following.

if counts > 2000: cloud_count += 1

  • Modify the print to print(cloud_count).

Upvotes: 1

Related Questions