def __call__(lineccs):
        # utilities for Gamera's graph API
        from gamera import graph
        from gamera import graph_util

        class SegForGraph:
            def __init__(self, seg):
                self.segment = seg
                self.label = 0

        #
        # build directed graph of all lines
        #
        G = graph.Graph(graph.FLAG_DAG)
        seg_data = [SegForGraph(s) for s in lineccs]
        # sort by y-position for row over column preference in ambiguities
        seg_data.sort(lambda s, t: s.segment.offset_y - t.segment.offset_y)
        G.add_nodes(seg_data)
        for s in seg_data:
            for t in seg_data:
                if s.segment.offset_x <= t.segment.offset_x + t.segment.ncols and \
                        s.segment.offset_x + s.segment.ncols >= t.segment.offset_x:
                    if s.segment.offset_y < t.segment.offset_y:
                        G.add_edge(s, t)
                elif s.segment.offset_x < t.segment.offset_x:
                    G.add_edge(s, t)
        #
        # compute topoligical sorting by depth-first-search
        #
        segs_sorted = []  # topologically sorted list

        def dfs_visit(node):
            node.data.label = 1
            for nextnode in node.nodes:
                if nextnode.data.label == 0:
                    dfs_visit(nextnode)
            segs_sorted.append(node.data.segment)

        for node in G.get_nodes():
            if node.data.label == 0:
                dfs_visit(node)
        segs_sorted.reverse()  # correct that we always appended to the back
        return segs_sorted
 def merge_boxes(bboxes):
     from gamera import graph
     bboxes.sort(lambda b1, b2: b1.rect.ul_y - b2.rect.ul_y)
     g = graph.Graph(graph.UNDIRECTED)
     # build graph where edge means overlap of two boxes
     for i in range(len(bboxes)):
         g.add_node(i)
     for i in range(len(bboxes)):
         for j in range(i + 1, len(bboxes)):
             if bboxes[j].rect.ul_y > bboxes[i].rect.lr_y:
                 break
             if bboxes[i].rect.intersects(bboxes[j].rect):
                 if not g.has_edge(i, j):
                     g.add_edge(i, j)
     new_bboxes = []
     for sg in g.get_subgraph_roots():
         seg = [n() for n in g.BFS(sg)]
         bbox = bboxes[seg[0]]
         for i in range(1, len(seg)):
             bbox.merge(bboxes[seg[i]])
         new_bboxes.append(bbox)
     return new_bboxes
    def __call__(self, Ta=40.0, fr=0.34):
        # compute neighborship graph
        from gamera.plugins.geometry import delaunay_from_points
        ccs = self.cc_analysis()
        i = 0
        points = []
        labels = []
        labels2ccs = {}
        for cc in ccs:
            p = cc.contour_samplepoints(15, 1)
            cc.points = p
            points += p
            labels += [cc.label] * len(p)
            labels2ccs[cc.label] = cc
        neighbors = delaunay_from_points(points, range(len(points)))

        # compute edge properties
        class Edge(object):
            def __init__(self, cc1, cc2, d2):
                self.cc1 = cc1
                self.cc2 = cc2
                self.d = d2
                a = [cc1.black_area()[0], cc2.black_area()[0]]
                self.ar = max(a) / min(a)

        labelneighbors = {}
        for pair in neighbors:
            if (labels[pair[0]] < labels[pair[1]]):
                label1 = labels[pair[0]]
                label2 = labels[pair[1]]
            else:
                label1 = labels[pair[1]]
                label2 = labels[pair[0]]
            if label1 == label2:
                continue
            p1 = points[pair[0]]
            p2 = points[pair[1]]
            d2 = (p1.x - p2.x)**2 + (p1.y - p2.y)**2
            key = "%i;%i" % (label1, label2)
            if not labelneighbors.has_key(key):
                labelneighbors[key] = Edge(labels2ccs[label1],
                                           labels2ccs[label2], d2)
            else:
                e = labelneighbors[key]
                if e.d > d2:
                    e.d = d2
        for e in labelneighbors.itervalues():
            e.d = sqrt(e.d)

        # determine thresholds Td1 and Td2 from distance statistics
        distances = [e.d for e in labelneighbors.itervalues()]
        distances.sort()
        if len(distances) > 50:
            distances = distances[len(distances) / 20:(len(distances) -
                                                       len(distances) / 20)]
        x = [float(i * max(distances)) / 512.0 for i in range(512)]
        density = kernel_density(distances, x, kernel=2)
        local_maxima_i = []
        local_maxima_d = []
        for i in range(1, len(density) - 1):
            if density[i] > density[i - 1] and density[i] > density[i + 1]:
                local_maxima_i.append(i)
                local_maxima_d.append(density[i])
        m1 = argmax(local_maxima_d)
        i1 = local_maxima_i[m1]
        local_maxima_i = [
            local_maxima_i[i] for i in range(len(local_maxima_i)) if i != m1
        ]
        local_maxima_d = [
            local_maxima_d[i] for i in range(len(local_maxima_d)) if i != m1
        ]
        i2 = local_maxima_i[argmax(local_maxima_d)]
        if i2 < i1:
            tmp = i2
            i2 = i1
            i1 = tmp
        dmax = density[i2]
        i2 += 1
        while i2 < len(x) - 1:
            if density[i2] < fr * dmax:
                break
            i2 += 1
        Td1 = x[i1]
        Td2 = x[i2]
        #print "Td1 =", Td1, "Td2 =", Td2, "(plugin)"

        # build graph
        from gamera import graph
        g = graph.Graph(graph.UNDIRECTED)
        rgb = self.to_rgb()
        for e in labelneighbors.itervalues():
            if not g.has_node(e.cc1.label):
                g.add_node(e.cc1.label)
            if not g.has_node(e.cc2.label):
                g.add_node(e.cc2.label)
            if (e.d / Td1 <= 1.0) or (e.d / Td2 + e.ar / Ta <= 1):
                g.add_edge(e.cc1.label, e.cc2.label)
            else:
                pass

        # split graph into connected subgraphs
        from gamera.core import MlCc
        seglabels = []
        for i, sg in enumerate(g.get_subgraph_roots()):
            seg = [n() for n in g.BFS(sg)]
            seglabels.append(seg)
        segments = []
        for lbs in seglabels:
            mlcc = MlCc([labels2ccs[lb] for lb in lbs])
            segments.append(mlcc.convert_to_cc())

        return segments