2

I want to count number of trees on this picture from above.

I know how to count elements, but till now I used images with white background, so counting is much easier. But on image like this i do not know what to do:

enter image description here

I converted the image to gray, and then done the threshold *(threshold value is done by hand, is there a way to find it automaticly?), my next idea is to find the 'centers' of black dots, or to 'group' them.

I also tried to change brightness and contrast but it didnt work.

What should I do? This is the code that I wrote:

import cv2
import numpy as np

# Read image
img = cv2.imread('slika.jpg')

# Convert image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Show grayscale image
cv2.imshow('gray image', gray)
cv2.waitKey(0)

#BIG PROBLEM: IM FINDING VALUE OF `40` IN THE LINE BELOW MANUALLY

# Inverse binary threshold image with threshold at 40,
_, threshold_one = cv2.threshold(gray, 40 , 255, cv2.THRESH_BINARY_INV)

# Show thresholded image
cv2.imshow('threshold image', threshold_one)
cv2.waitKey(0)

# Find contours
contours, h = cv2.findContours(threshold_one, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

print('Number of trees found:', len(contours))  #GIVES WRONG RESULT

# Iterate all found contours
for cnt in contours:

    # Draw contour in original/final image
    cv2.drawContours(img, [cnt], 0, (0, 0, 255), 1)

# Show final image
cv2.imshow('result image', img)
cv2.waitKey(0)

This is the image with treshold, I have tried to blur it (in order to connect black dots), but the final output is the same:

enter image description here

This is the result image:

enter image description here

1
  • 1
    this is a hard problem, not something that can be comprehensively answered here, see e.g. towardsdatascience.com/… Commented Oct 22, 2019 at 17:53

1 Answer 1

2

Here's a rough method to estimate the number of trees. The idea to to model each tree as a blob then use contour filtering with a minimum threshold area to ignore the noise. To determine automatic threshold levels, you can use Otsu's threshold by appending cv2.THRESH_OTSU or Adaptive threshold with cv2.adaptiveThreshold(). This approach has problems when the trees are very close together since they form a single blob. Possible improvements could be to find the average area of each tree then find the floor with a large blob. You would probably need to train a classifier and use deep/machine learning for better accuracy

enter image description here

Trees: 102

import cv2

image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
opening = cv2.morphologyEx(close, cv2.MORPH_OPEN, kernel, iterations=2)

cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
trees = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > 50:
        x,y,w,h = cv2.boundingRect(c)
        cv2.drawContours(image, [c], -1, (36,255,12), 2)
        trees += 1

print('Trees:', trees)
cv2.imshow('image', image)
cv2.waitKey()
Sign up to request clarification or add additional context in comments.

4 Comments

Have you used Otsu's threshold or Adaptive threshold? because I do not know where should I use it
Yes in this example I used Otsu's threshold by appending cv2.THRESH_OTSU. Here's the documentation for Otsu. To use adaptive threshold, it requires another function cv2.adaptiveThreshold()
You helped me a lot, thanks my friend! One more question, can you explain to me whats cv2.MORPH_ELLIPSE, cv2.MORPH_CLOSE, cv2.MORPH_OPEN ? I have read the documentation, but I did not understand it quite well
When performing morphological operations, specifically when using cv2.morphologyEx(), you can use cv2.MORPH_CLOSE which is a dilate followed by an erosion or cv2.MORPH_OPEN which is a erosion followed by a dilation. Its essentially combining cv2.dilate() and cv2.erode(). To perform this operation, it requires a kernel so in this case, we create a ellipse shaped kernel using cv2.MORPH_ELLIPSE. Look here for more details

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.