Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
yolo-centering-task.py
2
3import visp
4from visp.core import ColVector, Point, Color, PixelMeterConversion, Display
5from visp.core import CameraParameters, HomogeneousMatrix , ExponentialMap, PoseVector
6
7from visp.core import ImageRGBa
8from visp.robot import ImageSimulator
9from visp.visual_features import BasicFeature, FeaturePoint
10from visp.vs import Servo
11from visp.python.display_utils import get_display
12
13
14try:
15 from ultralytics import YOLO
16except ImportError:
17 print('This example requires yoloV8: pip install ultralytics')
18
19import time
20from PIL import Image
21import numpy as np
22import matplotlib.pyplot as plt
23from matplotlib import animation
24import argparse
25
26plt.rcParams['text.usetex'] = True
27
28def get_simulator(scene_path: str) -> ImageSimulator:
29 scene_image = np.asarray(Image.open(scene_path).convert('RGBA'))
30 scene_image = ImageRGBa(scene_image)
31 simulator = ImageSimulator() # Planar scene from single image
32 l, L = 1.5, 1.0
33 scene_3d = [
34 [-l, -L, 0.0], [l, -L, 0.0],
35 [l, L, 0.0], [-l, L, 0.0],
36 ]
37 simulator.init(scene_image, list(map(lambda X: Point(X), scene_3d)))
38 simulator.setCleanPreviousImage(True, color=Color.black)
39 simulator.setInterpolationType(ImageSimulator.InterpolationType.BILINEAR_INTERPOLATION)
40 return simulator
41
42class VSPlot(object):
43 def __init__(self):
44 self.v = []
45 self.error = []
46 self.r = []
47 self.I = []
48
49 def on_iter(self, Idisp: ImageRGBa, v: ColVector, error: ColVector, cTw: HomogeneousMatrix) -> None:
50 self.I.append(Idisp.numpy().copy())
51 self.v.append(v.numpy()[3:5].flatten())
52 self.error.append(error.numpy().flatten())
53 self.r.append(PoseVector(cTw).numpy()[3:5].flatten())
54
55 def generate_anim(self):
56 self.error = np.asarray(self.error)[1:]
57 self.v = np.asarray(self.v)[1:]
58 self.r = np.asarray(self.r)[1:]
59
60
61 fig, axs = plt.subplots(2, 2, figsize=(15, 15 * (self.I[0].shape[0] / self.I[0].shape[1])))
62 axs = [axs[0][0], axs[0][1], axs[1][0],axs[1][1]]
63 titles = ['I', 'Feature error', 'Velocity', 'Pose']
64 legends = [
65 None,
66 [r"$x$", r"$y$"],
67 [r"$\mathbf{\upsilon}_x$", r"$\mathbf{\upsilon}_y$"],
68 [r"$\theta\mathbf{u}_x$", r"$\theta\mathbf{u}_y$"],
69 ]
70 data = [None, self.error, self.v, self.r]
71 artists = []
72 for i in range(len(axs)):
73 axs[i].set_title(titles[i])
74 if data[i] is not None:
75 axs[i].set_xlabel('Iteration')
76 axs[i].grid()
77 axs[i].set_xlim(0, len(self.v))
78 min_val, max_val = np.min(data[i]), np.max(data[i])
79 margin = (max_val - min_val) * 0.05
80 axs[i].set_ylim(min_val - margin, max_val + margin)
81 artists.append(axs[i].plot(data[i]))
82 axs[i].legend(legends[i])
83 else:
84 artists.append(axs[i].imshow(self.I[0]))
85 axs[i].set_axis_off()
86 plt.tight_layout()
87 def animate(i):
88 xs = range(i)
89 artists[0].set_data(self.I[i])
90 for j in range(2):
91 artists[1][j].set_data(xs, self.error[:i, j])
92 artists[2][j].set_data(xs, self.v[:i, j])
93 artists[3][j].set_data(xs, self.r[:i, j])
94 return artists
95
96 anim = animation.FuncAnimation(fig, animate, frames=len(self.v), blit=False, repeat=False)
97 writervideo = animation.FFMpegWriter(fps=20)
98 anim.save('exp.mp4', writer=writervideo)
99 plt.savefig('exp.pdf')
100 plt.close()
101
102if __name__ == '__main__':
103 parser = argparse.ArgumentParser('Centering task using a YOLO network')
104 parser.add_argument('--scene', type=str, help='Path to the scene')
105 parser.add_argument('--class-id', type=int, help='COCO class id of the object to track (e.g, 2 for a car)')
106 args = parser.parse_args()
107
108 detection_model = YOLO('yolov8n.pt')
109
110 h, w = 480, 640
111 Z = 3.0
112 cam = CameraParameters(px=600, py=600, u0=w / 2.0, v0=h / 2.0)
113
114
115 plotter = VSPlot()
116
117 # Initialization
118 simulator = get_simulator(args.scene)
119 cTw = HomogeneousMatrix(-0.1, 0.1, Z, 0.0, 0.0, 0.0)
120 I = ImageRGBa(h, w)
121 Idisp = ImageRGBa(h, w)
122 simulator.setCameraPosition(cTw)
123 simulator.getImage(I, cam)
124
125 # Define centering task
126 xd, yd = PixelMeterConversion.convertPoint(cam, w / 2.0, h / 2.0)
127 sd = FeaturePoint()
128 sd.buildFrom(xd, yd, Z)
129
130 s = FeaturePoint()
131 s.buildFrom(0.0, 0.0, Z)
132
133 task = Servo()
134 task.addFeature(s, sd)
135 task.setLambda(0.5)
136 task.setCameraDoF(ColVector([0, 0, 0, 1, 1, 0]))
137 task.setServo(Servo.ServoType.EYEINHAND_CAMERA)
138 task.setInteractionMatrixType(Servo.ServoIteractionMatrixType.CURRENT)
139 target_class = args.class_id # Car
140 print(target_class)
141
142 prev_v = ColVector(6, 0.0)
143 v = ColVector(6, 0.0)
144
145 d = get_display()
146 d.init(I)
147 Display.display(I)
148 Display.flush(I)
149 _ = detection_model(np.array(I.numpy()[..., 2::-1]))
150 error_norm = 1e10
151 # Servoing loop
152 while error_norm > 5e-7:
153 print('Error norm is', error_norm)
154 print('AAAAAAAAAAAAAA')
155 start = time.time()
156 # Data acquisition
157 simulator.getImage(I, cam)
159 return box.cls is not None and len(box.cls) > 0 and box.cls[0]
160
161 # Build current features
162 results = detection_model(np.array(I.numpy()[..., 2::-1]))[0] # Run detection
163 boxes = results.boxes
164 max_conf = 0.0
165 idx = -1
166 bb = None
167 for i in range(len(boxes.conf)):
168 if boxes.cls[i] == target_class and boxes.conf[i] > max_conf:
169 print('New max')
170 idx = i
171 max_conf = boxes.conf[i]
172 bb = boxes.xywh[i].cpu().numpy()
173 # boxes = filter(has_class_box, boxes)
174 # print('BOXES AFTER FILTER:', list(boxes))
175 # boxes = sorted(boxes, key=lambda box: box.conf[0])
176 # bbs = list(map(lambda box: box.xywh[0].cpu().numpy(), boxes))
177 if bb is not None:
178 u, v = bb[0], bb[1]
179 x, y = PixelMeterConversion.convertPoint(cam, u, v)
180 s.buildFrom(x, y, Z)
181 v = task.computeControlLaw()
182 prev_v = v
183 else:
184 task.computeControlLaw()
185 v = prev_v
186 error: ColVector = task.getError()
187 error_norm = error.sumSquare()
188
189 # Display and logging
190 Display.display(I)
191 sd.display(cam, I, Color.darkBlue, thickness=2)
192 s.display(cam, I, Color.darkRed, thickness=2)
193 Display.flush(I)
194 Display.getImage(I, Idisp)
195 print(v)
196 print(v, error, cTw)
197 plotter.on_iter(Idisp, v, error, cTw)
198
199 # Move robot/update simulator
200 cTcn = ExponentialMap.direct(v, time.time() - start)
201 cTw = cTcn.inverse() * cTw
202 simulator.setCameraPosition(cTw)
203
204 plotter.generate_anim()
None on_iter(self, ImageRGBa Idisp, ColVector v, ColVector error, HomogeneousMatrix cTw)
ImageSimulator get_simulator(str scene_path)