2

I have this image of a bunch of circles, all different colors (red, green, yellow, purple, etc.). I would like to individually crop all the red circles and save them as separate files (ex. circle(1).png, circle(2).png, etc.).

What I have so far is a solution to only show the red circles. I created a mask with cv2.inRange and used a cv2.bitwise_and to only show the red circles. Here is my code:

import cv2 
import numpy as np


image = cv2.imread('dots.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

lower_red = np.array([150,100,0])
upper_red = np.array([255,255,255])

 # Threshold the HSV image to get only red cirlces
mask = cv2.inRange(hsv, lower_red, upper_red)

# Bitwise-AND mask and original image
res = cv2.bitwise_and(image,image, mask=mask)

I guess what I'm looking for is something like cv2.selectROI() but runs automatically (no manual click&drag) and can crop multiple regions. Any ideas or tips appreciated. Thanks

Nafeez Quraishi
  • 5,380
  • 2
  • 27
  • 34
FestiveHydra235
  • 473
  • 1
  • 7
  • 23
  • Since you already have a mask you can do this: https://answers.opencv.org/question/4183/what-is-the-best-way-to-find-bounding-box-for-binary-mask/ –  Jul 16 '19 at 17:17
  • you forgot to add image. – Anubhav Singh Jul 16 '19 at 19:48
  • See also https://stackoverflow.com/questions/56136367/how-to-get-region-properties-from-image-that-is-already-labeled-in-opencv/57063719#57063719 – fmw42 Jul 17 '19 at 00:34

1 Answers1

2

For red, you can choose the HSV range (0,50,20) ~ (5,255,255) and (175,50,20)~(180,255,255) using the colormap given here. Your mask in above code won't detect both red circles in below image, for example. Check this yourself.

You can try below code:

import cv2 
import numpy as np

image = cv2.imread('circles.jpg')
img_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Gen lower mask (0-5) and upper mask (175-180) of RED
mask1 = cv2.inRange(img_hsv, (0,50,20), (5,255,255))
mask2 = cv2.inRange(img_hsv, (175,50,20), (180,255,255))

# Merge the mask and crop the red regions
mask = cv2.bitwise_or(mask1, mask2)

# Bitwise-AND mask and original image
res = cv2.bitwise_and(image,image, mask=mask)

# coverting image with red colored region of interest from HSV to RGB
hsv2bgr = cv2.cvtColor(res, cv2.COLOR_HSV2BGR)

# RGB to GRAYSCALE
rgb2gray = cv2.cvtColor(hsv2bgr, cv2.COLOR_BGR2GRAY)

# Applying thresholding to the grayscale image for black & white color
thresh_gray = cv2.threshold(rgb2gray, 20,255, cv2.THRESH_BINARY)[1]

# Find the different contours
contours = cv2.findContours(rgb2gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
#print(len(contours))

i = 0
for c in contours:
    _, radius = cv2.minEnclosingCircle(c)

    if radius>10:
        # create a mask and fill it with white color
        mask = np.zeros(image.shape, dtype=np.uint8)
        cv2.fillPoly(mask, pts=[c], color=(255, 255, 255))

        # Bitwise-AND mask and original image 
        # output is red circle with black background
        masked_image = cv2.bitwise_and(image, mask)

        # to get individual red circle with white background
        mask_ = cv2.bitwise_not(mask) 
        circle_ = cv2.bitwise_or(masked_image, mask_)

        cv2.imwrite('circle({}).jpg'.format(i), circle_)
        i+=1

Input Image: circles.jpg

enter image description here

There are two red circle object in the above input image, hence it will create two files- circle(0).jpg and circle(1).jpg each with individual red circles.

Anubhav Singh
  • 8,321
  • 4
  • 25
  • 43