2

I have an image, in which I want to threshold part of the image within a circular region, and then the remainder of the image outside of this region.

Unfortunately my attempts seem to be thresholding the image as a whole, ignoring the masks. How can this be properly achieved? See code attempt below.

def circular_mask(h, w, centre=None, radius=None):
    if centre is None:  # use the middle of the image
        centre = [int(w / 2), int(h / 2)]
    if radius is None:  # use the smallest distance between the centre and image walls
        radius = min(centre[0], centre[1], w - centre[0], h - centre[1])

    Y, X = np.ogrid[:h, :w]
    dist_from_centre = np.sqrt((X - centre[0]) ** 2 + (Y - centre[1]) ** 2)

    mask = dist_from_centre <= radius
    return mask

img = cv2.imread('image.png', 0) #read image

h,w = img.shape[:2]
mask = circular_mask(h,w, centre=(135,140),radius=75) #create a boolean circle mask
mask_img = img.copy()

inside = np.ma.array(mask_img, mask=~mask)
t1 = inside < 50 #threshold part of image within the circle, ignore rest of image
plt.imshow(inside)
plt.imshow(t1, alpha=.25)
plt.show()

outside = np.ma.array(mask_img, mask=mask)
t2 = outside < 20 #threshold image outside circle region, ignoring image in circle
plt.imshow(outside)
plt.imshow(t2, alpha=.25)
plt.show()

fin = np.logical_or(t1, t2) #combine the results from both thresholds together
plt.imshow(fin)
plt.show()

Working solution:

img = cv2.imread('image.png', 0)

h,w = img.shape[:2]
mask = circular_mask(h,w, centre=(135,140),radius=75)


inside = img.copy()*mask
t1 = inside < 50#get_threshold(inside, 1)
plt.imshow(inside)
plt.show()

outside =  img.copy()*~mask
t2 = outside < 70
plt.imshow(outside)
plt.show()

plt.imshow(t1)
plt.show()
plt.imshow(t2)
plt.show()

plt.imshow(np.logical_and(t1,t2))
plt.show()
Sam
  • 1,052
  • 4
  • 13
  • 33
  • When you talk about *applying tresholds to images*, what do you mean by it? Could you give a graphics example of what is your expected output? Compared to the [OpenCV tresholding tutorial](http://docs.opencv.org/trunk/d7/d4d/tutorial_py_thresholding.html), it looks like you want to do something completely different. – EsotericVoid Aug 14 '17 at 15:40
  • @Bit Currently I am just using boolean logic to look for pixels under a certain value. Eg `img < 50' returns True where the pixels are dark enough. I would like to expand this to otsu binarisation thresholding but the procedure should be similar to the above example. My thresholding should return True where the condition is met, else False. – Sam Aug 14 '17 at 15:43

1 Answers1

0

I assume your image is single layered (e.g. Grey Scale). You can make 2 copies of the image. Multiply (or Logical AND) your mask with one of them and invert of that mask with the other one. Now apply your desired threshold to each of them. In the end merge both images using Logical OR operation.

Muhammad Abdullah
  • 876
  • 2
  • 8
  • 26
  • I had to use multiplication instead of logic operations for mask, and had to merge both images using AND. With this, your method worked great, thank you. – Sam Aug 15 '17 at 08:29