2

I was wondering if there was a way in openCV that would allow me to crop image between two circles, in a way that ignores everything in the smaller inner circle and everything outside of the larger circle. Like a donut shape.

lenik
  • 23,228
  • 4
  • 34
  • 43
JaK
  • 21
  • 1
  • 2
  • Post an example image. Are the two circles depicted in the image or do you just know the common center and the the two radii or diameters? – fmw42 Apr 30 '20 at 06:05

2 Answers2

7

Here is one way to do that in Python/OpenCV.

  • Read the input and get its dimensions
  • Define the radii of the two circles and the center coordinates
  • Create a white filled circle mask on a black background for each radius
  • Subtract the smaller radius mask from the larger radius mask
  • Put the resulting mask image into the alpha channel of the input
  • save the results

Input:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread('lena.jpg')
hh, ww = img.shape[:2]
hh2 = hh // 2
ww2 = ww // 2

# define circles
radius1 = 25
radius2 = 75
xc = hh // 2
yc = ww // 2

# draw filled circles in white on black background as masks
mask1 = np.zeros_like(img)
mask1 = cv2.circle(mask1, (xc,yc), radius1, (255,255,255), -1)
mask2 = np.zeros_like(img)
mask2 = cv2.circle(mask2, (xc,yc), radius2, (255,255,255), -1)

# subtract masks and make into single channel
mask = cv2.subtract(mask2, mask1)

# put mask into alpha channel of input
result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
result[:, :, 3] = mask[:,:,0]

# save results
cv2.imwrite('lena_mask1.png', mask1)
cv2.imwrite('lena_mask2.png', mask2)
cv2.imwrite('lena_masks.png', mask)
cv2.imwrite('lena_circle_masks.png', result)

cv2.imshow('image', img)
cv2.imshow('mask1', mask1)
cv2.imshow('mask2', mask2)
cv2.imshow('mask', mask)
cv2.imshow('masked image', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Smaller radius mask:

enter image description here

Larger radius mask:

enter image description here

Difference mask:

enter image description here

Resulting image:

enter image description here

fmw42
  • 46,825
  • 10
  • 62
  • 80
0

You should use masks. Create an empty image of the same size, draw the larger circle with value '1', then the smaller with value '0', you'll get a "donut", then use that donut as a mask to copy the part of your image you're interested in.

This might help as a tutorial: https://note.nkmk.me/en/python-opencv-numpy-alpha-blend-mask/

lenik
  • 23,228
  • 4
  • 34
  • 43
  • After applying the method mentioned in that tutorial, is it possible to remove alpha channel? I need a 2D image but I am getting a 3D one – İpek Nov 01 '22 at 08:15