Esempio n. 1
0
    def edgepixelsinbounds(self, subsetblob, boundaryblob):
        """
        :param subsetblob: A blob2d's id from which we will find a subset of edge_pixels
                           which are within an acceptable bound
        :param boundaryblob: A blob2d's id which is used to set the boundary constraints for pixels from subsetblob
        :return: A list of pixels, chosen from subsetblob.edge_pixels,
            which are within the scaled boundary defined by boundaryblob and Config.overscan_scale
        """
        assert 0 < self.overscan_scale < 2
        assert type(subsetblob) is int
        assert type(boundaryblob) is int
        subsetblob = Blob2d.get(subsetblob)
        boundaryblob = Blob2d.get(boundaryblob)

        left_bound = boundaryblob.avgx - ((boundaryblob.avgx - boundaryblob.minx) * self.overscan_scale)
        right_bound = boundaryblob.avgx + ((boundaryblob.maxx - boundaryblob.avgx) * self.overscan_scale)
        down_bound = boundaryblob.avgy - ((boundaryblob.avgy - boundaryblob.miny) * self.overscan_scale)
        up_bound = boundaryblob.avgy + ((boundaryblob.maxy - boundaryblob.avgy) * self.overscan_scale)
        boundedpixels = []
        for p_num, pixel in enumerate(
                subsetblob.edge_pixels):  # TODO TODO TODO IMPORTANT, need two way setup, for blob and self. FIXME
            pixel = Pixel.get(pixel)
            if left_bound <= pixel.x <= right_bound and down_bound <= pixel.y <= up_bound:
                boundedpixels.append(pixel.id)
        return boundedpixels
Esempio n. 2
0
    def extract_blob3ds(all_slides, stitched=True):
        printl('Extracting 3D blobs by combining 2D blobs into 3D', flush=True)
        blob3dlist = []
        if not stitched:
            warn(
                'Extracting blob3ds, and have been told that they haven\'t been stitched. This will be inaccurate'
            )
            printl(
                'Extracting blob3ds, and have been told that they haven\'t been stitched. This will be inaccurate'
            )  # DEBUG

        for slide_num, slide in enumerate(all_slides):
            for blob in slide.blob2dlist:
                if Blob2d.get(blob).b3did == -1:
                    if stitched:  # The much better option! ESPECIALLY for recursive_depth = 0
                        buf = [
                            b2d for b2d in Blob2d.get(
                                blob).get_stitched_partners()
                        ]  # old method
                        # buf = [Blob2d.get(b2d) for b2d in Blob2d.get(blob).getpartnerschain()] # IDEALLY could use this for both... for now, it doesnt work well
                    else:
                        buf = [
                            Blob2d.get(b2d)
                            for b2d in Blob2d.get(blob).getpartnerschain()
                        ]  # TODO setting partners needs filtering like stitching
                    if len(buf) != 0:
                        blob3dlist.append(Blob3d([b2d.id for b2d in buf]))
        return blob3dlist
Esempio n. 3
0
    def stitchAllBlobs(slidelist, quiet=True, debug=False):
        t_start_stitching = time.time()
        printl('')
        for slide_num, slide in enumerate(slidelist[:-1]):
            # Skipping last slide, because pairing go from lower slide to upper slide, so it's already processed with the second to last slide
            # IE blob2ds in the last slide are partners to the previous slide's blob2ds, and have no direct possible partners of their own
            t_start_stitching_this_slide = time.time()
            printl('Stitching %s blob2ds from slide #%s/%s to %s blob2ds from slide #%s/%s' % (len(slide.blob2dlist), slide_num + 1,
                len(slidelist), len(slidelist[slide_num+1].blob2dlist), str(slide_num + 2), len(slidelist)), end=' ')

            progress = ProgressBar(max_val=len(slide.blob2dlist), increments=20,
                                   symbol='.')  # Note actually more responsive to do based on blob than # of pixels, due to using only a subset to stitch
            for b_num, blob1 in enumerate(slide.blob2dlist):
                blob1 = Blob2d.get(blob1)
                if len(blob1.possible_partners) > 0:
                    if debug:
                        printl('  Starting on a new blob from bloblist:' + str(blob1) + ' which has:' + str(
                            len(blob1.possible_partners)) + ' possible partners')
                for b2_num, blob2 in enumerate(blob1.possible_partners):
                    blob2 = Blob2d.get(blob2)
                    if debug:
                        printl('   Comparing to blob2:' + str(blob2))
                    new_stitch = Pairing(blob1.id, blob2.id, 1.1, 36, quiet=quiet) # TODO use this to assign ids to pairings
                progress.update(b_num, set_val=True)

            if quiet and not debug:
                progress.finish()
                print_elapsed_time(t_start_stitching_this_slide, time.time(), prefix='took')
        print_elapsed_time(t_start_stitching, time.time(), prefix='Stitching all slides took', endline=False)
        printl(' total')
Esempio n. 4
0
def get_blob2ds_from_blob3ds(blob3dlist, ids=False):
    if ids:
        return list(
            set(
                Blob2d.get(b2did) for b3did in blob3dlist
                for b2did in Blob3d.get(b3did).blob2ds))
    else:
        return list(
            set(
                Blob2d.get(b2did) for b3d in blob3dlist
                for b2did in b3d.blob2ds))
Esempio n. 5
0
 def set_possible_partners(slidelist):
     max_height = max(slide.height for slide in slidelist)
     slides_by_height = [[] for _ in range(max_height + 1)]
     for slide in slidelist:
         slides_by_height[slide.height].append(slide)
     for height, slides_at_height in enumerate(
             slides_by_height[:-1]):  # All but the highest slides
         for slide in slides_at_height:
             for blob in slide.blob2dlist:
                 for above_slide in slides_by_height[height + 1]:
                     Blob2d.get(blob).set_possible_partners(
                         above_slide.blob2dlist)
Esempio n. 6
0
 def set_all_shape_contexts(slidelist):
     # Note Use the shape contexts approach from here: http://www.cs.berkeley.edu/~malik/papers/mori-belongie-malik-pami05.pdf
     # Note The paper uses 'Representative Shape Contexts' to do inital matching; I will do away with this in favor of checking bounds for possible overlaps
     t0 = time.time()
     pb = ProgressBar(max_val=sum(
         len(Blob2d.get(b2d).edge_pixels) for slide in slidelist
         for b2d in slide.blob2dlist))
     for slide in slidelist:
         for blob in slide.blob2dlist:
             Blob2d.get(blob).set_shape_contexts(36)
             pb.update(len(Blob2d.get(blob).edge_pixels), set_val=False)
     pb.finish()
     print_elapsed_time(t0, time.time(), prefix='took')
Esempio n. 7
0
    def __str__(self):
        if self.cost == -1:
            cost_str = 'Unset'
        else:
            cost_str = str(self.cost)

        return str('<Pairing between blob2ds at heights:(' + str(self.lowerheight) + ',' + str(
            self.upperheight) + ') with ids (' +
                   str(self.lowerblob) + ',' + str(self.upperblob) + '). Chose:' + str(len(self.lowerpixels)) +
                   '/' + str(len(Blob2d.get(self.lowerblob).edge_pixels)) + ' lower blob pixels and ' + str(
            len(self.upperpixels)) +
                   '/' + str(len(Blob2d.get(
            self.upperblob).edge_pixels)) + ' upper blob pixels. ' + 'Cost:' + cost_str + '>\n Actual lowerblob: ' + str(
            Blob2d.get(self.lowerblob)) + '\n Actual upperblob: ' + str(Blob2d.get(self.upperblob)))
Esempio n. 8
0
    def __init__(self, lowerblobid, upperblobid, overscan_scale, num_bins, quiet=True):
        self.overscan_scale = overscan_scale
        self.num_bins = num_bins
        self.lowerheight = Blob2d.get(lowerblobid).height
        self.upperheight = Blob2d.get(upperblobid).height
        self.lowerblob = lowerblobid
        self.upperblob = upperblobid
        self.upperpixels = self.edgepixelsinbounds(upperblobid, lowerblobid)
        self.lowerpixels = self.edgepixelsinbounds(lowerblobid, upperblobid)
        self.isReduced = False  # True when have chosen a subset of the edge pixels to reduce computation
        self.stitches = []
        self.cost = -1  # -1 to indicate that it is unset

        if self.upperpixels is not None and len(self.upperpixels) != 0 and len(self.lowerpixels) != 0:
            # HACK
            # NOTE planning to reduce to a subset
            # NOTE 1:28 for (203,301) pre-opt, :37 for (174, 178), 66mins for (640, 616) -> 4 mins after optimization (picking half of each) -> 59 seconds with selective[::3]
            # NOTE After ::2 opt, total time for [:3] data slides = 10 mins 19 seconds, instead of ~ 2 hours, after selective[::3], total time = 6mins 49 seconds
            # selective [::3] with 5 slides = 36 mins
            if len(self.upperpixels) > Config.max_pixels_to_stitch or len(
                    self.lowerpixels) > Config.max_pixels_to_stitch:
                if not quiet:
                    printd('-->Too many pixels in the below stitch, reducing to a subset, originally was: ' + str(
                        len(self.lowerpixels)) +
                           '/' + str(len(self.lowerblob.edge_pixels)) + ' lower blob pixels and ' + str(
                        len(self.upperpixels)) +
                           '/' + str(len(self.upperblob.edge_pixels)) + ' upper blob pixels.', quiet)
                pickoneovers = max(1, math.ceil(len(self.upperpixels) / Config.max_pixels_to_stitch)), max(1, math.ceil(
                    len(
                        self.lowerpixels) / Config.max_pixels_to_stitch))  # HACK TODO Modify these values to be more suitable dependent on computation time
                self.isReduced = True
                self.upperpixels = self.upperpixels[::pickoneovers[0]]  # Every pickoneover'th element
                self.lowerpixels = self.lowerpixels[
                                   ::pickoneovers[1]]  # HACK this is a crude way of reducing the number of pixels
            self.isConnected = True
            self.set_shape_contexts(num_bins)  # Set lower and upper context bins
            if not quiet:
                printd('   ' + str(self), quiet)
            self.gen_stitches()  # Now have set self.cost and self.indeces and self.connect
            Blob2d.all[lowerblobid].pairings.append(self)  # TODO TODO  convert this to use ids
            Blob2d.all[upperblobid].pairings.append(self)

        else:
            self.isConnected = False
        printd('Just created stitch: ' + str(self), Config.debug_stitches)
Esempio n. 9
0
 def stitch_blob2ds(b2ds, debug=False):
     pairlist = []
     for b_num, blob1 in enumerate(b2ds):
         blob1 = Blob2d.get(blob1)
         if len(blob1.possible_partners) > 0:
             if debug:
                 printl('  Starting on a new blob from bloblist:' + str(blob1) + ' which has:' + str(
                     len(blob1.possible_partners)) + ' possible partners')
         for b2_num, blob2 in enumerate(blob1.possible_partners):
             blob2 = Blob2d.get(blob2)
             if debug:
                 printl('   Comparing to blob2:' + str(blob2))
             pair = Pairing(blob1.id, blob2.id, 1.1, 36, quiet=True)
             if pair.isConnected:
                 pairlist.append(pair)
             elif debug:
                 printl('    -Blobs not connected')
     return pairlist
Esempio n. 10
0
 def assign_alive_pixels_to_blob2dlist(self, quiet=False):
     self.assignPixelsToIds(
         self.alive_pixels)  # Note only printing when primary slide
     id_lists = pixels_to_id_lists(self.alive_pixels)
     self.blob2dlist = [
     ]  # Note that blobs in the blob list are ordered by number of pixels, not id, this makes merging faster
     for (blobnum, blobslist) in enumerate(id_lists):
         newb2d = Blob2d(blobslist, self.height)
         self.blob2dlist.append(newb2d.id)
     if not quiet:
         printl('There were ' + str(len(self.alive_pixels)) +
                ' alive pixels assigned to ' + str(len(self.blob2dlist)) +
                ' blobs.')
         self.tf = time.time()
         printl('Creating this slide took', end='')
         print_elapsed_time(self.t0, self.tf, prefix='')
         printl('')
Esempio n. 11
0
 def get_pixels(self, ids=False):
     """
     Gets all pixels from a blob3d's blob2ds, as well as from all blob2ds that are created from any of its blob2ds
     This means that the result will be the same before and after blooming
     This is not the same as getting only the pixels which constitute blob2ds which consititure the blob ONLY the blob2ds of self.blob2ds
     :param ids: boolean, If true
     :return:
     """
     pixel_ids = []
     for b2d in self.blob2ds:
         b2d = Blob2d.get(b2d)
         b2d_descend = b2d.getdescendants(include_self=True)
         # printl("B2d: " + str(b2d) + ' ----- had descendants (incl self(' + str(len(b2d_descend)) + ') ------' + str(b2d_descend))
         for blob2d in b2d_descend:
             pixel_ids += blob2d.pixels
     if ids:
         return pixel_ids
     else:
         return [Pixel.get(pixel_id) for pixel_id in pixel_ids]
Esempio n. 12
0
    def __init__(self, blob2dlist, r_depth=0):
        self.id = Blob3d.next_id
        Blob3d.next_id += 1
        self.blob2ds = blob2dlist  # List of the blob 2ds used to create this blob3d
        # Now find my pairings
        self.pairings = []
        self.lowslideheight = min(
            Blob2d.get(blob).height for blob in self.blob2ds)
        self.highslideheight = max(
            Blob2d.get(blob).height for blob in self.blob2ds)
        self.recursive_depth = r_depth
        self.children = []
        self.parent_id = None
        self.isBead = None

        ids_that_are_removed_due_to_reusal = set()
        for blobid in self.blob2ds:
            blob = Blob2d.get(blobid)
            if Blob2d.all[
                    blob.
                    id].b3did != -1:  # DEBUG #FIXME THE ISSUES COME BACK TO THIS, find the source
                # warn('NOT assigning a new b3did (' + str(self.id) + ') to blob2d: ' + str(Blob2d.all[blob.id]))
                printl('---NOT assigning a new b3did (' + str(self.id) +
                       ') to blob2d: ' + str(Blob2d.all[blob.id]))
                Blob3d.possible_merges.append(
                    (Blob2d.all[blob.id].b3did, self.id, blob.id))
                ids_that_are_removed_due_to_reusal.add(blobid)  # HACK
            else:  # Note not adding to the new b3d
                Blob2d.all[blob.id].b3did = self.id
                for stitch in blob.pairings:
                    if stitch not in self.pairings:  # TODO set will be faster
                        self.pairings.append(stitch)
        # self.blob2ds = list(set(self.blob2ds) - ids_that_are_removed_due_to_reusal) # TODO fixed typo 10/10, check doesn't impact elsewhere before uncommenting
        self.maxx = max(Blob2d.get(blob).maxx for blob in self.blob2ds)
        self.maxy = max(Blob2d.get(blob).maxy for blob in self.blob2ds)
        self.miny = min(Blob2d.get(blob).miny for blob in self.blob2ds)
        self.minx = min(Blob2d.get(blob).minx for blob in self.blob2ds)
        self.avgx = sum(Blob2d.get(blob).avgx
                        for blob in self.blob2ds) / len(self.blob2ds)
        self.avgy = sum(Blob2d.get(blob).avgy
                        for blob in self.blob2ds) / len(self.blob2ds)
        self.avgz = (self.lowslideheight + self.highslideheight) / 2
        self.isSingular = False
        self.note = ''  # This is a note that can be manually added for identifying certain characteristics..
        if r_depth != 0:
            """
            This is one of the most convoluted and complicated parts of the project
            This occurs only when a blob3d is being created as a result of blooming
            The idea is that a blob3d is being creating from some blob2ds, which ideally were bloomed from a single blob2d
            However, sometimes bloomed blob2ds from multiple blob3ds end up being stitched together. The idea here is to combine those blob3ds together
            This is complicated because it may need to be recursively applied, to keep the condition that each blob2d and each blob3d are dervied from a single blob3d
            In the event that a blob3d would have multiple parent blob3ds, it's parents are combined
            """

            all_b2d_parents = [
                Blob2d.get(Blob2d.get(b2d).parent_id) for b2d in blob2dlist
            ]
            # printl('All b2d_parents of our b2ds that are going into a new b3d: ' + str(all_b2d_parents))
            parent_b3dids = set(
                [b2d.b3did for b2d in all_b2d_parents if b2d.b3did != -1])
            # printl('Their b3dids: ' + str(parent_b3dids))
            if len(parent_b3dids) > 0:
                printd(
                    'Attempting to create a new b3d with id: ' + str(self.id) +
                    '\nAll b2d_parents of our b2ds that are going into a new b3d: '
                    + str(all_b2d_parents) +
                    '\nAll of the b2ds\'_parents\' b3dids: ' +
                    str(parent_b3dids), Config.debug_b3d_merge)

                if len(parent_b3dids) > 1:
                    printd(
                        '*Found more than one b3d parent for b3d: ' +
                        str(self) + ', attempting to merge parents: ' +
                        str(list(Blob3d.get(b3d) for b3d in parent_b3dids)),
                        Config.debug_b3d_merge)
                    Blob3d.merge(list(parent_b3dids))
                    new_parent_b3dids = list(
                        set([
                            b2d.b3did for b2d in all_b2d_parents
                            if b2d.b3did != -1
                        ]))  # TODO can remove this, just for safety for now
                    printd(
                        '  Post merging b3d parents, updated available-parent b3dids: '
                        + str(new_parent_b3dids), Config.debug_b3d_merge)
                else:
                    new_parent_b3dids = list(parent_b3dids)
                self.parent_id = new_parent_b3dids[0]  # HACK HACK HACK
                if len(new_parent_b3dids) != 0 or self.parent_id == -1:
                    printd(
                        " Updating b3d " + str(self.id) +
                        '\'s parent_id to: ' + str(self.parent_id) +
                        ' from new_parent_ids(after regen after merge): ' +
                        str(
                            list(Blob3d.getb3d(b3d))
                            for b3d in new_parent_b3dids),
                        Config.debug_b3d_merge)
                Blob3d.all[self.parent_id].children.append(self.id)
                printd(
                    ' Added b3d ' + str(self.id) +
                    ' to parent\'s list of children, updated parent: ' +
                    str(Blob3d.all[self.parent_id]), Config.debug_b3d_merge)
                if len(new_parent_b3dids) != 1:
                    warn('New b3d (' + str(self.id) +
                         ') should have ended up with more than one parent!')
            else:
                warn('Creating a b3d at depth ' + str(r_depth) + ' with id ' +
                     str(self.id) + ' which could not find a b3d parent')
        self.validate()
        printd("Done creating new b3d:" + str(self), Config.debug_b3d_merge)
Esempio n. 13
0
 def get_edge_pixels(self):
     edge = []
     for b2d in self.blob2ds:
         b2d = Blob2d.get(b2d)
         edge = edge + [Pixel.get(pix) for pix in b2d.edge_pixels]
     return edge
Esempio n. 14
0
 def get_edge_pixel_count(self):
     edge = 0
     for b2d in self.blob2ds:
         edge += len(Blob2d.get(b2d).edge_pixels)
     return edge