OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Python - OpenCV - Is there a way to "Fill" an expected contour?

  • Thread starter Thread starter Klaidon
  • Start date Start date
K

Klaidon

Guest
I want to detect the contour of a ball and the object will always be a ball, but i have an object in the middle that can obstruct part of the ball, here's my current situation : (https://i.sstatic.net/gwxnsVTI.png)

I made it so it works just fine in this case where theres a good amount of the ball on both sides, but when it reduces its not as good: (https://i.sstatic.net/gYiZ9bCI.png)

I know I can change the parameters of my code where I just concatenate both parts when they are of a good enough size, but it gets very situational when it works because of the noise, so I can't reduce the parameters that much:

Code:
import cv2
import numpy as np
from pyfirmata2 import Arduino, SERVO
import time
import serial



# Camera Connection/Setup
cap = cv2.VideoCapture(0)


while True:
    _, frame = cap.read()
    hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    
    #Blue color
    low_blue = np.array([100, 100, 20])
    high_blue = np.array([200, 255, 255])
    blue_mask = cv2.inRange(hsv_frame, low_blue, high_blue)
    #blue_mask = cv2.GaussianBlur(blue_mask,(5,5),0)
    contours, hierarchy = cv2.findContours(blue_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    contours = sorted(contours, key=lambda x:cv2.contourArea(x), reverse=True)

    sum = 0
    emptymask = []
    for cnt in contours:
        if cv2.contourArea(cnt) > 300: #If the parts are big enough it assumes its a part of the ball
            sum += cv2.contourArea(cnt)
            emptymask.append(cnt)

    #print(sum)
    emptymask = cv2.vconcat(emptymask)

    (x, y, w, h) = cv2.boundingRect(emptymask)
   
    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    
    cv2.imshow("Frame", frame)
    cv2.imshow("Mask", blue_mask)

    
    key = cv2.waitKey(1)
    if key == 27:
        break
        

cap.release()
cv2.destroyAllWindows()

So I was thinking wether I can sort of deduce the ball based on its size or something like that, since it's always the same ball. I did do something like that in another code where if it's not the size expected, it "guesses" the whole ball and makes a square, but it became incredibly hard to calibrate the exact x and y positions:

Code:
if reference > 6000: #See if the object is cropped or not
        cv2.rectangle(frame, (x, y), (x + w, y + w), (0, 255, 0), 2)
    elif ((x>180 and x<230) and (y>170 and y<240) or (y<5 and x<225)):                #If it is, it will calculate the rest of the area
        cv2.rectangle(frame, (x+ball_diameter, y+h), (x, y+h - ball_diameter), (0, 255, 0), 2)
    elif (x>230 and x<290) and (y>140 and y<170):                #If it is, it will calculate the rest of the area
        cv2.rectangle(frame, (x+w, y+ball_diameter), (x+w - ball_diameter, y), (0, 255, 0), 2)
    elif (x>270 and x<300 and (y<140 or y>230)) or (y>220 and y<250) or (y<5 and x>225):                #If it is, it will calculate the rest of the area
        cv2.rectangle(frame, (x+w, y+h), (x+w - ball_diameter, y+h - ball_diameter), (0, 255, 0), 2)
    else:
        cv2.rectangle(frame, (x, y), (x + ball_diameter, y + ball_diameter), (0, 255, 0), 2)

Finally, my question is : Is there a way to detect the arch from either side and just fill the missing circle gap ? Or an even better way ?
<p>I want to detect the contour of a ball and the object will always be a ball, but i have an object in the middle that can obstruct part of the ball, here's my current situation :
(<a href="https://i.sstatic.net/gwxnsVTI.png" rel="nofollow noreferrer">https://i.sstatic.net/gwxnsVTI.png</a>)</p>
<p>I made it so it works just fine in this case where theres a good amount of the ball on both sides, but when it reduces its not as good:
(<a href="https://i.sstatic.net/gYiZ9bCI.png" rel="nofollow noreferrer">https://i.sstatic.net/gYiZ9bCI.png</a>)</p>
<p>I know I can change the parameters of my code where I just concatenate both parts when they are of a good enough size, but it gets very situational when it works because of the noise, so I can't reduce the parameters that much:</p>
<pre><code>import cv2
import numpy as np
from pyfirmata2 import Arduino, SERVO
import time
import serial



# Camera Connection/Setup
cap = cv2.VideoCapture(0)


while True:
_, frame = cap.read()
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

#Blue color
low_blue = np.array([100, 100, 20])
high_blue = np.array([200, 255, 255])
blue_mask = cv2.inRange(hsv_frame, low_blue, high_blue)
#blue_mask = cv2.GaussianBlur(blue_mask,(5,5),0)
contours, hierarchy = cv2.findContours(blue_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=lambda x:cv2.contourArea(x), reverse=True)

sum = 0
emptymask = []
for cnt in contours:
if cv2.contourArea(cnt) > 300: #If the parts are big enough it assumes its a part of the ball
sum += cv2.contourArea(cnt)
emptymask.append(cnt)

#print(sum)
emptymask = cv2.vconcat(emptymask)

(x, y, w, h) = cv2.boundingRect(emptymask)

cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)


cv2.imshow("Frame", frame)
cv2.imshow("Mask", blue_mask)


key = cv2.waitKey(1)
if key == 27:
break


cap.release()
cv2.destroyAllWindows()

</code></pre>
<p>So I was thinking wether I can sort of deduce the ball based on its size or something like that, since it's always the same ball.
I did do something like that in another code where if it's not the size expected, it "guesses" the whole ball and makes a square, but it became incredibly hard to calibrate the exact x and y positions:</p>
<pre><code>if reference > 6000: #See if the object is cropped or not
cv2.rectangle(frame, (x, y), (x + w, y + w), (0, 255, 0), 2)
elif ((x>180 and x<230) and (y>170 and y<240) or (y<5 and x<225)): #If it is, it will calculate the rest of the area
cv2.rectangle(frame, (x+ball_diameter, y+h), (x, y+h - ball_diameter), (0, 255, 0), 2)
elif (x>230 and x<290) and (y>140 and y<170): #If it is, it will calculate the rest of the area
cv2.rectangle(frame, (x+w, y+ball_diameter), (x+w - ball_diameter, y), (0, 255, 0), 2)
elif (x>270 and x<300 and (y<140 or y>230)) or (y>220 and y<250) or (y<5 and x>225): #If it is, it will calculate the rest of the area
cv2.rectangle(frame, (x+w, y+h), (x+w - ball_diameter, y+h - ball_diameter), (0, 255, 0), 2)
else:
cv2.rectangle(frame, (x, y), (x + ball_diameter, y + ball_diameter), (0, 255, 0), 2)


</code></pre>
<p>Finally, my question is : Is there a way to detect the arch from either side and just fill the missing circle gap ? Or an even better way ?</p>
 

Latest posts

Top