def group_textlines(self, laparams, lines): plane = Plane(self.bbox) plane.extend(lines) boxes = {} for line in lines: neighbors = line.find_neighbors(plane, laparams.line_margin) if line not in neighbors: continue members = [] for obj1 in neighbors: members.append(obj1) if obj1 in boxes: members.extend(boxes.pop(obj1)) if isinstance(line, LTTextLineHorizontal): box = LTTextBoxHorizontal() else: box = LTTextBoxVertical() for obj in uniq(members): box.add(obj) boxes[obj] = box done = set() for line in lines: if line not in boxes: continue box = boxes[line] if box in done: continue done.add(box) if not box.is_empty(): yield box return
def group_textboxes(self, laparams, boxes): if len(boxes) > 100: # Grouping this many boxes would take too long and it doesn't make much sense to do so # considering the type of grouping (nesting 2-sized subgroups) that is done here. logging.info("Too many boxes (%d) to group, skipping.", len(boxes)) return boxes dists = [] for obj1, obj2 in zip(boxes[0:], boxes[1:]): dists.append((0, dist(obj1, obj2), obj1, obj2)) dists.sort() plane = Plane(boxes) while dists: (c, d, obj1, obj2) = dists.pop(0) if c == 0 and isany(obj1, obj2, plane): dists.append((1, d, obj1, obj2)) continue if (isinstance(obj1, (LTTextBoxVertical, LTTextGroupTBRL)) or isinstance(obj2, (LTTextBoxVertical, LTTextGroupTBRL))): group = LTTextGroupTBRL([obj1, obj2]) else: group = LTTextGroupLRTB([obj1, obj2]) plane.remove(obj1) plane.remove(obj2) dists = [n for n in dists if not n[2] in (obj1, obj2) and not n[3] in (obj1, obj2)] for other in plane: dists.append((0, dist(group, other), group, other)) dists.sort() plane.add(group) assert len(plane) == 1 return list(plane)
def group_textboxes(self, laparams, boxes): dists = [] for (obj1, obj2) in zip(boxes[0:], boxes[1:]): dists.append((0, dist(obj1, obj2), obj1, obj2)) #for i in xrange(len(boxes)): # obj1 = boxes[i] # for j in xrange(i + 1, len(boxes)): # obj2 = boxes[j] # dists.append((0, dist(obj1, obj2), obj1, obj2)) #dists.sort() plane = Plane(boxes) while dists: (c, d, obj1, obj2) = dists.pop(0) if c == 0 and isany(obj1, obj2, plane): dists.append((1, d, obj1, obj2)) continue if (isinstance(obj1, LTTextBoxVertical) or isinstance(obj1, LTTextGroupTBRL) or isinstance(obj2, LTTextBoxVertical) or isinstance(obj2, LTTextGroupTBRL)): group = LTTextGroupTBRL([obj1, obj2]) else: group = LTTextGroupLRTB([obj1, obj2]) plane.remove(obj1) plane.remove(obj2) dists = [n for n in dists if not n[2] in (obj1, obj2) and not n[3] in (obj1, obj2)] for other in plane: dists.append((0, dist(group, other), group, other)) #dists.sort() plane.add(group) assert len(plane) == 1 return list(plane)
def get_textboxes(self, laparams, lines): plane = Plane(lines) for line in lines: plane.add(line) plane.finish() boxes = {} for line in lines: neighbors = line.find_neighbors(plane, laparams.line_margin) assert line in neighbors, line members = [] for obj1 in neighbors: members.append(obj1) if obj1 in boxes: members.extend(boxes.pop(obj1)) if isinstance(line, LTTextLineHorizontal): box = LTTextBoxHorizontal() else: box = LTTextBoxVertical() for obj in uniq(members): box.add(obj) boxes[obj] = box done = set() for line in lines: box = boxes[line] if box in done: continue done.add(box) yield box.analyze(laparams) return
def group_textboxes(self, laparams, boxes): assert boxes def dist(obj1, obj2): """A distance function between two TextBoxes. Consider the bounding rectangle for obj1 and obj2. Return its area less the areas of obj1 and obj2, shown as 'www' below. This value may be negative. +------+..........+ (x1,y1) | obj1 |wwwwwwwwww: +------+www+------+ :wwwwwwwwww| obj2 | (x0,y0) +..........+------+ """ x0 = min(obj1.x0,obj2.x0) y0 = min(obj1.y0,obj2.y0) x1 = max(obj1.x1,obj2.x1) y1 = max(obj1.y1,obj2.y1) return ((x1-x0)*(y1-y0) - obj1.width*obj1.height - obj2.width*obj2.height) def isany(obj1, obj2): """Check if there's any other object between obj1 and obj2. """ x0 = min(obj1.x0,obj2.x0) y0 = min(obj1.y0,obj2.y0) x1 = max(obj1.x1,obj2.x1) y1 = max(obj1.y1,obj2.y1) objs = set(plane.find((x0,y0,x1,y1))) return objs.difference((obj1,obj2)) # XXX this still takes O(n^2) :( dists = [] for i in xrange(len(boxes)): obj1 = boxes[i] for j in xrange(i+1, len(boxes)): obj2 = boxes[j] dists.append((0, dist(obj1, obj2), obj1, obj2)) dists.sort() plane = Plane(boxes) while dists: (c,d,obj1,obj2) = dists.pop(0) if c == 0 and isany(obj1, obj2): dists.append((1,d,obj1,obj2)) continue if (isinstance(obj1, LTTextBoxVertical) or isinstance(obj1, LTTextGroupTBRL) or isinstance(obj2, LTTextBoxVertical) or isinstance(obj2, LTTextGroupTBRL)): group = LTTextGroupTBRL([obj1,obj2]) else: group = LTTextGroupLRTB([obj1,obj2]) plane.remove(obj1) plane.remove(obj2) # this line is optimized -- don't change without profiling dists = [ n for n in dists if n[2] in plane._objs and n[3] in plane._objs ] for other in plane: dists.append((0, dist(group,other), group, other)) dists.sort() plane.add(group) assert len(plane) == 1 return list(plane)
def group_textboxes(self, laparams, boxes): assert boxes def dist(obj1, obj2): """A distance function between two TextBoxes. Consider the bounding rectangle for obj1 and obj2. Return its area less the areas of obj1 and obj2, shown as 'www' below. This value may be negative. +------+..........+ (x1, y1) | obj1 |wwwwwwwwww: +------+www+------+ :wwwwwwwwww| obj2 | (x0, y0) +..........+------+ """ x0 = min(obj1.x0, obj2.x0) y0 = min(obj1.y0, obj2.y0) x1 = max(obj1.x1, obj2.x1) y1 = max(obj1.y1, obj2.y1) return ((x1-x0)*(y1-y0) - obj1.width*obj1.height - obj2.width*obj2.height) def isany(obj1, obj2): """Check if there's any other object between obj1 and obj2. """ x0 = min(obj1.x0, obj2.x0) y0 = min(obj1.y0, obj2.y0) x1 = max(obj1.x1, obj2.x1) y1 = max(obj1.y1, obj2.y1) objs = set(plane.find((x0, y0, x1, y1))) return objs.difference((obj1, obj2)) # XXX this still takes O(n^2) :( dists = [] for i in xrange(len(boxes)): obj1 = boxes[i] for j in xrange(i+1, len(boxes)): obj2 = boxes[j] dists.append((0, dist(obj1, obj2), obj1, obj2)) dists.sort() plane = Plane(self.bbox) plane.extend(boxes) while dists: (c, d, obj1, obj2) = dists.pop(0) if c == 0 and isany(obj1, obj2): dists.append((1, d, obj1, obj2)) continue if (isinstance(obj1, (LTTextBoxVertical, LTTextGroupTBRL)) or isinstance(obj2, (LTTextBoxVertical, LTTextGroupTBRL))): group = LTTextGroupTBRL([obj1, obj2]) else: group = LTTextGroupLRTB([obj1, obj2]) plane.remove(obj1) plane.remove(obj2) # this line is optimized -- don't change without profiling dists = [n for n in dists if n[2] in plane._objs and n[3] in plane._objs] for other in plane: dists.append((0, dist(group, other), group, other)) dists.sort() plane.add(group) assert len(plane) == 1 return list(plane)
def get_textboxes(self, laparams, lines): plane = Plane(lines) boxes = {} for line in lines: neighbors = line.find_neighbors(plane, laparams.line_margin) assert line in neighbors, line members = [] for obj1 in neighbors: members.append(obj1) if obj1 in boxes: members.extend(boxes.pop(obj1)) if isinstance(line, LTTextLineHorizontal): box = LTTextBoxHorizontal() else: box = LTTextBoxVertical() for obj in uniq(members): box.add(obj) boxes[obj] = box done = set() for line in lines: box = boxes[line] if box in done: continue done.add(box) yield box.analyze(laparams) return
def main(): # classes first, then execute code # for modular code, put code in a main function r = requests.get( "https://opensky-network.org/api/states/all?lamin=36&lomin=-124&lamax=39&lomax=-121" ) rest = r.json() states = rest['states'] tracks = [] # will hold the Planes from the opensky data for trk in states: if not trk[8]: #filters tracks that are squawking on the ground tracks.append(Plane(trk[6], trk[5], trk[10], trk[9], trk[1])) time = input("prediction time in minutes >>> ") for trk in tracks: print() print(f" **** {trk.callsign.strip()} ****") print(f"currently at: {str(trk.coords)}") print("heading " + str(trk.hdg) + "deg, at " + str(trk.vel) + "m/s") print("will be at: " + str(trk.predict(int(time)))) paths = [] # will hold plotly info for i in range(len(tracks)): paths.append( go.Scattergeo( locationmode='USA-states', lon=[tracks[i].lon, tracks[i].predict(int(time)).lon], lat=[tracks[i].lat, tracks[i].predict(int(time)).lat], mode='lines+markers', line=dict(width=1, color='red'), marker={ 'symbol': [2, 0], 'size': 7, 'color': "red" }, opacity=float(tracks[i].vel / max(tracks, key=lambda x: x.vel).vel), hoverinfo='text', text=tracks[i].callsign)) layout = go.Layout(autosize=True, showlegend=False, geo=go.layout.Geo( resolution=50, showcoastlines=True, scope='north america', projection=go.layout.geo.Projection( type='orthographic', ), )) fig = go.Figure(data=paths, layout=layout) fig.update_geos(fitbounds='locations') fig.show()
def ipm(imgFile, cfgFile): image = cv2.cvtColor(cv2.imread(imgFile), cv2.COLOR_BGR2RGB) TARGET_H, TARGET_W = 1024, 1024 # TARGET_H, TARGET_W = 800, 800 plane = Plane(20, -25, 0, 0, 0, 0, TARGET_H, TARGET_W, 0.035) extrinsic, intrinsic = load_camera_params(cfgFile) warped1 = ipm_from_parameters(image, plane.xyz, intrinsic, extrinsic, TARGET_H, TARGET_W) return warped1
def test_perspective(): extrinsic, intrinsic = load_camera_params('camera.json') P = intrinsic @ extrinsic plane = Plane( 0, -1, 0, # x, y, z 0, 0, 0, # roll, pitch, yaw 3, 3, 2) # col, row, scale print(perspective(plane.xyz, P, 3, 3))
def ipm_from_opencv(image, source_points, target_points): # Compute projection matrix M = cv2.getPerspectiveTransform(source_points, target_points) # Warp the image warped = cv2.warpPerspective(image, M, (TARGET_W, TARGET_H), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=0) return warped if __name__ == '__main__': ################ # Derived method ################ # Define the plane on the region of interest (road) plane = Plane(0, -25, 0, 0, 0, 0, TARGET_H, TARGET_W, 0.1) # Retrieve camera parameters extrinsic, intrinsic = load_camera_params('camera.json') # Apply perspective transformation warped1 = ipm_from_parameters(image, plane.xyz, intrinsic, extrinsic) ################ # OpenCV ################ # Vertices coordinates in the source image s = np.array([[830, 598], [868, 568], [1285, 598], [1248, 567]], dtype=np.float32) # Vertices coordinates in the destination image
class LTLayoutContainer(LTContainer): def __init__(self, bbox): LTContainer.__init__(self, bbox) self.layout = None return def analyze(self, laparams): # textobjs is a list of LTChar objects, i.e. # it has all the individual characters in the page. (textobjs, otherobjs) = fsplit(lambda obj: isinstance(obj, LTChar), self._objs) if not textobjs: return textlines = list(self.get_textlines(laparams, textobjs)) assert len(textobjs) <= sum( len(line._objs) for line in textlines ) (empties, textlines) = fsplit(lambda obj: obj.is_empty(), textlines) textboxes = list(self.get_textboxes(laparams, textlines)) assert len(textlines) == sum( len(box._objs) for box in textboxes ) top = self.group_textboxes(laparams, textboxes) def assign_index(obj, i): if isinstance(obj, LTTextBox): obj.index = i i += 1 elif isinstance(obj, LTTextGroup): for x in obj: i = assign_index(x, i) return i assign_index(top, 0) textboxes.sort(key=lambda box:box.index) self._objs = textboxes + otherobjs + empties self.layout = top return self def get_textlines(self, laparams, objs): obj0 = None line = None for obj1 in objs: if obj0 is not None: k = 0 if (obj0.is_compatible(obj1) and obj0.is_voverlap(obj1) and min(obj0.height, obj1.height) * laparams.line_overlap < obj0.voverlap(obj1) and obj0.hdistance(obj1) < max(obj0.width, obj1.width) * laparams.char_margin): # obj0 and obj1 is horizontally aligned: # # +------+ - - - # | obj0 | - - +------+ - # | | | obj1 | | (line_overlap) # +------+ - - | | - # - - - +------+ # # |<--->| # (char_margin) k |= 1 if (laparams.detect_vertical and obj0.is_compatible(obj1) and obj0.is_hoverlap(obj1) and min(obj0.width, obj1.width) * laparams.line_overlap < obj0.hoverlap(obj1) and obj0.vdistance(obj1) < max(obj0.height, obj1.height) * laparams.char_margin): # obj0 and obj1 is vertically aligned: # # +------+ # | obj0 | # | | # +------+ - - - # | | | (char_margin) # +------+ - - # | obj1 | # | | # +------+ # # |<-->| # (line_overlap) k |= 2 if ( (k & 1 and isinstance(line, LTTextLineHorizontal)) or (k & 2 and isinstance(line, LTTextLineVertical)) ): line.add(obj1) elif line is not None: yield line.analyze(laparams) line = None else: if k == 2: line = LTTextLineVertical(laparams.word_margin) line.add(obj0) line.add(obj1) elif k == 1: line = LTTextLineHorizontal(laparams.word_margin) line.add(obj0) line.add(obj1) else: line = LTTextLineHorizontal(laparams.word_margin) line.add(obj0) yield line.analyze(laparams) line = None obj0 = obj1 if line is None: line = LTTextLineHorizontal(laparams.word_margin) line.add(obj0) yield line.analyze(laparams) return def get_textboxes(self, laparams, lines): plane = Plane(lines) boxes = {} for line in lines: neighbors = line.find_neighbors(plane, laparams.line_margin) assert line in neighbors, line members = [] for obj1 in neighbors: members.append(obj1) if obj1 in boxes: members.extend(boxes.pop(obj1)) if isinstance(line, LTTextLineHorizontal): box = LTTextBoxHorizontal() else: box = LTTextBoxVertical() for obj in uniq(members): box.add(obj) boxes[obj] = box done = set() for line in lines: box = boxes[line] if box in done: continue done.add(box) yield box.analyze(laparams) return def group_textboxes(self, laparams, boxes): def dist((x0,y0,x1,y1), obj1, obj2): """A distance function between two TextBoxes. Consider the bounding rectangle for obj1 and obj2. Return its area less the areas of obj1 and obj2, shown as 'www' below. This value may be negative. +------+..........+ (x1,y1) | obj1 |wwwwwwwwww: +------+www+------+ :wwwwwwwwww| obj2 | (x0,y0) +..........+------+ """ return ((x1-x0)*(y1-y0) - obj1.width*obj1.height - obj2.width*obj2.height) boxes = boxes[:] # XXX this is very slow when there're many textboxes. while 2 <= len(boxes): mindist = (INF,0) minpair = None plane = Plane(boxes) boxes = csort(boxes, key=lambda obj: obj.width*obj.height) for i in xrange(len(boxes)): for j in xrange(i+1, len(boxes)): (obj1, obj2) = (boxes[i], boxes[j]) b = (min(obj1.x0,obj2.x0), min(obj1.y0,obj2.y0), max(obj1.x1,obj2.x1), max(obj1.y1,obj2.y1)) others = set(plane.find(b)).difference((obj1,obj2)) d = dist(b, obj1, obj2) # disregard if there's any other object in between. if 0 < d and others: d = (1,d) else: d = (0,d) if mindist <= d: continue mindist = d minpair = (obj1, obj2) assert minpair is not None, boxes (obj1, obj2) = minpair boxes.remove(obj1) boxes.remove(obj2) if (isinstance(obj1, LTTextBoxVertical) or isinstance(obj2, LTTextBoxVertical) or isinstance(obj1, LTTextGroupTBRL) or isinstance(obj2, LTTextGroupTBRL)): group = LTTextGroupTBRL([obj1, obj2]) else: group = LTTextGroupLRTB([obj1, obj2]) boxes.append(group.analyze(laparams)) assert len(boxes) == 1 return boxes.pop()
def getImageFiles(rootDir): imgFiles = os.listdir(rootDir) imgFiles = [os.path.join(rootDir, img) for img in imgFiles] return imgFiles if __name__ == '__main__': rootDir = argv[1] cfgFile = argv[2] imgFiles = getImageFiles(rootDir) TARGET_H, TARGET_W = 1024, 1024 extrinsic, intrinsic = load_camera_params(cfgFile) plane = Plane(20, -25, 0, 0, 0, 0, TARGET_H, TARGET_W, 0.035) i = 1 for imgFile in tqdm(imgFiles, total=len(imgFiles)): image = cv2.cvtColor(cv2.imread(imgFile), cv2.COLOR_BGR2RGB) warped = ipm_from_parameters(image, plane.xyz, intrinsic, extrinsic) cv2.imwrite(imgFile, cv2.cvtColor(warped, cv2.COLOR_BGR2RGB)) # outFile = os.path.join(rootDir, str(i) + ".png") # cv2.imwrite(outFile, cv2.cvtColor(warped, cv2.COLOR_BGR2RGB)) # i += 1 # fig, ax = plt.subplots(1, 2) # ax[0].imshow(image)
pixel_coords = perspective(xyz, P, TARGET_H, TARGET_W) print('pixel_coords.shape', pixel_coords.shape) print('pixel_coords[0,0]', pixel_coords[250, 250]) image2 = bilinear_sampler(image, pixel_coords) return image2.astype(np.uint8) if __name__ == '__main__': # Define the plane on the region of interest (road) plane = Plane( 0, -25, 0, #x, y, z 0, 0, 0, #roll, pitch, yaw TARGET_H, TARGET_W, 0.1) #col, row, scale assert plane.xyz.shape == (4, 250000) print(plane.xyz) extrinsic, intrinsic = load_camera_params('camera.json') warped1 = ipm_from_parameters(image, plane.xyz, intrinsic, extrinsic) plt.figure(figsize=(20, 20)) plt.imshow(warped1) plt.show() ''' ################