Search code examples
pythonopencvimage-processingcolorsgeometry

Detecting a specific color in a circular area and adding horizontal lines inside the circle


I was working to reproduce an optical illusion that you find here(image) but I having trouble adding horizontal lines inside of the circles: My attempt so far:

-Detect the certain colors of the circles

-Detect contours, and extract circle center points, and radius

-Then try to draw horizontal lines (which I failed)

Here is my code:

import numpy as np
import cv2

img = 255*np.ones((800, 800, 3), np.uint8)
height, width,_ = img.shape

#filling the image with lines
for i in range(0, height, 15):
    cv2.line(img, (0, i+3), (width, i+3), (255, 0, 0), 4)
    cv2.line(img, (0, i+8), (width, i+8), (0, 255, 0), 4)
    cv2.line(img, (0, i+13), (width, i+13), (0, 0, 255), 4)

#adding 5 gray circles
for i in range(0, height, int(height/5)):
        cv2.circle(img, (i+50, i+50), 75, (128, 128, 128), -1) 
#finding rannge of gray circles
lower=np.array([127,127,127])
upper=np.array([129,129,129])
mask = cv2.inRange(img, lower, upper)

#contours
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    #draw circles around the contours
    coordinates = cv2.minEnclosingCircle(cnt)
     #coordinates and radius:
    center = (int(coordinates[0][0]), int(coordinates[0][1]))
    radius = int(coordinates[1])
    #I wanted to do a sanity check before the for loop (I added a line the longest line should be 2*radius)
    cv2.line(img, (center[0]-radius, center[1]), (center[0]+radius, center[1]), (0, 0, 0), 4)
    
    for i in range(0, radius, int(radius/5)):
        cv2.line(img, (center[0]-radius+i, center[1]+i), (center[0]+radius-i, center[1]+i), (0, 0, 0), 4)
        cv2.line(img, (center[0]-radius+i, center[1]-i), (center[0]+radius-i, center[1]-i), (0, 0, 0), 4)
        

cv2.imwrite('munker.png',img)

And here is the result: enter image description here

As you can see the values in the for loop are not proportional to the boundaries of the circle, so the lines are short(except the longest line). What am I missing here?

I tried the Hough transform but I had a similar problem.

For more clarity, I write a code to show what I wanted:

 for i in range(0, 360, 15):
        x = int(center[0] + radius * np.cos(np.deg2rad(i)))
        y = int(center[1] + radius * np.sin(np.deg2rad(i)))
        cv2.line(img, (x,y), (x, y), (0, 255, 255), 10)

img

I want to merge the yellow dots with horizontal lines. But my math is finished right here. Sorry, it's long, I was just trying to make things clear. Thank you for your time.


Solution

  • As @fmw42 pointed out in the comment, splitting the RGB channels and applying a mask is very effective at being able to fill the inside of the circles with horizontal lines.

    import numpy as np
    import cv2
    
    img = 255*np.ones((800, 800, 3), np.uint8)
    height, width,_ = img.shape
    for i in range(0, height, 15):
        cv2.line(img, (0, i+3), (width, i+3), (255, 0, 0), 4)
        cv2.line(img, (0, i+8), (width, i+8), (0, 255, 0), 4)
        cv2.line(img, (0, i+13), (width, i+13), (0, 0, 255), 4)
    b, g, r = cv2.split(img)
    mask_b = np.zeros((height, width), np.uint8)
    mask_g = np.zeros((height, width), np.uint8)
    mask_r = np.zeros((height, width), np.uint8)
    for i in range(0, height, int(height/5)):
        cv2.circle(mask_b, (i, i), 75, 255, -1)
        cv2.circle(mask_g, (i, i), 75, 255, -1)
        cv2.circle(mask_r, (i, i), 75, 255, -1)
    
    #apply the mask to the channels
    b = cv2.bitwise_and(b, b, mask=mask_b)
    g = cv2.bitwise_and(g, g, mask=mask_g)
    r = cv2.bitwise_and(r, r, mask=mask_r)
    #merge the channels
    img = cv2.merge((b, g, r))
    
    cv2.imshow('image', img)
    cv2.waitKey(0)