0
votes

I am trying to obtain an image mask with multiple level of threshold meaning considering on the intensity of the pixels I want to threshold the image - white for brightest regions, grey for slightly less brighter regions and black for relatively darker regions. I have come across various articles about multilevel otsu threshold but I could not find an implementation I could use as reference. Once I have these masks I want to perform the bitwise_and on these mask to retrieve original image area for white and grey regions. Is that possible? Currently, I am using ret, thresh_ = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) for getting the masks.

I have tried to explicitly set the values using if statements.

if(thresh_ <=80):
            thresh_ = 0

        elif(thresh_ >80 & thresh_ <=160):
            thresh_ = 150

        else: 
            thresh_ = 255

But it didn't work and it gave an error- The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

for file in glob.glob(path):
        img = cv2.imread(file)  


        #edge detection
        canny = auto_canny(img)


        #Dilation(Morphological function to increase edge width)
        img_dilate = cv2.dilate(canny, (3,3), iterations = 1)
2
You could create 3 threshold images using cv2.inrange() for each range you want. See docs.opencv.org/4.1.1/d2/de8/…fmw42
If you search Google, you will find stackoverflow.com/questions/22706742/… and perhaps others. Also from Skimage, see scikit-image.org/docs/dev/auto_examples/segmentation/…fmw42
@fmw42 is it available in python?Christina Evans
Skimage is python compatiblefmw42
@fmw42 I tried these approaches but it didn't work for me. Maybe I was doing something wrong. That is why I was explicitly specifying the ranges using if statements.Christina Evans

2 Answers

1
votes

Using cv for this might be overkill; you can probably take the image and use numpy-style indexing in order to set your thresholds:

img[img < 80] = 0
img[(img < 160) & (img > 0)] = 150
img[img > 150] = 255

(untested)

The reason you're getting the error you're seeing is because comparisons against an array don't work in "vanilla" python; what would you expect the result of [1, 2, 3] > 2 to return?

But in numpy-flavored Python (which OpenCV uses), the above will return an itemwise comparison of [False, False, True], which is a quality we take advantage of in the code block above.

1
votes

Using Numpy, the solution can easily be achieved with fast built in functions for a variable number of regions. Assume we are doing grey-level segments. Assuming a list of thresholds T of length k-1 (ex. k = 3 regions, T = [85, 170]).

import numpy as np

Digitize will get the bin indices for each element (0...k-1):

out = np.digitize(image, bins=T)

Now we map the indices to grayscale color:

out = out*int(255/(k-1))