0

What is My Issue?

I have generated depth maps from monocular images using DenseDepth. Some of my results are below. I need help masking the darkest shades/ the darkest value of greys in a given range in the depth map.

I would like to be able to give two hex values ie. #6E6E6E and #000000 and for the mask to select all the values in-between Hex values in-between #6E6E6E and #000000 and then generate a black and white mask.

What Have I Tried?

After some research I came across this here: https://medium.com/@offsouza/segmentando-objetos-pela-cor-opencv-487d5181b473 (Use on Chrome for Google Translate as it is in Spanish I think)

Here is the depth map which I tried to use in this specific example:

DepthMap used in demo code

Here is the python code which I used:

import cv2
import numpy as np

image = cv2.imread('DepthMap.png')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
blur = cv2.medianBlur(hsv ,11)

lower = np.array([0,0,35])
upper = np.array([0,0,44])

mask = cv2.inRange(blur, lower, upper)
res = cv2.bitwise_and(image,image, mask= mask)            

cv2.imshow("mask ",mask)
cv2.imshow('stack', np.hstack([image, res]))
cv2.waitKey(0)

This is the output of the code:

Output1

Output2

This doesn't ,however, allow me to give two hex values and then select everything in-between but instead I need to specify the upper and lower values. To do this I used this script here: https://github.com/offsouza/color-segmentation/blob/master/get_color.py.

As you can probably tell, this isn't the best result- at all- to the extent that it doesn't work. I have very little knowledge in this field so I would really appreciate if you could help me!

Edit: this is a hand drawn representation of an expected outcome:

https://i.ibb.co/n8JkSf3/C051-EAE8-C114-4-E90-8938-25-A8-C79-A4-A7-E.jpg

Aiyush
  • 170
  • 13
  • 1
    How do you know this is not the correct result, please? What is the expected result, please? What are the units of your hex values in metres, please? – Mark Setchell Jan 03 '21 at 22:11
  • Hi @Mark, yes. The hex values are actually colour values, not meters, although they do represent depth they are arbitrary so it is difficult to give an exact number. I expected only the darker area to be masked , however, this is not the case ie the chair in the bottom left is not masked. Thanks Ag – Aiyush Jan 04 '21 at 07:31
  • @Mark here is a hand drawn representation of the mask of what I would have liked to achieve : https://i.ibb.co/n8JkSf3/C051-EAE8-C114-4-E90-8938-25-A8-C79-A4-A7-E.jpg – Aiyush Jan 04 '21 at 07:38
  • you need to understand the `lower` and `upper` variables and the `inRange` function in that code you copied. it is bad form to simply copy code and ask others to fix it. – Christoph Rackwitz Jan 04 '21 at 07:53
  • Depth maps are normally single channel images wherein the values (pixel brightnesses) represent distance. So I mean they are not 3-channel RGB images, so there is no need to convert RGB2HSV. so drop that step. Then look at the `inRange()` function like Christoph helpfully suggested. – Mark Setchell Jan 04 '21 at 08:18
  • Okay I will do that, do you think that using a threshold instead would be better suited to my issue? – Aiyush Jan 04 '21 at 09:01
  • Personally, I would use an `and` in a Numpy boolean https://stackoverflow.com/a/33356484/2836621 – Mark Setchell Jan 04 '21 at 09:24
  • @Mark Oh right, at the moment, I am finding the average (not dominant) colour in my image and then dividing this by 2 to use as my threshold value as this gives the darkest shade of grey selected and also gives as a map, I am just experimenting on ways to make it more efficient at the moment. Overall, do you believe that open-cv is faster than skim age? – Aiyush Jan 04 '21 at 09:28
  • **OpenCV** is certainly highly SIMD-optimised if you are on Intel, but choosing the right algorithm and having the correct system architecture and design can easily make a bigger difference. – Mark Setchell Jan 04 '21 at 10:13
  • Hmm that's interesting. In the future I hope to deploy this on Rpi so I'll be sticking with OpenCV I think. – Aiyush Jan 04 '21 at 10:27

1 Answers1

2

To better solve my issue and allow it to be generalised across a wide range of depth maps I took a different approach to reach the same objective.

Instead of selecting upper and lower colour ranges which seemed to give inconsistent results when tested on various images. I chose to use global thresholding instead.

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html

I further adapted my code to take the average (not dominant) shade of grey aka brightness, and divided this by 2. Thus giving me the 25% darkest areas of grey being highlighted and used this as my threshold value. This effectively completed my objective.

Here is my code.

import cv2
import numpy as np

# Only for the threshold display
from matplotlib import pyplot as plt

# The Image to be used
image = 'DepthMap.png'

# Finding the average greyscale value
image_bgr = cv2.imread(image, cv2.IMREAD_GRAYSCALE)

# Calculate the mean of each channel
channels = cv2.mean(image_bgr)
# Type Float
thresh = channels[0]/2
#print (thresh)

# Displaying the threshold value

img = cv2.imread(image,0)
img = cv2.medianBlur(img,5)

# If below then black else white 
ret,th1 = cv2.threshold(img,thresh,255,cv2.THRESH_BINARY)


titles = ['Original Image', 'Global Thresholding']
images = [img, th1]

for i in range(2):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

# Shows single image on its' own
'''
plt.imshow(images[1], 'gray')
plt.xticks([]),plt.yticks([])
'''
plt.show()

DepthMap.png:

DepthMap

Output:

Global Thresholding

To prove that this works on other images I also tested the same code on another Depth Map:

Input:

Depth Map Generalisation

Output:

Depth Map Generalisation Output

Evaluation Although you can see in both images the darkest value is different, the algorithm has adapted and still works, this means that this could be used on video depth maps also and not require constant tweaking.

Aiyush
  • 170
  • 13
  • Why are you using `cv2.IMREAD_COLOR` if you have/want a greyscale depth image? You would be better off using `cv2.IMREAD_GRAYSCALE` because that will be faster and use less memory and also mean you spend less time calculating the means of the channels as you will only have one instead of three - see what I mean about choosing the right algorithm/design – Mark Setchell Jan 04 '21 at 12:43
  • @Mark Jeez, that made it way quicker- noticeably quicker just by looking at it. Wish I had common sense like you ;) & expertise in this field. Decided to go into this not knowing anything about Image processing but have learnt a tonne due to helpful dudes like you. – Aiyush Jan 04 '21 at 13:59