Finding the darkest region in a depth map using numpy and/or cv2
The minimum is not a single point but as a rule a larger area. argmin
finds the first x and y (top left corner) of this area:
In case of multiple occurrences of the minimum values, the indicescorresponding to the first occurrence are returned.
What you need is the center of this minimum region. You can find it using moments
. Sometimes you have multiple minimum regions for instance in frame107.png
. In this case we take the biggest one by finding the contour with the largest area.
We still have some jumping markers as sometimes you have a tiny area that is the minimum, e.g. in frame25.png
. Therefore we use a minimum area threshold min_area
, i.e. we don't use the absolute minimum region but the region with the smallest value from all regions greater or equal that threshold.
import numpy as npimport cv2import globmin_area = 500for file in glob.glob("*.png"): img = cv2.imread(file, cv2.IMREAD_GRAYSCALE) for i in range(img.min(), 255): if np.count_nonzero(img==i) >= min_area: b = np.where(img==i, 1, 0).astype(np.uint8) break contours,_ = cv2.findContours(b, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) max_contour = max(contours, key=cv2.contourArea) m = cv2.moments(max_contour) x = int(m["m10"] / m["m00"]) y = int(m["m01"] / m["m00"]) out = cv2.circle(img, (x,y), 10, 255, 2 ) cv2.imwrite(file,out)
frame107
with five regions where the image is 0
shown with enhanced gamma:
frame25
with very small min region (red arrow), we take the fifth largest min region instead (white cirle):
The result (for min_area=500
) is still a bit jumpy at some places, but if you further increase min_area
you'll get false results for frames with a very steeply descending (and hence small per value) dark area. Maybe you can use the time axis (frame number) to filter out frames where the location of the darkest region jumps back and forth within 3 frames.