python-3.ximagematplotlibimage-processingimage-thresholding

Is there a way to apply a threshold to an image 1 row at a time


I am trying to apply a threshold to an image 1 row at a time. I want to be able to select the the row the threshold would begin and end. Ex. if I have a 1000 x 1000 image I would like to apply my threshold beginning at row 200 and end at row 850. Currently I am able to apply a threshold to an entire image.

img = cv2.imread("*.png",0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

titles = ['Original Image','BINARY']
images = [img, thresh1]

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

Solution

  • There are couple of ways of doing this, so I'll go from simplest and fastest, to more flexible and slower...

    Simplest and fastest, if your masked area is very simple like yours:

    import cv2
    import numpy as np
    
    # Load Paddington as greyscale
    img = cv2.imread('paddington.png',0)
    
    # Define a region of interest, in this case entire rows 100-300
    ROI = slice(100,300) 
    
    # Threshold the region of interest, and reinsert back into image
    ret,img[ROI] = cv2.threshold(img[ROI],127,255,cv2.THRESH_BINARY)  
    

    enter image description here

    Notice I declared the ROI as a variable in just one place so that both sides of the equals sign remain correct if you change the mask's size - maintenance issue avoidance!


    If your masked area was not entire rows, you could create a tuple of slices:

    # Declare ROI
    ROI = slice(100,300),slice(10,390)
    
    # Threshold with mask
    ret,img[ROI] = cv2.threshold(img[ROI],127,255,cv2.THRESH_BINARY)
    

    enter image description here


    If your masked area is more complicated, e.g. compound shapes, an outline or circular, you can still threshold only the masked region of interest! First you create a mask the same size filled with black, then draw your shapes in white and then apply the threshold to the masked region of interest:

    # Make a mask the same size as the image and fill with black
    mask = np.zeros_like(img)
    
    # Draw a filled white circle onto the black mask to define a region of interest
    mask = cv2.circle(mask,(200,100),100,255,-1) # -1 to fill inside circle 
    ROI = np.nonzero(mask)
    
    # Threshold the region of interest, and reinsert back into image
    ret, mask_thresholded = cv2.threshold(img[ROI],127,255,cv2.THRESH_BINARY) 
    img[ROI] = mask_thresholded.reshape(-1)
    

    enter image description here


    Here is the original image of the young rogue:

    enter image description here

    Keywords: Python, OpenCV, Numpy, image, image processing, mask, masked, threshold, filter, ROI, region of interest