Search code examples
pythonopencvimage-thresholding

Python OpenCV thresholding by logical indexing


I am trying to threshold certain values in a grayscale image. So far I have been successful by inputting certain ranges of numbers, but I want to take the values that are between 50 and 150 and multiply them by 1.2. I am not sure how I can access the number within the vector to then multiply it by 1.2.

myimg[myimg <= 50] = 0
myimg[myimg > 150 ] = 255
myimg[50<myimg<=150] = myimg * 1.2 #this line produces this error: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Solution

  • Here are three possible ways to do that.

    The first simply multiplies the image by the factor 1.2 and the threshold values by a factor of 1.2 and uses the new threshold values.

    The second multiplies the image by the factor 1.2, creates a mask from the threshold value. The uses the mask the to make the image black and white in the desired regions.

    The third method does more like what you want without having to process the whole image.

    Input (linear gradient image):

    enter image description here

    import cv2
    import numpy as np
    
    # read image as grayscale
    img = cv2.imread('grad.png', cv2.COLOR_BGR2GRAY)
    
    # Method 1
    
    # set threshold values
    tlow = 50
    thigh = 150
    
    # multiply image by 1.2
    result1 = img.copy()
    result1 = (1.2 * result1).clip(0,255).astype(np.uint8)
    
    # compute modified threshold values
    tlow = int(1.2 * tlow)
    thigh = int(1.2 * thigh)
    result1[result1 <= tlow] = 0
    result1[result1 > thigh ] = 255
    print(tlow, thigh)
    
    
    # Method 2
    
    # set threshold values
    tlow = 50
    thigh = 150
    
    # create mask that is black outside the desired range and white inside the desired range
    mask = img.copy()
    mask[mask <= tlow] = 0
    mask[mask > thigh ] = 255
    
    # modify input by 1.2 factor
    result2 = img.copy()
    result2 = (1.2 * result2).clip(0,255).astype(np.uint8)
    
    # use mask to combine the input and the modified image
    result2[mask==0] = 0
    result2[mask==255] = 255
    
    # method 3
    
    # set threshold values
    tlow = 50
    thigh = 150
    
    result3 = img.copy()
    result3[result3 <= tlow] = 0
    result3[result3 > thigh ] = 255
    result3 = result3.astype(np.float32)
    result3[(result3>50) & (result3<=150)] *= 1.2
    result3 = result3.clip(0,255).astype(np.uint8)
    
    # save result
    cv2.imwrite("grad_process1.png", result1)
    cv2.imwrite("grad_mask.png", mask)
    cv2.imwrite("grad_process2.png", result2)
    cv2.imwrite("grad_process3.png", result3)
    
    # view result
    cv2.imshow("result1", result1)
    cv2.imshow("mask", mask)
    cv2.imshow("result2", result2)
    cv2.imshow("result3", result3)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    


    Result 1:

    enter image description here

    Result 2:

    enter image description here

    Result 3:

    enter image description here