Esempio n. 1
0
def get_common_interior_polygons(polygon, list_of_polygons):
    """Check if polygon resides inside any polygon
    in the list_of_polygons.

    Parameters
    ----------
    polygon: matplotlib.Polygon

    Returns
    -------
    list_of_common_polygons: list
                             A filtered list of ids

    """
    if isinstance(polygon, Polygon):
        polygon = shapelyPolygon(polygon.get_xy()).buffer(0)
    list_of_common_polygons = []
    for index, outside_polygon in enumerate(list_of_polygons):
        if isinstance(outside_polygon, Polygon):
            outside_polygon = shapelyPolygon(
                outside_polygon.get_xy()).buffer(0)
        if polygon.is_valid and outside_polygon.is_valid:
            if polygon.within(outside_polygon):
                list_of_common_polygons.append(index)
    return list_of_common_polygons
Esempio n. 2
0
def do(star, stars, vertices):
	maxArea = 0	
	start_poly = onestar_to_poly(star, vertices)
	adjTupleSet = getStarAdj(star, stars)
	# Get all adjacent combination with polyno number of polygons
	for polyno in range(1,len(adjTupleSet)+1):
		print("combine with" + str(polyno) + "\n\n")
		combis = itertools.combinations(adjTupleSet,polyno)
		for combi in combis:
			print("new combination")
			poly = shapelyPolygon(start_poly)
			# vertices of this combination
			polyvert = star.copy()
			for p in combi:
				# pdb.set_trace()
				addPoly = shapelyPolygon(onestar_to_poly(p, vertices))
				poly = cascaded_union([poly, addPoly])
				for v in p:
					polyvert.append(v)
			# pdb.set_trace()
			polyvert = list(set(polyvert))
			polyvert.sort()
			print("Vertices", polyvert)
			polyvert = onestar_to_poly(polyvert, vertices)
			print("Area", poly.area)
			print("Star", starise.kernel(list(range(len(polyvert))), polyvert))

			print("\n")
Esempio n. 3
0
 def intersects_rectangle(self, rectangle):
     if self.geometry.is_empty:
         return False
     x0,z0,x1,z1 = rectangle
     points = [(x0, z0), (x1, z0), (x1, z1), (x0, z1)]
     shPolygon = shapelyPolygon(points)
     return not self.geometry.disjoint(shPolygon)
Esempio n. 4
0
 def contains_rectangle(self, rectangle):
     if self.geometry.is_empty:
         return False
     x0,z0,x1,z1 = rectangle
     points = [(x0, z0), (x1, z0), (x1, z1), (x0, z1)]
     shPolygon = shapelyPolygon(points)
     return all([point_in_rectangle(point, self.geometry.bounds) for point in points]) and self.geometry.contains(shPolygon)
Esempio n. 5
0
def mpl_polygon_to_shapely_scaled(polygon, x0=0, y0=0, scale_factor=1):
    """Convert a given matploltib polygon to shapely

    Shapely allows more operations that we really ned
    while matplotlib.polygon is in use for legacy reasons

    Parameters
    ----------
    polygon: matplotlib.Polygon
             Input object
    x0, y0: int
            Origin for scaling
    scale_factor: float
                  How much to scale
    Returns
    -------
    shapely_polygon: Polygon
                     Scaled polygon

    """
    xy = polygon.get_xy()
    shapely_polygon = shapelyPolygon(xy)
    return scale(shapely_polygon,
                 xfact=scale_factor,
                 yfact=scale_factor,
                 origin=(x0, y0))
Esempio n. 6
0
def get_annotation_polygons(json_filepath, polygon_type="mpl"):
    """Get annotation jsons polygons

    Assumed to be at level 0

    Parameters
    ----------
    json_filepath: string
                    Path to json file
    polygon_type: string
                  'matplotlib/shapely'

    Returns
    -------
    polygons: dict(Polygons)
                dict of matplotlib.Polygons with keys are normal/tumor

    """
    json_parsed = json.load(open(json_filepath))
    tumor_patches = json_parsed["tumor"]
    normal_patches = json_parsed["normal"]
    polygons = OrderedDict()
    polygons["tumor"] = []
    polygons["normal"] = []
    for tumor_patch in tumor_patches:
        tumor_patch["vertices"] = np.array(tumor_patch["vertices"])
        if polygon_type == "mpl":
            polygon = Polygon(tumor_patch["vertices"])
        else:
            if tumor_patch["vertices"].shape[0] >= 3:
                polygon = shapelyPolygon(tumor_patch["vertices"])
            else:
                continue
        polygons["tumor"].append(polygon)
    for normal_patch in normal_patches:
        if polygon_type == "mpl":
            polygon = Polygon(np.array(tumor_patch["vertices"]))
        else:
            polygon = shapelyPolygon(np.array(tumor_patch["vertices"]))
        polygons["normal"].append(polygon)
    return polygons
Esempio n. 7
0
def triangulate_polygon_constrained(shape, additional_opts=""):
    """
    Perform constrained polygon triangulation. Essentially a compatibility layer between shapely and triangle.

    For more information about the triangulation, see documentation for triangle: https://rufat.be/triangle/API.html

    :param shape: shapely shape to triangulate
    :param additional_opts: additional options to  pass to triangle.triangulate(). "p" option is always used.
    :type additional_opts: str
    :return: vertices, faces; where vertices is a list of coordinates, and faces a list of 1-indexed face definitions.
    """
    if not _TRIANGLE_IMPORTED:
        raise EnvironmentError("Library 'triangle' required for triangulation.")
    if not _POLYLABEL_IMPORTED:
        raise EnvironmentError("Constrained polygon triangulation requires shapely>=1.7.0")
    # Polygon case
    if shape.geometryType() == "Polygon":
        tri = {"vertices": [], "segments": [], "holes": []}
        # add exterior edge
        ext_pt_cnt = len(shape.exterior.coords) - 1
        tri["vertices"] += shape.exterior.coords[:-1]
        tri["segments"] += [[i, i+1] for i in range(ext_pt_cnt-1)] + [[ext_pt_cnt-1, 0]]
        # add interior edges and holes
        offset = ext_pt_cnt
        for hole in shape.interiors:
            hole_pt_cnt = len(hole.coords) - 1
            tri["vertices"] += list(hole.coords[:-1])
            tri["segments"] += [[i, i+1] for i in range(offset, offset+hole_pt_cnt-1)] + [[offset+hole_pt_cnt-1, offset]]
            rp = shapelyPolygon(hole.coords).representative_point()
            tri["holes"].append(list(*rp.coords))
            offset += hole_pt_cnt
        if len(tri["holes"]) == 0:
            tri.pop("holes")
        # perform triangulation
        t = triangle.triangulate(tri, "p"+additional_opts)
        vertices = t["vertices"]
        faces = [[i+1 for i in j] for j in t["triangles"]]  # switch from 0- to 1-indexing
        return vertices, faces
    # MultiPolygon/GeometryCollection case (recursive)
    elif shape.geometryType() in ["MultiPolygon", "GeometryCollection"]:
        vertices, faces = [], []
        for part in shape:
            if part.geometryType() == "Polygon":
                v, f = triangulate_polygon_constrained(part, additional_opts)
                offset = len(vertices)
                vertices += [list(i) for i in v]
                faces += [[i+offset for i in j] for j in f]
        return vertices, faces
    # Unsupported geometry case
    else:
        raise NotImplementedError("Can't do constrained triangulation on geometry type " + shape.geometryType())
Esempio n. 8
0
def get_approx_tumor_mask(polygons, thumbnail_nrow, thumbnail_ncol, patch_size=256):
    """Indicate whether a particular tile overlaps with tumor annotation.

    The method has an approx in its name, as the entire tile
    might not be coming from a tumor annotated region as parts of
    it might actually be normal. We just report
    here if the patch overlaps with a tumor annotation. It might have
    an overlap with a normal region as well, but that is filtered
    in a later method so we don't worry about it here.

    Parameters
    ----------
    polygons: dict
              dict with keys ['normal', 'tumor']
              as obtained from `get_annotation_polygons`
    thumbnail_nrow: int
                    Number of rows in the thumbnail image
    thumbnail_ncol: int
                    Number of columns in the thumbnail

    Returns
    -------
    mask: array
          tumor mask
    """
    scaled_tumor_polygons = []
    for tpol in polygons["tumor"]:
        scaled = translate_and_scale_polygon(tpol, 0, 0, 1 / 256)
        scaled_tumor_polygons.append(scaled)
    polymasked = poly2mask(scaled_tumor_polygons, (thumbnail_nrow, thumbnail_ncol))
    # Is any of the masked out points inside a normal annotated region?
    poly_x, poly_y = np.where(polymasked > 0)
    set_to_zero = []
    for px, py in zip(poly_x, poly_y):
        point = shapelyPoint(px, py)
        for npol in polygons["normal"]:
            scaled = translate_and_scale_polygon(npol, 0, 0, 1 / 256)
            pol = shapelyPolygon(scaled.get_xy())
            if pol.contains(point):
                set_to_zero.append((px, py))

    if len(set_to_zero):
        set_to_zero = np.array(set_to_zero)
        polymasked[set_to_zero] = 0
    return polymasked
Esempio n. 9
0
def scoreMap(polygon, events, square_width):
    samples = createSamplePoints(polygon, square_width, 6371.0)
    points = []
    num_colors = 400
    radian_events = [(math.radians(lat), math.radians(lon), weight) for lat,lon,weight in events]
    for sample in samples:
        latitude = sample[1]
        for a, b, c, d, lon_middle in sample[3::]:
            points.append((math.radians(latitude),math.radians( lon_middle)))
    scores = compute.computeScores(radian_events, len(radian_events), points, len(points), num_colors)
    scores_list = compute.unsignedLongArray_frompointer(scores)
    patches = []
    i = 0
    colors = list()
    x,y = polygon.exterior.xy
    for sample in samples:
        lat_top = sample[0]
        lat_middle = sample[1]
        lat_bottom = sample[2]
        
        for lon_left_top, lon_left_bottom, lon_right_top, lon_right_bottom, lon_middle in sample[3::]:
            temp_polygon = [(lon_left_top, lat_top), (lon_right_top, lat_top), (lon_right_bottom, lat_bottom), (lon_left_bottom, lat_bottom)]
            sPoly = shapelyPolygon(temp_polygon)
            if polygon.contains(sPoly) or polygon.intersects(sPoly):
                patches.append(patchPolygon(temp_polygon, True))
                score = scores_list[i]
                colors.append(score*(100.0/num_colors))
            i+= 1
                
                
    patch_collection = PatchCollection(patches, cmap=matplotlib.cm.plasma, alpha=1.0)

    patch_collection.set_array(np.array(colors))
    figure, axis = plt.subplots()

    axis.add_collection(patch_collection)
    plt.plot(x, y)
    plt.show()
Esempio n. 10
0
    def _editFunc(self, selectedROIParam: RoiParams):
        """Callback triggered by right click or key press, required a selected Roi"""
        # extract handle points from the polygon
        poly = shapelyPolygon(selectedROIParam.roiFile.getRoi().verts)
        poly = poly.buffer(0)
        poly = poly.simplify(poly.length ** .5 / 5, preserve_topology=False)
        handles = poly.exterior.coords

        def done(verts, handles):
            verts = verts[0]
            newRoi = pwsdt.Roi.fromVerts(np.array(verts), selectedROIParam.roiFile.getRoi().mask.shape)
            self._polyWidg.set_active(False)
            self._roiManager.updateRoi(selectedROIParam.roiFile, newRoi)
            self.roiModified.emit(self.metadata, selectedROIParam.roiFile)

            self.enableHoverAnnotation(True)

        def cancelled():
            self.enableHoverAnnotation(True)

        self._polyWidg = PolygonModifier(self.ax, onselect=done, onCancelled=cancelled)
        self._polyWidg.set_active(True)
        self.enableHoverAnnotation(False)
        self._polyWidg.initialize([handles])
Esempio n. 11
0
def create_tumor_mask_from_tile(tile_x, tile_y, polygons, patch_size=256):
    """Create a patch_size x patch_size mask from tile_x,y coordinates
    Parameters
    ----------
    tile_x, tile_y:  int
    polygons: dict
              ['normal', 'tumor'] with corresponding polygons

    Returns
    -------
    mask: array
          patch_size x patch_size binary mask

    """

    # Initiate a zero mask
    mask = np.zeros((patch_size, patch_size))
    # patch_polygon = shapelyRectangle(tile_x, tile_y, patch_size, patch_size)
    x_min = tile_x
    y_min = tile_y
    x_max = x_min + 256
    y_max = y_min + 256
    patch_polygon = shapelyPolygon(
        [(x_min, y_min), (x_max, y_min), (x_max, y_max), (x_min, y_max)]
    )

    # Is it overlapping any of the tumor polygons?
    is_inside_tumor = [
        patch_polygon.intersection(polygon.buffer(0)) for polygon in polygons["tumor"]
    ]

    # the patch will always be inside just one annotated boundary
    # which are assumed to be non-overlapping and hence we can just fetch
    # the first sample
    tumor_poly_index = None
    tumor_poly_coords = None
    for index, sample_intersection in enumerate(is_inside_tumor):
        if sample_intersection.area > 0:
            tumor_poly_index = index
            if sample_intersection.geom_type == "Polygon":
                tumor_poly_coords = np.array(sample_intersection.exterior.coords)
            elif sample_intersection.geom_type == "MultiPolygon":
                tumor_poly_coords = []
                for p in sample_intersection:
                    tumor_poly_coords += p.exterior.coords
                tumor_poly_coords = np.array(tumor_poly_coords)
            elif sample_intersection.geom_type == "GeometryCollection":
                tumor_poly_coords = []
                for p in sample_intersection:
                    if p.geom_type == "LineString" or p.geom_type == "Point":
                        tumor_poly_coords += p.coords
                    elif p.geom_type == "Polygon":
                        tumor_poly_coords += p.exterior.coords
                    else:
                        print("Found geom_type:{}".format(p.geom_type))
                        raise ValueError("")
            else:
                print("Found geom_type:{}".format(sample_intersection.geom_type))
                raise ValueError("")
            break

    if tumor_poly_index is None:
        # No overlap with tumor so must return as is
        return mask

    # This path belongs to a tumor patch so set everything to one
    # Set these coordinates to one

    # Shift the tumor coordinates to tile_x, tile_y
    tumor_poly_coords = tumor_poly_coords - np.array([tile_x, tile_y])
    overlapping_tumor_poly = shapelyPolygon(tumor_poly_coords)
    # Create a psuedo mask
    psuedo_mask = poly2mask([overlapping_tumor_poly], (patch_size, patch_size))
    # Add it to the original mask
    mask = np.logical_or(mask, psuedo_mask)

    # If its inside tumor does this tumor patch actually contain any normal patches?
    tumor_poly = polygons["tumor"][tumor_poly_index]
    normal_patches_inside_tumor = get_common_interior_polygons(
        tumor_poly, polygons["normal"]
    )

    # For all the normal patches, ensure
    # we set the mask to zero
    for index in normal_patches_inside_tumor:
        normal_poly = polygons["normal"][index]

        # What is the intersection portion of this normal polygon
        # with our patch of interest?
        common_area = normal_poly.intersection(patch_polygon)
        if not common_area.is_valid:
            return mask
        if common_area.geom_type == "Polygon":
            normal_poly_coords = np.array(common_area.exterior.coords) - np.array(
                [tile_x, tile_y]
            )
        elif common_area.geom_type == "MultiPolygon":
            normal_poly_coords = []
            for p in common_area:
                normal_poly_coords += p.exterior.coords
            normal_poly_coords = np.array(normal_poly_coords) - np.array(
                [tile_x, tile_y]
            )
        elif common_area.geom_type == "LineString":
            normal_poly_coords = common_area.coords
        else:
            raise ValueError("Founr geom {}".format(common_area.geom_type))
        if common_area:
            # normal_poly_coords = np.array(
            #   common_area.exterior.coords) - np.array([tile_x, tile_y])
            overlapping_normal_poly = shapelyPolygon(normal_poly_coords)
            psuedo_mask = poly2mask([overlapping_normal_poly], (patch_size, patch_size))
            # Get coordinates wherever this is non zero
            non_zero_coords = np.where(psuedo_mask > 0)
            # Add set these explicitly to zero
            mask[non_zero_coords] = 0
    return mask