commit 06382e5fdf8e8e4a73fe0c39361e364ce622d69c
Author: Mann Patel <130435633+MannPatel0@users.noreply.github.com>
Date: Tue Jul 9 09:17:57 2024 -0600
Initial commit
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..dfe0770
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/Project.iml b/.idea/Project.iml
new file mode 100644
index 0000000..2c80e12
--- /dev/null
+++ b/.idea/Project.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..e4e0c8b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..74f1bcb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6a6d17d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Mann Patel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..37248dc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# Project
+ RoboCup SSL
diff --git a/Template.jpg b/Template.jpg
new file mode 100644
index 0000000..a8fd926
Binary files /dev/null and b/Template.jpg differ
diff --git a/Test1.mp4 b/Test1.mp4
new file mode 100644
index 0000000..7d321c9
Binary files /dev/null and b/Test1.mp4 differ
diff --git a/Test2.mp4 b/Test2.mp4
new file mode 100644
index 0000000..2f73edc
Binary files /dev/null and b/Test2.mp4 differ
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..ffd9b1e
--- /dev/null
+++ b/main.py
@@ -0,0 +1,145 @@
+import cv2
+import numpy as np
+from scipy.spatial import distance as dist, distance
+import copy
+
+
+# Initialize empty lists for robots and ID markings
+robotList = []
+robotMarks = []
+
+
+
+class Robot:
+ def __init__(self, pos=None, team='-no team!-', ID='-no ID!-'):
+ # Initialize with default empty list if pos is not provided
+ self.pos = pos if pos is not None else []
+ self.team = team
+ self.ID = ID
+ self.circles = [] # ID markings [x, y, color]
+
+ def add_marking(self, circle=None):
+ # Initialize with default circle if none is provided
+ if circle is None:
+ circle = [0, 0, [0, 0, 0]]
+ self.circles.append(circle)
+
+class Ball:
+ def __init__(self, pos=None):
+ # Initialize with default empty list if pos is not provided
+ self.pos = pos if pos is not None else []
+
+# Initialize the ball with default position
+ball = Ball()
+
+def Color_Detection(blue, green, red):
+ if blue > 220 and green < 50 and red < 50:
+ return 'Blue'
+ if blue < 50 and green > 200 and red > 200:
+ return 'Yellow'
+ if blue > 200 and green < 50 and red > 200:
+ return 'Purple'
+ if blue < 50 and green > 220 and red < 50:
+ return 'Green'
+ if blue < 50 and green < 200 and red > 220:
+ return 'Orange'
+ return 'Unidentified'
+
+
+def IdentifyCircles(img, circle):
+ global ball
+
+ x, y = int(circle[0]), int(circle[1])
+ blue, green, red = img[y, x, 0], img[y, x, 1], img[y, x, 2]
+ color = Color_Detection(blue, green, red)
+
+ if color == 'Blue' or color == 'Yellow':
+ robotList.append(Robot([x, y], color))
+ elif color == 'Green' or color == 'Purple':
+ robotMarks.append([x, y, color])
+ print('ROBOT FOUND')
+ elif color == 'Orange':
+ ball = Ball([x, y])
+
+
+def assignIDmarks():
+ if robotList is not None:
+ for idx, robot in enumerate(robotList):
+ distances = []
+
+ for i, mark in enumerate(robotMarks):
+ mark_dist = distance.euclidean(mark[:2], robot.pos)
+ distances.append((i, mark_dist))
+ distances.sort(key=lambda x: x[1])
+ closest_marks_indices = [i for i, _ in distances[:4]]
+ robot.circles = [robotMarks[i] for i in closest_marks_indices]
+ robot.ID = idx + 1
+
+
+def detect_circles(image):
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
+ blurred = cv2.GaussianBlur(gray, (9, 9), 0)
+ circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, 1, minDist=20, param1=50, param2=14, minRadius=15, maxRadius=25)
+ return circles
+
+def annotate_image(img):
+ for robot in robotList:
+ team_color = "B" if robot.team == 'Blue' else "Y"
+ cv2.putText(img, f'{team_color}', (robot.pos[0] + 20, robot.pos[1] - 40), cv2.FONT_HERSHEY_SIMPLEX, .75, (255, 255, 255), 2, cv2.LINE_AA)
+ cv2.putText(img, f'ID{robot.ID}', (robot.pos[0] + 20, robot.pos[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, .75, (255, 255, 255), 2, cv2.LINE_AA)
+ cv2.putText(img, f'{robot.pos}', (robot.pos[0] + 20, robot.pos[1]), cv2.FONT_HERSHEY_SIMPLEX, .75, (255, 255, 255), 2, cv2.LINE_AA)
+ # Assuming orientation and other details are part of robot attributes
+
+ if ball:
+ cv2.putText(img, f'Ball {ball.pos}', (ball.pos[0] + 20, ball.pos[1] + 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)
+
+# Main function
+def main():
+ global robotList, robotMarks, ball
+
+ # Initialize globals
+ robotList = []
+ robotMarks = []
+ ball = None
+
+ # Load and process the image
+ imgpath = "/Users/mannpatel/Desktop/Project/Template.jpg"
+ img = cv2.imread(imgpath)
+ cv2.imshow("Original Image", img)
+
+ # Detect circles in the image
+ circles = detect_circles(img)
+
+ if circles is not None:
+ circles = np.uint16(np.around(circles))
+ for circle in circles[0, :]:
+ IdentifyCircles(img, circle)
+ cv2.circle(img, (circle[0], circle[1]), circle[2], (0, 255, 0), 2)
+ cv2.circle(img, (circle[0], circle[1]), 2, (0, 0, 255), 3)
+
+ assignIDmarks()
+
+ for robot in robotList:
+ print(f'There is a {robot.team} robot with these ID circles:')
+ for mark in robot.circles:
+ print(mark)
+
+ if ball:
+ print(f'Ball found at {ball.pos}')
+
+ for robot in robotList:
+ cv2.circle(img, (robot.pos[0], robot.pos[1]), 10, (0, 0, 0), 5)
+ for mark in robot.circles:
+ cv2.circle(img, (mark[0], mark[1]), 10, (0, 0, 0), 5)
+
+ else:
+ print("No circles detected")
+
+ annotate_image(img)
+ cv2.imshow("Annotated Image", img)
+ cv2.waitKey(0)
+ cv2.destroyAllWindows()
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/main1.py b/main1.py
new file mode 100644
index 0000000..8a2f362
--- /dev/null
+++ b/main1.py
@@ -0,0 +1,145 @@
+import cv2
+import numpy as np
+from scipy.spatial import distance as dist
+
+# Initialize empty lists for robots and ID markings
+robotList = []
+robotMarks = []
+
+class Robot:
+ def __init__(self, pos=None, team='-no team!-', ID='-no ID!-'):
+ self.pos = pos if pos is not None else []
+ self.team = team
+ self.ID = ID
+ self.circles = [] # ID markings [x, y, color]
+
+ def add_marking(self, circle=None):
+ if circle is None:
+ circle = [0, 0, [0, 0, 0]]
+ self.circles.append(circle)
+
+class Ball:
+ def __init__(self, pos=None):
+ self.pos = pos if pos is not None else []
+
+# Initialize the ball with default position
+ball = Ball()
+
+def Color_Detection(blue, green, red):
+ if blue > 220 and green < 50 and red < 50:
+ return 'Blue'
+ if blue < 50 and green > 200 and red > 200:
+ return 'Yellow'
+ if blue > 200 and green < 50 and red > 200:
+ return 'Purple'
+ if blue < 50 and green > 220 and red < 50:
+ return 'Green'
+ if blue < 50 and green < 200 and red > 220:
+ return 'Orange'
+ return 'Unidentified'
+
+def IdentifyCircles(img, circle):
+ global ball
+
+ x, y = int(circle[0]), int(circle[1])
+ blue, green, red = img[y, x, 0], img[y, x, 1], img[y, x, 2]
+ color = Color_Detection(blue, green, red)
+
+ if color == 'Blue' or color == 'Yellow':
+ robotList.append(Robot([x, y], color))
+ elif color == 'Green' or color == 'Purple':
+ robotMarks.append([x, y, color])
+ print('ROBOT FOUND')
+ elif color == 'Orange':
+ ball = Ball([x, y])
+
+def assignIDmarks():
+ if robotList is not None:
+ for idx, robot in enumerate(robotList):
+ distances = []
+
+ for i, mark in enumerate(robotMarks):
+ mark_dist = dist.euclidean(mark[:2], robot.pos)
+ distances.append((i, mark_dist))
+ distances.sort(key=lambda x: x[1])
+ closest_marks_indices = [i for i, _ in distances[:4]]
+ robot.circles = [robotMarks[i] for i in closest_marks_indices]
+ robot.ID = idx + 1
+
+def detect_circles(image):
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
+ blurred = cv2.GaussianBlur(gray, (9, 9), 0)
+ circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, 1, minDist=20, param1=50, param2=14, minRadius=15, maxRadius=50)
+ return circles
+
+def annotate_image(img):
+ for robot in robotList:
+ team_color = "B" if robot.team == 'Blue' else "Y"
+ cv2.putText(img, f'{team_color}', (robot.pos[0] + 20, robot.pos[1] - 40), cv2.FONT_HERSHEY_SIMPLEX, .75, (255, 255, 255), 2, cv2.LINE_AA)
+ cv2.putText(img, f'ID{robot.ID}', (robot.pos[0] + 20, robot.pos[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, .75, (255, 255, 255), 2, cv2.LINE_AA)
+ cv2.putText(img, f'{robot.pos}', (robot.pos[0] + 20, robot.pos[1]), cv2.FONT_HERSHEY_SIMPLEX, .75, (255, 255, 255), 2, cv2.LINE_AA)
+
+ if ball:
+ cv2.putText(img, f'Ball {ball.pos}', (ball.pos[0] + 20, ball.pos[1] + 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)
+
+# Main function
+def main():
+ global robotList, robotMarks, ball
+
+ # Initialize globals
+ robotList = []
+ robotMarks = []
+ ball = None
+
+ # Load and process the video
+ video_path = "/Test2.mp4"
+ cap = cv2.VideoCapture(video_path)
+
+ while cap.isOpened():
+ ret, frame = cap.read()
+ if not ret:
+ break
+
+ # Reset robot and mark lists for each frame
+ robotList = []
+ robotMarks = []
+
+ # Detect circles in the frame
+ circles = detect_circles(frame)
+
+ if circles is not None:
+ circles = np.uint16(np.around(circles))
+ for circle in circles[0, :]:
+ IdentifyCircles(frame, circle)
+ cv2.circle(frame, (circle[0], circle[1]), circle[2], (0, 255, 0), 2)
+ cv2.circle(frame, (circle[0], circle[1]), 2, (0, 0, 255), 3)
+
+ assignIDmarks()
+
+ for robot in robotList:
+ print(f'There is a {robot.team} robot with these ID circles:')
+ for mark in robot.circles:
+ print(mark)
+
+ if ball:
+ print(f'Ball found at {ball.pos}')
+
+ for robot in robotList:
+ cv2.circle(frame, (robot.pos[0], robot.pos[1]), 10, (0, 0, 0), 5)
+ for mark in robot.circles:
+ cv2.circle(frame, (mark[0], mark[1]), 10, (0, 0, 0), 5)
+
+ else:
+ print("No circles detected")
+
+ annotate_image(frame)
+ cv2.imshow("Annotated Video", frame)
+
+ if cv2.waitKey(1) & 0xFF == ord('q'):
+ break
+
+ cap.release()
+ cv2.destroyAllWindows()
+
+if __name__ == "__main__":
+ main()