Home > front end >  How to generate histograms on zones of an image in Python? (after determining contours with openCV)
How to generate histograms on zones of an image in Python? (after determining contours with openCV)

Time:06-17

I have zero experience in Python but I need to use it as a data processing step for my project. I'm working with drone thermal images of vineyards and the objective is to separate the canopy pixels from the ground pixels based on elevation and temperature. Using a DEM (digital elevation model), a first distinction was made between the canopy and the ground. This results in a binary mask layer that can be put on top of the thermal image of the vineyard. That way, I now have a thermal image in Python of which most of the ground pixels are 0 and the canopy pixels have a value between 0 and 65535 representing the temperature. However, since the first distinction (using the DEM) is not precise enough, some ground pixels are also included in the canopy mask.

Now I want to make a second distinction using the temperature of the selected zones. I was able to make contours of all the canopy zones with opencv (so I have a complete list of all the contours representing the canopy zones - with some ground pixels). I aim to make a histogram per contour zone displaying the density of each pixelvalue within that zone. Hopefully I can then delete the pixels that are too hot (i.e. groundpixels).

Does anyone know how to generate histograms for every (filled) contour of an image? The format now is an 6082x4922 ndarray with values between 0 and 65535 of datatype uint16. I use PyCharm as an IDE.

Thanks in advance!

CodePudding user response:

Approach:

  • Iterate through each contour in the mask
  • Find locations of pixels present in the mask
  • Find their corresponding values in the given image
  • Compute and plot the histogram

Code:

# reading given image in grayscale
img = cv2.imread('apples.jpg', 0)

enter image description here

# reading the mask in grayscale
img_mask = cv2.imread(r'apples_mask.jpg', 0)
# binarizing the mask
mask = cv2.threshold(img_mask,0,255,cv2.THRESH_BINARY cv2.THRESH_OTSU)[1]

enter image description here

# find contours on the mask
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# the approach is encoded within this loop
for i, c in enumerate(contours):
    # create a blank image of same shape
    black = np.full(shape = im.shape, fill_value = 0, dtype = np.uint8)
    # draw a single contour as a mask
    single_object_mask = cv2.drawContours(black,[c],0,255, -1)
    # coordinates containing white pixels of mask
    coords = np.where(single_object_mask == 255)
    # pixel intensities present within the image at these locations
    pixels = img[coords]
    # plot histogram
    plt.hist(pixels,256,[0,256])
    plt.savefig('apples_histogram_{}.jpg'.format(i)')
    # to avoid plotting in the same plot
    plt.clf()

Result: (the following are the 3 histogram plots)

enter image description here

enter image description here

enter image description here

If you remove plt.clf(), all the histograms will be plotted on a single plot

You can extend the same approach for your use case

Original image:

enter image description here

  • Related