1- # -*- coding: utf-8 -*-
21"""
32Implementation of bindings for correspondences and related data structures.
43
54Created on Fri Oct 28 13:46:39 2016
65
7- @author: yosef
6+ @author: Yosef Meller, Alex Liberzon, TAU
87"""
98
109from libc.stdlib cimport malloc, calloc, free
@@ -17,7 +16,7 @@ from optv.calibration cimport Calibration, calibration
1716from optv.orientation cimport COORD_UNUSED
1817from optv.tracking_framebuf cimport TargetArray, Target, target, frame, \
1918 PT_UNUSED, CORRES_NONE
20-
19+
2120cdef class MatchedCoords:
2221 """
2322 Keeps a block of 2D flat coordinates, each with a "point number", the same
@@ -145,9 +144,15 @@ def correspondences(list img_pts, list flat_coords, list cals,
145144 num_targs - total number of targets (must be greater than the sum of
146145 previous 3).
147146 """
147+ cdef int num_cams = len (cals)
148+
149+ # Special case of a single camera, follow the single_cam_correspondence docstring
150+ if num_cams == 1 :
151+ sorted_pos, sorted_corresp, num_targs = single_cam_correspondence(img_pts, flat_coords, cals)
152+ return sorted_pos, sorted_corresp, num_targs
153+
148154 cdef:
149155 int pt, cam
150- int num_cams = len (cals)
151156
152157 calibration ** calib = < calibration ** > malloc(
153158 num_cams * sizeof(calibration * ))
@@ -171,49 +176,115 @@ def correspondences(list img_pts, list flat_coords, list cals,
171176 frm.targets[cam] = (< TargetArray> img_pts[cam])._tarr
172177 frm.num_targets[cam] = len (img_pts[cam])
173178 corrected[cam] = (< MatchedCoords> flat_coords[cam]).buf
174-
179+
175180 # The biz:
176181 corresp_buf = corresp(& frm, corrected,
177182 vparam._volume_par, cparam._control_par, calib, match_counts)
178-
183+
179184 # Distribute data to return structures:
180185 sorted_pos = [None ]* (num_cams - 1 )
181186 sorted_corresp = [None ]* (num_cams - 1 )
182187 last_count = 0
183-
188+
184189 for clique_type in xrange (num_cams - 1 ):
185190 num_points = match_counts[clique_type]
186191 clique_targs = np.full((num_cams, num_points, 2 ), PT_UNUSED,
187192 dtype = np.float64)
188193 clique_ids = np.full((num_cams, num_points), CORRES_NONE,
189194 dtype = np.int_)
190-
195+
191196 # Trace back the pixel target properties through the flat metric
192197 # intermediary that's x-sorted.
193198 for cam in range (num_cams):
194199 for pt in range (num_points):
195200 geo_id = corresp_buf[pt + last_count].p[cam]
196201 if geo_id < 0 :
197202 continue
198-
203+
199204 p1 = corrected[cam][geo_id].pnr
200205 clique_ids[cam, pt] = p1
201206
202207 if p1 > - 1 :
203208 targ = img_pts[cam][p1]
204209 clique_targs[cam, pt, 0 ] = (< Target> targ)._targ.x
205210 clique_targs[cam, pt, 1 ] = (< Target> targ)._targ.y
206-
211+
207212 last_count += num_points
208213 sorted_pos[clique_type] = clique_targs
209214 sorted_corresp[clique_type] = clique_ids
210-
215+
211216 # Clean up.
212217 num_targs = match_counts[num_cams - 1 ]
218+
219+
220+
213221 free(frm.targets)
214222 free(frm.num_targets)
215223 free(calib)
216224 free(match_counts)
217225 free(corresp_buf) # Note this for future returning of correspondences.
218226
219227 return sorted_pos, sorted_corresp, num_targs
228+
229+
230+ def single_cam_correspondence (list img_pts , list flat_coords , list cals ):
231+ """
232+ Single camera correspondence is not a real correspondence, it will be only a projection
233+ of a 2D target from the image space into the 3D position, x,y,z using epi_mm_2d
234+ function. Here we only update the pointers of the targets and return it in a proper format.
235+
236+ Arguments:
237+ img_pts - a list of c := len(cals), containing TargetArray objects, each
238+ with the target coordinates of n detections in the respective image.
239+ The target arrays are clobbered: returned arrays have the tnr property
240+ set. the pnr property should be set to the target index in its array.
241+ flat_coords - a list of MatchedCoordinates objects, one per camera, holding
242+ the x-sorted flat-coordinates conversion of the respective image
243+ targets.
244+ cals - a list of Calibration objects, each for the camera taking one image.
245+
246+ Returns:
247+ sorted_pos - a tuple of (c,?,2) arrays, each with the positions in each of
248+ c image planes of points belonging to quadruplets, triplets, pairs
249+ found.
250+ sorted_corresp - a tuple of (c,?) arrays, each with the point identifiers
251+ of targets belonging to a quad/trip/etc per camera.
252+ num_targs - total number of targets (must be greater than the sum of
253+ previous 3).
254+ """
255+ cdef:
256+ int pt, num_points
257+ coord_2d * corrected = < coord_2d * > malloc(sizeof(coord_2d * ))
258+
259+ corrected = (< MatchedCoords> flat_coords[0 ]).buf
260+
261+ sorted_pos = [None ]
262+ sorted_corresp = [None ]
263+
264+ num_points = len (img_pts[0 ])
265+
266+ clique_targs = np.full((1 , num_points, 2 ), PT_UNUSED,
267+ dtype = np.float64)
268+ clique_ids = np.full((1 , num_points), CORRES_NONE,
269+ dtype = np.int_)
270+
271+ # Trace back the pixel target properties through the flat metric
272+ # intermediary that's x-sorted.
273+ for pt in range (num_points):
274+
275+ # From Beat code (issue #118) pix[0][geo[0][i].pnr].tnr=i;
276+
277+ p1 = corrected[pt].pnr
278+ clique_ids[0 , pt] = p1
279+
280+ if p1 > - 1 :
281+ targ = img_pts[0 ][p1]
282+ clique_targs[0 , pt, 0 ] = (< Target> targ)._targ.x
283+ clique_targs[0 , pt, 1 ] = (< Target> targ)._targ.x
284+ # we also update the tnr, see docstring of correspondences
285+ (< Target> targ)._targ.tnr = pt
286+
287+ sorted_pos[0 ] = clique_targs
288+ sorted_corresp[0 ] = clique_ids
289+
290+ return sorted_pos, sorted_corresp, num_points
0 commit comments