def clean_polygon(self, polygon):
        """清多边形

        Args:
            polygon ([type]): [description]

        Returns:
            [type]: [description]
        """
        simple = pyclipper.SimplifyPolygon(polygon, pyclipper.PFT_NONZERO)

        if simple is None or len(simple) == 0:
            return None

        biggest = simple[0]
        biggest_area = pyclipper.Area(biggest)
        for i in range(1, len(simple)):
            area = abs(pyclipper.Area(simple[i]))
            if area > biggest_area:
                biggest = simple[i]
                biggest_area = area

        clean = pyclipper.CleanPolygon(biggest, self.config['curveTolerance'])
        if clean is None or len(clean) == 0:
            return None
        return clean
示例#2
0
 def test_area(self):
     # area less than 0 because orientation is False
     area_neg = pyclipper.Area(PATH_SUBJ_1)
     area_pos = pyclipper.Area(PATH_SUBJ_1[::-1])
     self.assertLess(area_neg, 0)
     self.assertGreater(area_pos, 0)
     self.assertEqual(abs(area_neg), area_pos)
示例#3
0
def softnms(boxes, box_scores, char_scores=None, overlapThresh=0.3,
                          threshold=0.8, neighbourThresh=0.5, num_neig=0):
    scores = box_scores.copy()
    new_boxes = boxes[:, 0: 8].copy()
    if char_scores is not None:
        new_char_scores = char_scores.copy()
    polygons = [pyclipper.scale_to_clipper(poly.reshape((-1, 2))) for poly in new_boxes]
    areas = [pyclipper.scale_from_clipper(pyclipper.scale_from_clipper(
             pyclipper.Area(poly))) for poly in polygons]
    areas = [abs(_) for _ in areas]
    N = boxes.shape[0]
    order = np.arange(N)
    i = 0
    while i < N:
        max_pos = scores[order[i: N]].argmax() + i
        order[i], order[max_pos] = order[max_pos], order[i]
        pos = i + 1
        neighbours = list()
        while pos < N:
            try:
                pc = pyclipper.Pyclipper()
                pc.AddPath(polygons[order[i]], pyclipper.PT_CLIP, True)
                pc.AddPaths([polygons[order[pos]]], pyclipper.PT_SUBJECT, True)
                solution = pc.Execute(pyclipper.CT_INTERSECTION)
                if len(solution) == 0:
                    inter = 0
                else:
                    inter = pyclipper.scale_from_clipper(
                        pyclipper.scale_from_clipper(
                            pyclipper.Area(solution[0])))
            except Exception:
                inter = 0
            union = areas[order[i]] + areas[order[pos]] - inter
            iou = inter / union if union > 0 else 0
            if iou > neighbourThresh:
                neighbours.append(order[pos])
            weight = np.exp(-(iou **2) / 0.5)
            scores[order[pos]] *= weight
            if scores[order[pos]] < threshold:
                order[pos], order[N - 1] = order[N - 1], order[pos]
                N -= 1
                pos -= 1
            pos += 1
        if len(neighbours) >= num_neig:
            neighbours.append(order[i])
            temp_scores = box_scores[neighbours].reshape((-1, 1))
            new_boxes[order[i], :8] = (boxes[neighbours, :8] * temp_scores).sum(axis=0) / temp_scores.sum()
            if char_scores is not None:
                new_char_scores[order[i], :] = (char_scores[neighbours, :] * temp_scores).sum(axis=0) / temp_scores.sum()
        else:
            order[i], order[N - 1] = order[N - 1], order[i]
            N -= 1
            i -= 1
        i += 1
    keep = [order[_] for _ in range(N)]
    if char_scores is not None:
        return keep, new_boxes, new_char_scores
    else:
        return keep, new_boxes
示例#4
0
def area(vset):
    """ This function calculates the area of the set of FRV or ARV """
    # Initialize A as it could be calculated iteratively
    A = 0
    # Check multiple exteriors
    if type(vset[0][0]) == list:
        # Calc every exterior separately
        for i in range(len(vset)):
            A += pyclipper.scale_from_clipper(pyclipper.scale_from_clipper(pyclipper.Area(pyclipper.scale_to_clipper(vset[i]))))
    else:
        # Single exterior
        A = pyclipper.scale_from_clipper(pyclipper.scale_from_clipper(pyclipper.Area(pyclipper.scale_to_clipper(vset))))
    return A
def iou_clipper(p1, p2):
    pc = pyclipper.Pyclipper()
    pc.AddPath(to_coords(p1), pyclipper.PT_CLIP, True)
    pc.AddPath(to_coords(p2), pyclipper.PT_SUBJECT, True)
    I = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD,
                   pyclipper.PFT_EVENODD)
    if len(I) > 0:
        U = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD,
                       pyclipper.PFT_EVENODD)
        Ia = pyclipper.Area(I[0])
        Ua = pyclipper.Area(U[0])
        IoU = Ia / Ua
    else:
        IoU = 0.0
    return IoU
示例#6
0
def nms_poly(polys,
             scores,
             overlapThresh,
             neighbourThresh=0.5,
             minScore=0,
             num_neig=0):
    pick = list()
    suppressed = [False for _ in range(len(polys))]
    polygons = [
        pyclipper.scale_to_clipper(poly.reshape((-1, 2))) for poly in polys
    ]
    areas = [
        pyclipper.scale_from_clipper(
            pyclipper.scale_from_clipper(pyclipper.Area(poly)))
        for poly in polygons
    ]
    areas = [abs(_) for _ in areas]
    order = np.array(scores).argsort()[::-1]
    for _i, i in enumerate(order):
        if suppressed[i] is False:
            pick.append(i)
            neighbours = list()
            for j in order[_i + 1:]:
                if suppressed[j] is False:
                    try:
                        pc = pyclipper.Pyclipper()
                        pc.AddPath(polygons[i], pyclipper.PT_CLIP, True)
                        pc.AddPaths([polygons[j]], pyclipper.PT_SUBJECT, True)
                        solution = pc.Execute(pyclipper.CT_INTERSECTION)
                        if len(solution) == 0:
                            inter = 0
                        else:
                            inter = pyclipper.scale_from_clipper(
                                pyclipper.scale_from_clipper(
                                    pyclipper.Area(solution[0])))
                    except Exception as e:
                        inter = 0
                    union = areas[i] + areas[j] - inter
                    iou = inter / union if union > 0 else 0
                    if union > 0 and iou > overlapThresh:
                        suppressed[j] = True
                    if iou > neighbourThresh:
                        neighbours.append(j)
            if len(neighbours) < num_neig:
                for ni in neighbours:
                    suppressed[ni] = False
                pick.pop()
    return pick
def moveForwardToCutThreshold(cleared, stepDistance, toReachArea, maxArea):
    global last_gui_update
    passes=0
    while True:
        if not moveForward(stepDistance): #reached the end of current path
            if not nextPath(): #reached the end of all paths
                passes=passes+1
                if passes>1: return False

        cpt, dr = getCurrentPoint()
        toolInPos = translatePath(toolGeometry,cpt) #move tool to current position
        # calculate cut area in the current poisiton
        cp.Clear()
        cp.AddPath(toolInPos, pyclipper.PT_SUBJECT, True)
        cp.AddPaths(cleared, pyclipper.PT_CLIP, True)
        cuttingPolygon=cp.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)
        tryCuttingArea = 0
        if time.time() - last_gui_update > GuiUtils.GUI_UPDATE_PERIOD:
            GuiUtils.sceneClearPaths("POLY")
            GuiUtils.sceneDrawFilledTool(
                "POLY", cpt, scale_factor, (0, 1, 0))
            GuiUtils.sceneUpdateGui()
            last_gui_update = time.time()
        for poly in cuttingPolygon:
            tryCuttingArea = tryCuttingArea + math.fabs(pyclipper.Area(poly))

        if tryCuttingArea > toReachArea and tryCuttingArea<maxArea:
            return True
示例#8
0
def check_and_validate_polys(polys, tags, xxx_todo_changeme):
    '''
    check so that the text poly is in the same direction,
    and also filter some invalid polygons
    :param polys:
    :param tags:
    :return:
    '''
    (h, w) = xxx_todo_changeme
    if polys.shape[0] == 0:
        return [], []
    polys[:, :, 0] = np.clip(polys[:, :, 0], 0, w - 1)
    polys[:, :, 1] = np.clip(polys[:, :, 1], 0, h - 1)

    validated_polys = []
    validated_tags = []
    for poly, tag in zip(polys, tags):
        if abs(pyclipper.Area(poly)) < 1:
            continue
        #clockwise
        if pyclipper.Orientation(poly):
            poly = poly[::-1]

        validated_polys.append(poly)
        validated_tags.append(tag)
    return np.array(validated_polys), np.array(validated_tags)
示例#9
0
def calcCutingArea(toolPos, newToolPos, toolRadiusScaled, cleared):

    dist = GeomUtils.magnitude(GeomUtils.sub2v(newToolPos, toolPos))
    if dist == 0:
        return 0, 0

    toolCoverArea = getToolCuttingShape(toolPos, newToolPos, toolRadiusScaled)

    if GeomUtils.anyValidPath(toolCoverArea):
        #calculate area
        cp.Clear()
        cp.AddPaths(toolCoverArea, pyclipper.PT_SUBJECT, True)
        cp.AddPaths(cleared, pyclipper.PT_CLIP, True)
        cuttingPolygon = cp.Execute(pyclipper.CT_DIFFERENCE,
                                    pyclipper.PFT_EVENODD,
                                    pyclipper.PFT_EVENODD)

        cuttingArea = 0
        cuttingAreaPerDist = 0
        for poly in cuttingPolygon:
            cuttingArea = cuttingArea + math.fabs(pyclipper.Area(poly))
            cuttingAreaPerDist = cuttingArea / dist
        return cuttingArea, cuttingAreaPerDist
    else:
        return 0, 0
示例#10
0
def shrink_poly(polys, ratio=0.5):

    if type(polys) == list:
        polys = np.array(polys)

    if ratio == 1: return polys
    """
    收缩多边形
    :param polys: 多边形
    :param ratio: 收缩比例
    :return:
    """
    area = abs(pyclipper.Area(polys))  # 面积
    _perimeter = perimeter(polys)  # 周长

    pco = pyclipper.PyclipperOffset()
    if _perimeter:
        # TODO:不知道为何这样计算???
        d = area * (1 - ratio * ratio) / _perimeter
        pco.AddPath(polys, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
        # 缩小后返回多边形
        polys_shrink = pco.Execute(-d)
    else:
        logger.warning("多边形周长为0")
        return None

    if len(polys_shrink) == 0:
        logger.debug("收缩多边形[面积=%f]失败,使用原有坐标", area)
        return polys
    shrinked_bbox = np.array(polys_shrink[0])
    return shrinked_bbox
示例#11
0
def nms_with_char_cls(boxes,
                      char_scores,
                      overlapThresh,
                      neighbourThresh=0.5,
                      minScore=0,
                      num_neig=0):
    new_boxes = np.zeros_like(boxes)
    new_char_scores = np.zeros_like(char_scores)
    pick = []
    suppressed = [False for _ in range(boxes.shape[0])]
    areas = [
        Polygon([(b[0], b[1]), (b[2], b[3]), (b[4], b[5]), (b[6], b[7])]).area
        for b in boxes
    ]
    polygons = pyclipper.scale_to_clipper(boxes[:, :8].reshape((-1, 4, 2)))
    order = boxes[:, 8].argsort()[::-1]
    for _i, i in enumerate(order):
        if suppressed[i] is False:
            pick.append(i)
            neighbours = list()
            for j in order[_i + 1:]:
                if suppressed[j] is False:
                    try:
                        pc = pyclipper.Pyclipper()
                        pc.AddPath(polygons[i], pyclipper.PT_CLIP, True)
                        pc.AddPaths([polygons[j]], pyclipper.PT_SUBJECT, True)
                        solution = pc.Execute(pyclipper.CT_INTERSECTION)
                        if len(solution) == 0:
                            inter = 0
                        else:
                            inter = pyclipper.scale_from_clipper(
                                pyclipper.scale_from_clipper(
                                    pyclipper.Area(solution[0])))
                    except:
                        inter = 0
                    union = areas[i] + areas[j] - inter
                    iou = inter / union if union > 0 else 0
                    if union > 0 and iou > overlapThresh:
                        suppressed[j] = True
                    if iou > neighbourThresh:
                        neighbours.append(j)
            if len(neighbours) >= num_neig:
                neighbours.append(i)
                temp_scores = (boxes[neighbours, 8] - minScore).reshape(
                    (-1, 1))
                new_boxes[i, :8] = (boxes[neighbours, :8] * temp_scores).sum(
                    axis=0) / temp_scores.sum()
                new_boxes[i, 8] = boxes[i, 8]
                new_char_scores[i, :] = (char_scores[neighbours, :] *
                                         temp_scores).sum(
                                             axis=0) / temp_scores.sum()
            else:
                for ni in neighbours:
                    suppressed[ni] = False
                pick.pop()
    return pick, new_boxes, new_char_scores
示例#12
0
    def clean_polygon(self, polygon):
        simple = pyclipper.SimplifyPolygon(polygon, pyclipper.PFT_NONZERO)

        if simple is None or len(simple) == 0:
            return None

        biggest = simple[0]
        biggest_area = pyclipper.Area(
            biggest)  # 给出端点,求多边形面积,端点顺序一定要是逆时针的,否则结果为负
        for i in range(1, len(simple)):
            area = abs(pyclipper.Area(simple[i]))
            if area > biggest_area:
                biggest = simple[i]
                biggest_area = area

        clean = pyclipper.CleanPolygon(biggest, self.config['curveTolerance'])
        if clean is None or len(clean) == 0:
            return None
        return clean
示例#13
0
def generate_seg(im_size, polys, tags, image_name, scale_ratio):
    '''
    标签生成
    :param im_size: 输入图片尺寸
    :param polys: 输入文本区域
    :param tags: 忽略的文本区域 tags
    :param image_name: 图片名称
    :param scale_ratio:ground truth的收缩比例饿, 默认值为[0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    :return:
    seg_maps: 不同收缩比例的分割结果,保存在不同的通道中
    training_mask: 忽略文本区域的mask
    '''
    h, w = im_size
    #mark different text poly
    seg_maps = np.zeros((h, w, 6), dtype=np.uint8)
    # mask used during traning, to ignore some hard areas
    training_mask = np.ones((h, w), dtype=np.uint8)
    ignore_poly_mark = []
    for i in range(len(scale_ratio)):
        seg_map = np.zeros((h, w), dtype=np.uint8)
        for poly_idx, poly_tag in enumerate(zip(polys, tags)):
            poly = poly_tag[0]
            tag = poly_tag[1]

            # 忽略'*','###','?'等文本区域
            if i == 0 and tag:
                cv2.fillPoly(training_mask,
                             poly.astype(np.int32)[np.newaxis, :, :], 0)
                ignore_poly_mark.append(poly_idx)

            # seg map
            shrinked_polys = []
            if poly_idx not in ignore_poly_mark:
                shrinked_polys = shrink_poly(poly.copy(),
                                             scale_ratio[i])  #收缩区域坐标计算

            if not len(shrinked_polys) and poly_idx not in ignore_poly_mark:
                logger.info(
                    "before shrink poly area:{} len(shrinked_poly) is 0,image {}"
                    .format(abs(pyclipper.Area(poly)), image_name))
                # if the poly is too small, then ignore it during training
                cv2.fillPoly(training_mask,
                             poly.astype(np.int32)[np.newaxis, :, :], 0)
                ignore_poly_mark.append(poly_idx)
                continue
            for shrinked_poly in shrinked_polys:
                seg_map = cv2.fillPoly(
                    seg_map, [np.array(shrinked_poly).astype(np.int32)], 1)

        seg_maps[..., i] = seg_map
    return seg_maps, training_mask
示例#14
0
def store_to_gd(gerber_data, tracks, pads, regions, apertures, tracksize,
                isDark):
    # Stores the existing set of layer data as polygonal data points
    # This is the equivalent of rasterisation of the draw commands
    li = len(gerber_data.layers) / 3
    # Expand tracks from centrelines based on aperture
    track_outlines = []
    for seg in range(len(tracks)):
        for vert in range(len(tracks[seg]) - 1):
            xstart = tracks[seg][vert][0]
            xend = tracks[seg][vert + 1][0]
            ystart = tracks[seg][vert][1]
            yend = tracks[seg][vert + 1][1]
            singletrack = pyclipper.MinkowskiSum(apertures[tracksize[seg]], \
                                                 [[xstart, ystart], [xend, yend]], -1)
            if len(singletrack) > 1:
                biggest = []
                myarea = 0
                for mypath in singletrack:
                    newarea = pyclipper.Area(mypath)
                    if newarea > myarea:
                        biggest = mypath
                        myarea = newarea
                singletrack = [[]]
                singletrack[0] = (biggest)
            track_outlines.extend(singletrack)

    mergedBounds = union_boundary(track_outlines + pads, regions)

    # Store data into layers.
    gerber_data.layers.append(
        GerberLayer(isDark,
                    str(li) + "_Tracks",
                    track_outlines,
                    type=GerberLayer.TYPE_TRACK))
    gerber_data.layers.append(
        GerberLayer(isDark,
                    str(li) + "_Boundaries", mergedBounds, False, False,
                    "blue", GerberLayer.TYPE_BOUNDARY))
    # gerber_data.layers.append(GerberLayer(isDark, str(li) + "_Boundaries", track_outlines + pads, False, False, "blue"))
    gerber_data.layers.append(
        GerberLayer(isDark,
                    str(li) + "_Regions",
                    regions,
                    type=GerberLayer.TYPE_REGION))
    gerber_data.layers.append(
        GerberLayer(isDark,
                    str(li) + "_Pads",
                    pads,
                    type=GerberLayer.TYPE_PAD,
                    color="#009000"))
示例#15
0
def clipExecute(subjectContours,
                clipContours,
                operation,
                subjectFillType="nonZero",
                clipFillType="nonZero"):
    pc = pyclipper.Pyclipper()

    for i, subjectContour in enumerate(subjectContours):
        try:
            pc.AddPath(subjectContour, pyclipper.PT_SUBJECT)
        except pyclipper.ClipperException:
            # skip invalid paths with no area
            if pyclipper.Area(subjectContour) != 0:
                raise InvalidSubjectContourError(
                    "contour %d is invalid for clipping" % i)

    for j, clipContour in enumerate(clipContours):
        try:
            pc.AddPath(clipContour, pyclipper.PT_CLIP)
        except pyclipper.ClipperException:
            # skip invalid paths with no area
            if pyclipper.Area(clipContour) == 0:
                raise InvalidClippingContourError(
                    "contour %d is invalid for clipping" % j)

    bounds = pc.GetBounds()
    if (bounds.bottom, bounds.left, bounds.top, bounds.right) == (0, 0, 0, 0):
        # do nothing if there are no paths
        return []

    try:
        solution = pc.Execute(_operationMap[operation],
                              _fillTypeMap[subjectFillType],
                              _fillTypeMap[clipFillType])
    except pyclipper.ClipperException as exc:
        raise ExecutionError(exc)

    return [[tuple(p) for p in path] for path in solution]
示例#16
0
def shrink_poly(poly, r):
    try:
        area_poly = abs(pyclipper.Area(poly))
        perimeter_poly = perimeter(poly)
        poly_s = []
        pco = pyclipper.PyclipperOffset()
        if perimeter_poly:
            d = area_poly * (1 - r * r) / perimeter_poly
            pco.AddPath(poly, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
            poly_s = pco.Execute(-d)
        return poly_s
    except Exception as e:
        traceback.print_exc()
        raise e
示例#17
0
def generate_seg(im_size, polys, tags, image_name, scale_ratio):
    '''
    :param im_size: input image size
    :param polys: input text regions
    :param tags: ignore text regions tags
    :param image_index: for log
    :param scale_ratio:ground truth scale ratio, default[0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    :return:
    seg_maps: segmentation results with different scale ratio, save in different channel
    training_mask: ignore text regions
    '''
    h, w = im_size
    #mark different text poly
    seg_maps = np.zeros((h, w, 6), dtype=np.uint8)
    # mask used during traning, to ignore some hard areas
    training_mask = np.ones((h, w), dtype=np.uint8)
    ignore_poly_mark = []
    for i in range(len(scale_ratio)):
        seg_map = np.zeros((h, w), dtype=np.uint8)
        for poly_idx, poly_tag in enumerate(zip(polys, tags)):
            poly = poly_tag[0]
            tag = poly_tag[1]

            # ignore ###
            if i == 0 and tag:
                cv2.fillPoly(training_mask,
                             poly.astype(np.int32)[np.newaxis, :, :], 0)
                ignore_poly_mark.append(poly_idx)

            # seg map
            shrinked_polys = []
            if poly_idx not in ignore_poly_mark:
                shrinked_polys = shrink_poly(poly.copy(), scale_ratio[i])

            if not len(shrinked_polys) and poly_idx not in ignore_poly_mark:
                logger.info(
                    "before shrink poly area:{} len(shrinked_poly) is 0,image {}"
                    .format(abs(pyclipper.Area(poly)), image_name))
                # if the poly is too small, then ignore it during training
                cv2.fillPoly(training_mask,
                             poly.astype(np.int32)[np.newaxis, :, :], 0)
                ignore_poly_mark.append(poly_idx)
                continue
            for shrinked_poly in shrinked_polys:
                seg_map = cv2.fillPoly(
                    seg_map, [np.array(shrinked_poly).astype(np.int32)], 1)

        seg_maps[..., i] = seg_map
    return seg_maps, training_mask
示例#18
0
def centerOfMass( polygon ):
	x = 0
	y = 0
	p0 = polygon[len(polygon)-1];
	for p1 in polygon:
		second_factor = ((p0[0] * p1[1]) - (p1[0] * p0[1]))
		x += (p0[0] + p1[0]) * second_factor
		y += (p0[1] + p1[1]) * second_factor
		p0 = p1
	area = pyclipper.Area(polygon);
	x = x / 6 / area;
	y = y / 6 / area;

	if (x < 0):
		x = -x;
		y = -y;
	return (x,y);
示例#19
0
def appendToolPathCheckCollision(of,
                                 cp,
                                 toolPaths,
                                 passToolPath,
                                 toolRadiusScaled,
                                 cleared,
                                 close=False):
    #appending pass toolpath to the list of cuts
    #checking the jump line for obstacles
    global output_point_count

    if len(passToolPath) < 1: return
    jumpType = 1  # assume no lift
    nextPoint = passToolPath[0]
    if len(toolPaths) != 0 and len(
            toolPaths[-1]) > 0:  #if this is first path: lift to safe height
        lastPath = toolPaths[-1]
        lastPoint = lastPath[-1]
        #make tool shape from last point to next point
        of = pyclipper.PyclipperOffset()
        of.AddPath([lastPoint, nextPoint], pyclipper.JT_ROUND,
                   pyclipper.ET_OPENROUND)
        toolShape = of.Execute(toolRadiusScaled - 2)
        #check clearance
        cp.Clear()
        cp.AddPaths(toolShape, pyclipper.PT_SUBJECT, True)
        cp.AddPaths(cleared, pyclipper.PT_CLIP, True)
        crossing = cp.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD,
                              pyclipper.PFT_EVENODD)
        collisionArea = 0
        for path in crossing:
            collisionArea = collisionArea + math.fabs(pyclipper.Area(path))
        if collisionArea > 0:
            jumpType = 2
        toolPaths.append([[lastPoint[0], lastPoint[1], jumpType],
                          [nextPoint[0], nextPoint[1], jumpType]])

    #passToolPath = pyclipper.CleanPolygon(passToolPath,0.7) # this messes up the start point (adds a point to the start of path)
    output_point_count = output_point_count + len(passToolPath)
    if len(passToolPath) > 0:
        if close:
            passToolPath = GeomUtils.closePath(passToolPath)
        toolPaths.append(passToolPath)
示例#20
0
    def create_mask(self, datafield, myCell):

        named_layers = defaultdict(dict)

        for l1 in self.points:
            Polygon = namedtuple('Polygon', ['area', 'points'])
            pp = Polygon(area=pyclipper.Area(l1), points=l1)

            if pp.area < 0:
                if 'holes' in named_layers:
                    named_layers['holes'].append(pp)
                else:
                    named_layers['holes'] = [pp]
            elif pp.area > 0:
                if 'polygon' in named_layers:
                    named_layers['polygon'].append(pp)
                else:
                    named_layers['polygon'] = [pp]
            else:
                raise ValueError('polygon area cannot be zero')

        for poly in named_layers['polygon']:
            add_to_mask = True

            for hole in named_layers['holes']:
                if abs(hole.area) < abs(poly.area):

                    if utils.is_nested_polygons(hole, poly):
                        datafield.add(poly.points,
                                      self.key,
                                      holes=hole.points,
                                      model='model')
                        myCell.add(gdspy.Polygon(hole.points, layer=81))
                        add_to_mask = False
                    else:
                        datafield.add(poly.points, self.key, model='model')
                        add_to_mask = False

            if add_to_mask:
                datafield.add(poly.points, self.key, model='model')

            myCell.add(gdspy.Polygon(poly.points, self.key[0], verbose=False))
示例#21
0
    def process_row(self, row):
        if row.object_name not in self.classes:
            return None
        # Deal with excluded areas
        row_poly = [(row.xmin, row.ymin), (row.xmin, row.ymax),
                    (row.xmax, row.ymax), (row.xmax, row.ymin)]
        row_area = (row.xmax - row.xmin) * (row.ymax - row.ymin)
        for poly in self.exclude:
            pc = pyclipper.Pyclipper()
            pc.AddPath(poly, pyclipper.PT_CLIP, True)
            pc.AddPath(row_poly, pyclipper.PT_SUBJECT, True)
            inter = pc.Execute(pyclipper.CT_INTERSECTION,
                               pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)
            if len(inter) == 0:
                continue
            inter_area = pyclipper.Area(inter[0])
            if inter_area / row_area > 0.6:
                return None

        # Deal w/ crop
        crop = self.crop  # lazy
        if not crop:
            return row
        if row.xmax < crop.xmin or crop.xmax < row.xmin or \
                row.ymax < crop.ymin or crop.ymax < row.ymin:
            return None
        xA = min(row.xmax, crop.xmax)
        yA = min(row.ymax, crop.ymax)
        xB = max(row.xmin, crop.xmin)
        yB = max(row.ymin, crop.ymin)
        inter_area = (xA - xB) * (yA - yB)
        row_area = (row.xmax - row.xmin) * (row.ymax - row.ymin)
        if inter_area / row_area < 0.25:
            return None
        else:
            return row
示例#22
0
def Execute(op, obj, feat_num, feat, p_scale_factor):
    global toolGeometry
    global optimalCutAreaPerDist
    global iteration_limit_count
    global total_point_count
    global total_iteration_count
    global topZ
    global toolRadiusScaled
    global output_point_count
    global cache_hit_count
    global cache_pot_count
    global cache
    global cp
    global of
    global scale_factor

    scale_factor = p_scale_factor

    if RELOAD_MODULES:
        reload(Interpolation)
        reload(EngagementPoint)
        reload(GeomUtils)

    toolDiaScaled = op.tool.Diameter * scale_factor
    toolRadiusScaled = toolDiaScaled / 2
    perf_start_time = time.time()
    perf_total_len = 0.0
    print "toolRadiusScaled: ", toolRadiusScaled
    helixDiameter = min(
        op.tool.Diameter, 1000.0 if obj.HelixDiameterLimit.Value == 0.0 else
        obj.HelixDiameterLimit.Value)
    print "Helix diameter: ", helixDiameter
    helixDiameterScaled = helixDiameter * scale_factor
    stepOver = 0.01 * obj.StepOver  # percentage to factor
    stepOverDistanceScaled = toolDiaScaled * stepOver
    finishPassOffset = 1.0 * obj.Tolerance / 2
    cache_hit_count = 0
    cache_pot_count = 0
    cache = {}
    output_point_count = 0
    topZ = op.stock.Shape.BoundBox.ZMax

    #initialization
    of = pyclipper.PyclipperOffset()
    cp = pyclipper.Pyclipper()

    toleranceScaled = int(obj.Tolerance * scale_factor)

    stepScaled = 10

    toolGeometry = genToolGeometry(toolRadiusScaled + 1)

    # intitalization = calculate slot cutting area per step i.e. 100% step over
    sceneInit(toolRadiusScaled, topZ, scale_factor)

    distScaled = toolRadiusScaled / 2
    slotStep = translatePath(toolGeometry, [0, distScaled])
    cp.Clear()
    cp.AddPath(toolGeometry, pyclipper.PT_SUBJECT, True)
    cp.AddPath(slotStep, pyclipper.PT_CLIP, True)
    crossing = cp.Execute(pyclipper.CT_DIFFERENCE, pyclipper.PFT_EVENODD,
                          pyclipper.PFT_EVENODD)
    referenceCutArea = pyclipper.Area(crossing[0])
    fullSlotAreaPerDist = referenceCutArea / distScaled
    bound_extend = int(toolDiaScaled)

    #optimalCutAreaPerDistance (in scaled units)
    optimalCutAreaPerDist = stepOver * fullSlotAreaPerDist
    print "Optimal APD: ", optimalCutAreaPerDist, " Clipper scale factor: ", scale_factor, " Tolerance: ", obj.Tolerance, " Tolerance scaled: ", toleranceScaled
    try:
        # find cut region toolpath polygons
        of.Clear()
        of.AddPaths(feat, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
        cut_region_tp = of.Execute(-int(finishPassOffset * scale_factor) -
                                   toolRadiusScaled)
        cut_region_tp_polytree = of.Execute2(
            -int(finishPassOffset * scale_factor) - toolRadiusScaled)
        cut_region_tp = pyclipper.CleanPolygons(cut_region_tp)

        sceneDrawPaths("BOUNDARY", cut_region_tp, scale_factor, (1, 0, 0),
                       True)

        cleared, startPoint = findStartPoint(op, feat_num, cut_region_tp,
                                             cut_region_tp_polytree,
                                             helixDiameterScaled / 2,
                                             toolRadiusScaled, scale_factor)

        if cleared == None: return [], [0, 0]
        cleared = pyclipper.CleanPolygons(cleared)
        toolPos = startPoint

        of.Clear()
        of.AddPath([startPoint, startPoint], pyclipper.JT_ROUND,
                   pyclipper.ET_OPENROUND)
        helixTp = of.Execute(helixDiameterScaled / 2)
        sceneDrawPaths("TOOLPATH", helixTp, scale_factor, (0, 0, 1), True)

        EngagementPoint.Initialize(cut_region_tp, toolRadiusScaled, stepScaled,
                                   scale_factor)
        total_point_count = 1
        total_iteration_count = 0
        iteration_limit_count = 0
        toolPaths = []
        no_cut_count = 0
        over_cut_count = 0
        toolPos = [startPoint[0], startPoint[1] - helixDiameterScaled / 2]
        toolDir = [1.0, 0.0]
        firstEngagePoint = True
        last_tool_gui_update = 0
        pas = 0

        while True:
            pas = pas + 1
            #print "pass:"******"finding next pass engange point... pas:"******"Pass: %d\n"%pas)

            if toolPos == None:
                Console.PrintMessage("next engage point not found\n")
                break  #nothing more to cut

            passToolPath = []
            toClearPath = []
            cumulativeCuttingArea = 0
            no_cut_count = 0
            reachedBoundaryPoint = None
            isOutside = False

            gyro = [toolDir] * 5
            toolDir = GeomUtils.normalize(GeomUtils.sumv(gyro))

            if SHOW_MARKERS:
                sceneClearPaths("ENGAGE")
                sceneDrawToolDir("ENGAGE", toolPos, toolDir, scale_factor,
                                 (0, 1, 0))

            engagePoint = toolPos
            #iteration through the points on path/pass
            i = 0
            deflectionAngle = math.pi  #init
            del deflectionAngleHistory[:]
            distToBoundary = 0
            while True:  #points
                i = i + 1

                sceneUpdateGui()

                if obj.StopProcessing:
                    break
                #Console.PrintMessage("findNextPoint: %d =================================================================\n"%i)
                total_point_count = total_point_count + 1
                toolDir = GeomUtils.normalize(GeomUtils.sumv(gyro))

                #distance to the boundary line
                #if distToBoundary<toolRadiusScaled:
                clp, distToBoundary = GeomUtils.getClosestPointOnPaths(
                    cut_region_tp, toolPos)

                distToEngagePoint = GeomUtils.magnitude(
                    GeomUtils.sub2v(toolPos, engagePoint))

                relDistToBoundary = 2.0 * distToBoundary / toolRadiusScaled
                minCutAreaPerDist = optimalCutAreaPerDist / 3 + 1
                #if we are away from end boundary line, try making the optimal cut
                if relDistToBoundary > 1 or distToEngagePoint < toolRadiusScaled:
                    targetArea = optimalCutAreaPerDist
                else:  #decrease the cut area if we are close to boundary, adds a little bit of smoothing to the end of cut
                    targetArea = relDistToBoundary * \
                        (optimalCutAreaPerDist-minCutAreaPerDist) + minCutAreaPerDist

                if distToBoundary < toolRadiusScaled or distToEngagePoint < toolRadiusScaled:
                    stepScaled = toleranceScaled * 2
                elif math.fabs(deflectionAngle) > 0.0001:
                    stepScaled = 4.0 / deflectionAngle
                else:
                    stepScaled = toleranceScaled * 4

                if stepScaled < toleranceScaled * 2:
                    stepScaled = toleranceScaled * 2
                if stepScaled > toolRadiusScaled / 2:
                    stepScaled = toolRadiusScaled / 2

                #
                # Find next point with optimal cut
                #

                bound_box = [
                    [toolPos[0] - bound_extend, toolPos[1] - bound_extend],
                    [toolPos[0] + bound_extend, toolPos[1] - bound_extend],
                    [toolPos[0] + bound_extend, toolPos[1] + bound_extend],
                    [toolPos[0] - bound_extend, toolPos[1] + bound_extend]
                ]
                cp.Clear()
                cp.AddPath(bound_box, pyclipper.PT_SUBJECT, True)
                cp.AddPaths(cleared, pyclipper.PT_CLIP, True)
                cleared_bounded = cp.Execute(pyclipper.CT_INTERSECTION,
                                             pyclipper.PFT_EVENODD,
                                             pyclipper.PFT_EVENODD)
                if not GeomUtils.anyValidPath(cleared_bounded):
                    cleared_bounded = cleared

                newToolPos, newToolDir, cuttingAreaPerDist, cuttingArea, deflectionAngle = findNextPoint(
                    obj, op, of, cp, cleared_bounded, toolPos, toolDir,
                    toolRadiusScaled, stepScaled, targetArea, scale_factor)
                #
                # CHECK if we reached the the boundary
                #
                if distToBoundary < toolRadiusScaled and isOutsideCutRegion(
                        newToolPos, cut_region_tp_polytree, True):
                    isOutside = True
                    reachedBoundaryPoint = GeomUtils.getIntersectionPointLWP(
                        [toolPos, newToolPos], cut_region_tp)

                    if reachedBoundaryPoint != None:
                        #print "reachedBoundaryPoint:", reachedBoundaryPoint
                        #showTool("TL", reachedBoundaryPoint, scale_factor, (1, 0, 0))
                        newToolPos = reachedBoundaryPoint
                    else:
                        newToolPos = toolPos

                    cuttingArea, cuttingAreaPerDist = calcCutingArea(
                        toolPos, newToolPos, toolRadiusScaled, cleared_bounded)

                if cuttingArea > 3 * cuttingAreaPerDist + 10 and cuttingAreaPerDist > 2 * optimalCutAreaPerDist + 10:
                    over_cut_count = over_cut_count + 1
                    Console.PrintMessage("Break: over cut (%d %f/%f)\n" %
                                         (over_cut_count, cuttingAreaPerDist,
                                          optimalCutAreaPerDist))
                    break
                else:
                    over_cut_count = 0

                if len(toClearPath) == 0: toClearPath.append(toolPos)
                toClearPath.append(newToolPos)
                if firstEngagePoint:
                    if len(toClearPath) > 10:
                        of.Clear()
                        of.AddPath(toClearPath, pyclipper.JT_ROUND,
                                   pyclipper.ET_OPENROUND)
                        toolCoverArea = of.Execute(toolRadiusScaled + 1)[0]
                        cleared = expandClearedArea(cp, toolCoverArea, cleared)
                        toClearPath = []

                if cuttingArea > 0:
                    # cut is OK, record it
                    cumulativeCuttingArea = cumulativeCuttingArea + cuttingArea
                    if time.time() - last_tool_gui_update > GUI_UPDATE_PERIOD:
                        if SHOW_MARKERS:
                            sceneClearPaths("TP")
                            sceneDrawFilledTool("TP", newToolPos, scale_factor,
                                                (0, 0, 1))
                            sceneDrawToolDir("TP", newToolPos, newToolDir,
                                             scale_factor, (0, 0, 1))

                        sceneClearPaths("PTP")
                        sceneDrawPath("PTP", passToolPath, scale_factor,
                                      (0, 0, 1))
                        # sceneClearPaths("CL_BOUNDED")
                        # sceneDrawPaths("CL_BOUNDED", cleared_bounded,scale_factor,(1,1,0),True)
                        last_tool_gui_update = time.time()
                    #append next point to toolpath

                    perf_total_len = perf_total_len + stepScaled
                    if i == 0:
                        passToolPath.append(
                            toolPos)  #append first point to toolpath
                    passToolPath.append(newToolPos)
                    toolPos = newToolPos
                    gyro.append(newToolDir)
                    gyro.pop(0)
                    no_cut_count = 0
                else:  #no cut
                    #print "no cut:", no_cut_count
                    no_cut_count = no_cut_count + 1
                    newToolDir = toolDir
                    break
                    # if no_cut_count > 1:
                    #     print "break: no cut"
                    #     break

                if isOutside:  # next valid cut not found
                    #print "Breaking: reached boundary"
                    break
                #distToBoundary = distToBoundary-stepScaled
                #END OF POINTS INTERATION

            #expand cleared area
            if len(toClearPath) > 0:
                of.Clear()
                of.AddPath(toClearPath, pyclipper.JT_ROUND,
                           pyclipper.ET_OPENROUND)
                toolCoverArea = of.Execute(toolRadiusScaled + 1)[0]
                cleared = expandClearedArea(cp, toolCoverArea, cleared)
                toClearPath = []

            if cumulativeCuttingArea > stepScaled * stepOver * referenceCutArea / 40:  #did we cut something significant?
                sceneClearPaths("PTP")
                sceneDrawPath("TOOLPATH", passToolPath, scale_factor)
                passToolPath = GeomUtils.cleanPath(passToolPath,
                                                   CLEAN_PATH_TOLERANCE)
                appendToolPathCheckCollision(of, cp, toolPaths, passToolPath,
                                             toolRadiusScaled, cleared)

            if over_cut_count > 5:
                Console.PrintError(
                    "Break: WARNING: resulting toolpath may be incomplete! (Hint: try changing numeric precision or StepOver)\n"
                )
                break
            #FIND NEXT ENGAGING POINT
            if firstEngagePoint:
                EngagementPoint.moveToClosestPoint(newToolPos)
                firstEngagePoint = False
            else:
                moveDistance = stepOverDistanceScaled / 4 + 1
                if not EngagementPoint.moveForwardToCutThreshold(
                        cleared, moveDistance, moveDistance * 2,
                        1.5 * optimalCutAreaPerDist * moveDistance):
                    break

            #clear around the engagement point
            toolPos, toolDir = EngagementPoint.getCurrentPoint()

        performance = 1.0 * perf_total_len / scale_factor / (
            time.time() - perf_start_time)  # mm/s
        Console.PrintMessage(
            "Passes: %s, Toolpaths: %d, Output Points: %d, Processed Points: %d, Avg.Iterations: %f, Exceeded: %d, Perf.: %f mm/s, Cut shape cache hit: %d/%d (%f perc.)\n"
            %
            (pas, len(toolPaths), output_point_count, total_point_count,
             1.0 * total_iteration_count / total_point_count,
             iteration_limit_count, performance, cache_hit_count,
             cache_pot_count, 100 * cache_hit_count / (cache_pot_count + 0.1)))

        #generate finishing pass
        sceneUpdateGui()
        passToolPath = []
        of.Clear()
        of.AddPaths(feat, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
        finishing = of.Execute2(-toolRadiusScaled)
        # add only paths containing the startPoint and their childs
        for child in finishing.Childs:
            if pyclipper.PointInPolygon(startPoint, child.Contour) != 0:
                appendToolPathCheckCollision(
                    of, cp, toolPaths,
                    GeomUtils.cleanPath(child.Contour,
                                        CLEAN_PATH_TOLERANCE / 2),
                    toolRadiusScaled, cleared, True)
                for hole in child.Childs:
                    appendToolPathCheckCollision(
                        of, cp, toolPaths,
                        GeomUtils.cleanPath(hole.Contour,
                                            CLEAN_PATH_TOLERANCE / 2),
                        toolRadiusScaled, cleared, True)

        # append the return to the initial point (and check collision)
        if len(toolPaths) > 0 and len(toolPaths[0]) > 0:
            appendToolPathCheckCollision(
                of, cp, toolPaths, [[toolPaths[0][0][0], toolPaths[0][0][1]]],
                toolRadiusScaled, cleared, True)
    except:
        sceneClean()
        raise

    sceneClean()
    return toolPaths, startPoint
示例#23
0
def parse(f):
    dxf = ezdxf.readfile(f)
    mds = dxf.blocks
    listShapes = []

    for e in mds.__iter__():
        s = Shape()
        dicLayerPolyline = {1: s.cutPolyline, 14: s.shapePolyline}
        polylineFragments = []
        noDuplicates = []
        s.fileName = e.name

        for ez in e.__iter__():
            """
                This will ignore layer which are not a number
                TODO: change it later when we need a better dxf parser
            """
            try:
                layer = int(ez.get_dxf_attrib("layer"))
            except:
                continue

            if ez.dxftype() == "POLYLINE":
                vertList = list(ez.points())
                p = Polyline()
                p.listToPolyline(vertList)
                if pyclipper.Area(p.polylineToTuple()) < 0:
                    vertList = vertList[::-1]
                if ez.is_closed:  # closing polyline if the attribute is_closed is true
                    vertList.append(vertList[0])
                if layer == 8:  # if layer is non permanant marking
                    s.dicMarkings[8].append(Polyline())
                    dicLayerPolyline[8] = s.dicMarkings[8][-1]
                if (layer in dicLayerPolyline
                        and len(dicLayerPolyline[layer].vertices) > 2):
                    polylineFragments.append(vertList)
                else:
                    if (
                            layer not in dicLayerPolyline
                    ):  # if layer is not in a specific layer of shape (unusedLayer)
                        pUnused = Polyline()
                        if layer not in s.unusedLayer:
                            s.unusedLayer[layer] = [pUnused]
                    for idx, v in enumerate(vertList):
                        if v == vertList[
                                idx - 1] and idx != 0:  # skip duplicate vertex
                            continue
                        if layer in dicLayerPolyline:
                            addVertexToLayer(dicLayerPolyline[layer],
                                             convert2Vertex(v))
                        else:  # add to unused layer
                            addVertexToLayer(pUnused, convert2Vertex(v))
            elif ez.dxftype() == "POINT":
                if layer == 13:  # adding marking points which are in layer 13
                    s.dicMarkings[13].append(Polyline())
                    dicLayerPolyline[13] = s.dicMarkings[13][-1]
                    addVertexToLayer(dicLayerPolyline[13],
                                     convert2Vertex(ez.dxf.location))
                    addVertexToLayer(
                        dicLayerPolyline[13], convert2Vertex(ez.dxf.location)
                    )  # need to add it twice to have the points in the polyline

            elif (ez.dxftype() == "TEXT" and layer != 19
                  and ez.get_dxf_attrib("text")[0] == "#"):
                coord = ez.get_dxf_attrib("insert")
                tag = ez.get_dxf_attrib("text")
                newTextVertex = Vertex(coord[0], coord[1], tag)
                duplicate = False  # avoid duplicate vertex
                for v in noDuplicates:
                    if (
                            newTextVertex.is_equal(v)
                            and newTextVertex.name == v.name
                            and layer not in [4, 80, 81, 82, 83]
                    ):  # if duplicate point in notch don't set it to duplicate
                        duplicate = True
                        continue

                for mark in s.dicMarkings[8] + s.dicMarkings[13]:
                    for v in mark.vertices:
                        if newTextVertex.is_equal(v):
                            v.name = newTextVertex.name

                if (
                        duplicate
                ):  # If vertex is a duplicate, do not append to notches or textMarkings
                    continue

                if int(layer) in [4, 80, 81, 82, 83] and isNotchValid(
                        newTextVertex, s.notches):
                    s.notches.append(
                        Notch(
                            _x=newTextVertex.x,
                            _y=newTextVertex.y,
                            _name=newTextVertex.name,
                        ))
                else:
                    s.textMarkings.append(newTextVertex)
                noDuplicates.append(newTextVertex)

            elif ez.dxftype() == "LINE" and layer == 7:
                v1 = Vertex(ez.dxf.start[0], ez.dxf.start[1])
                v2 = Vertex(ez.dxf.end[0], ez.dxf.end[1])
                s.grainPolyline.vertices = [v1, v2]

        if polylineFragments:
            frags = []
            for p in polylineFragments:
                poly = []
                for v in p:
                    poly.append(convert2Vertex(v))
                frags.append(poly)
            frags.insert(0, s.cutPolyline.vertices)
            s.cutPolyline.vertices = mergePolylinesFragments(frags)

        # Assign rules to polylines in each layer:
        for layer in s.allPolyLayers:
            content = eval("s." + layer)
            if type(content) == type([]):
                for p in content:
                    for tag in s.textMarkings:
                        assignRulToShape(p, tag)
            else:
                for tag in s.textMarkings:
                    assignRulToShape(content, tag)

        for layer in list(s.dicMarkings.keys()):
            s.markings.extend(s.dicMarkings[layer])

        if (len(s.cutPolyline.vertices) or s.markings
            ):  # adding to the listShapes only if the shape has vertices
            listShapes.append(s)

    return listShapes
示例#24
0
 def test_area(self):
     with self.assertWarns(DeprecationWarning):
         pyclipper.Area(PATH_SUBJ_1)
示例#25
0
def lf_non_max_suppression_area(lf_xy_positions, confidences, overlap_range,
                                overlap_thresh):
    # lf_xy_positions = np.concatenate([l.data.cpu().numpy()[None,...] for l in lf_xy_positions])
    # lf_xy_positions = lf_xy_positions[:,:,:2,:2]

    # print lf_xy_positions
    # raw_input()
    lf_xy_positions = [l[:, :2, :2] for l in lf_xy_positions]
    #this assumes equal length positions
    # lf_xy_positions = np.concatenate([l[None,...] for l in lf_xy_positions])
    # lf_xy_positions = lf_xy_positions[:,:,:2,:2]

    c = confidences

    bboxes = []
    center_lines = []
    scales = []
    for i in range(len(lf_xy_positions)):
        pts = lf_xy_positions[i]
        # for i in xrange(lf_xy_positions.shape[1]):
        # pts = lf_xy_positions[:,i,:]
        if overlap_range is not None:
            pts = pts[overlap_range[0]:overlap_range[1]]

        f = pts[0]
        delta = f[:, 0] - f[:, 1]
        scale = np.sqrt((delta**2).sum())
        scales.append(scale)

        # ls = pts[:,:,0].tolist() + pts[:,:,1][::-1].tolist()
        # ls = [[int(x[0]), int(x[1])] for x in ls]
        # poly_regions.append(ls)
        center_lines.append((pts[:, :, 0] + pts[:, :, 1]) / 2.0)

        min_x = pts[:, 0].min()
        max_x = pts[:, 0].max()
        min_y = pts[:, 1].min()
        max_y = pts[:, 1].max()

        bboxes.append((min_x, min_y, max_x, max_y))

    bboxes = np.array(bboxes)

    if len(bboxes.shape) < 2:
        return []

    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]

    area = (x2 - x1 + 1) * (y2 - y1 + 1)
    idxs = np.argsort(c)

    overlapping_regions = []
    pick = []
    while len(idxs) > 0:

        last = len(idxs) - 1
        i = idxs[last]
        pick.append(i)

        xx1 = np.maximum(x1[i], x1[idxs[:last]])
        yy1 = np.maximum(y1[i], y1[idxs[:last]])
        xx2 = np.minimum(x2[i], x2[idxs[:last]])
        yy2 = np.minimum(y2[i], y2[idxs[:last]])

        # compute the width and height of the bounding box
        w = np.maximum(0, xx2 - xx1 + 1)
        h = np.maximum(0, yy2 - yy1 + 1)

        # compute the ratio of overlap
        overlap_bb = (w * h) / area[idxs[:last]]

        overlap = []
        for step, j in enumerate(idxs[:last]):
            #Skip anything that does't actually have any overlap
            if overlap_bb[step] < 0.1:
                overlap.append(0)
                continue

            path0 = center_lines[i]
            path1 = center_lines[j]

            path = np.concatenate([path0, path1[::-1]])
            path = [[int(x[0]), int(x[1])] for x in path]

            expected_scale = (scales[i] + scales[j]) / 2.0
            one_off_area = expected_scale**2 * (path0.shape[0] +
                                                path1.shape[0]) / 2.0

            simple_path = pyclipper.SimplifyPolygon(path,
                                                    pyclipper.PFT_NONZERO)
            inter_area = 0
            for path in simple_path:
                inter_area += abs(pyclipper.Area(path))

            area_ratio = inter_area / one_off_area
            area_ratio = 1.0 - area_ratio

            overlap.append(area_ratio)

        overlap = np.array(overlap)
        to_delete = np.concatenate(
            ([last], np.where(overlap > overlap_thresh)[0]))
        idxs = np.delete(idxs, to_delete)

    return pick
示例#26
0
def nms_with_char_cls(boxes,
                      char_scores,
                      overlapThresh,
                      neighbourThresh=0.5,
                      minScore=0,
                      num_neig=0):
    new_boxes = np.zeros_like(boxes)
    new_char_scores = np.zeros_like(char_scores)
    pick = []
    suppressed = [False for _ in range(boxes.shape[0])]
    areas = [
        Polygon([(b[0], b[1]), (b[2], b[3]), (b[4], b[5]), (b[6], b[7])]).area
        for b in boxes
    ]
    polygons = pyclipper.scale_to_clipper(boxes[:, :8].reshape((-1, 4, 2)))

    centers = [[(p[0][0] + p[1][0] + p[2][0] + p[3][0]) / 4,
                (p[0][1] + p[1][1] + p[2][1] + p[3][1]) / 4] for p in polygons]
    sides = []
    for p in polygons:
        x_coordinates = [p[0][0], p[1][0], p[2][0], p[3][0]]
        y_coordinates = [p[0][1], p[1][1], p[2][1], p[3][1]]

        side_x = max(x_coordinates) - min(x_coordinates)
        side_y = max(y_coordinates) - min(y_coordinates)
        sides.append([side_x, side_y])

    order = boxes[:, 8].argsort()[::-1]
    print('nms with char cls...')
    for _i, i in enumerate(tqdm(order)):
        if suppressed[i] is False:
            pick.append(i)
            neighbours = list()
            for j in order[_i + 1:]:
                var_x = ((sides[i][0] + sides[j][0]) / 2 -
                         abs(centers[i][0] - centers[j][0])) > 0
                var_y = ((sides[i][1] + sides[j][1]) / 2 -
                         abs(centers[i][1] - centers[j][1])) > 0
                if var_x and var_y and (suppressed[j] is False):
                    pc = pyclipper.Pyclipper()
                    pc.AddPath(polygons[i], pyclipper.PT_CLIP, True)
                    pc.AddPaths([polygons[j]], pyclipper.PT_SUBJECT, True)
                    solution = pc.Execute(pyclipper.CT_INTERSECTION)
                    if len(solution) == 0:
                        inter = 0
                    else:
                        inter = pyclipper.scale_from_clipper(
                            pyclipper.scale_from_clipper(
                                pyclipper.Area(solution[0])))
                    union = areas[i] + areas[j] - inter
                    iou = inter / union if union > 0 else 0
                    if union > 0 and iou > overlapThresh:
                        suppressed[j] = True
                    if iou > neighbourThresh:
                        neighbours.append(j)
            if len(neighbours) >= num_neig:
                neighbours.append(i)
                temp_scores = (boxes[neighbours, 8] - minScore).reshape(
                    (-1, 1))
                new_boxes[i, :8] = (boxes[neighbours, :8] * temp_scores).sum(
                    axis=0) / temp_scores.sum()
                new_boxes[i, 8] = boxes[i, 8]
                new_char_scores[i, :] = (char_scores[neighbours, :] *
                                         temp_scores).sum(
                                             axis=0) / temp_scores.sum()
            else:
                for ni in neighbours:
                    suppressed[ni] = False
                pick.pop()

    return pick, new_boxes, new_char_scores
示例#27
0
import pyclipper
import numpy as np

subj = [253, 285, 824, 296, 833, 435, 283, 413]
clipp = [215, 267, 853, 296, 826, 449, 246, 414]

subj = np.array(subj, dtype=np.float)
clipp = np.array(clipp, dtype=np.float)

subj = subj.reshape((4, 2))
clipp = clipp.reshape((4, 2))

pc = pyclipper.Pyclipper()
invalid = False
try:
    bool_subj = pc.AddPath(subj, pyclipper.PT_SUBJECT, True)
    bool_clipp = pc.AddPath(clipp, pyclipper.PT_CLIP, True)
except pyclipper.ClipperException as e:
    invalid = True
if not invalid:
    inter_path = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_EVENODD)
    union_path = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD)

    inter = pyclipper.Area(inter_path[0]) if len(inter_path) > 0 else .0
    uunion = pyclipper.Area(union_path[0]) if len(union_path) > 0 else .0
    ovr = inter / max(uunion, 1.)  # 防止0除溢出
else:
    ovr = .0
pc.Clear()

print("IoU: {:3f}".format(ovr))
示例#28
0
def evaluate_polygonal_results(ground_truth,
                               detection_results,
                               iou_thresh=0.5):
    """Evaluate polygonal text detection results and return TP, FP, FN.
    
    # Arguments
        ground_truth: List of ground truth polygonal with
            shape (objects, 4 x xy)
        detection_results: List of corresponding detection polygonal with 
            shape (objects, 4 x xy)
        image_size: Input size of detector network.
        iou_thresh: Minimum intersection over union required to associate
            a detected polygon box to a ground truth polygon box.
    
    # Returns
        TP: True Positive detections
        FP: False Positive detections
        FN: False Negative detections
    """

    # we do not sort by confidence here
    # all detections are of class text

    gt = ground_truth
    dt = detection_results

    TP = []
    FP = []
    FN_sum = 0

    num_groundtruth_boxes = 0  # has to be TP_sum + FN_sum
    num_detections = 0

    for i in range(len(gt)):  # samples
        gt_polys = [
            np.reshape(gt[i][j, :], (-1, 2)) for j in range(len(gt[i]))
        ]
        dt_polys = [
            np.reshape(dt[i][j, :], (-1, 2)) for j in range(len(dt[i]))
        ]

        # prepare polygones, pyclipper, is much faster
        scale = 1e5
        gt_polys = [np.asarray(p * scale, dtype=np.int64) for p in gt_polys]
        dt_polys = [np.asarray(p * scale, dtype=np.int64) for p in dt_polys]

        # perpare polygones, shapely
        #gt_polys = [geometry.Polygon(p) for p in gt_polys]
        #dt_polys = [geometry.Polygon(p) for p in dt_polys]

        num_dt = len(dt_polys)
        num_gt = len(gt_polys)

        num_groundtruth_boxes += num_gt
        num_detections += num_dt

        TP_img = np.zeros(num_dt)
        FP_img = np.zeros(num_dt)

        assignement = np.zeros(num_gt, dtype=np.bool)

        for k in range(len(dt[i])):  # dt
            poly1 = dt_polys[k]
            gt_iou = []
            for j in range(len(gt[i])):  # gt
                poly2 = gt_polys[j]

                # intersection over union, pyclipper
                pc = pyclipper.Pyclipper()
                pc.AddPath(poly1, pyclipper.PT_CLIP, True)
                pc.AddPath(poly2, pyclipper.PT_SUBJECT, True)
                I = pc.Execute(pyclipper.CT_INTERSECTION,
                               pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)
                if len(I) > 0:
                    U = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_EVENODD,
                                   pyclipper.PFT_EVENODD)
                    Ia = pyclipper.Area(I[0])
                    Ua = pyclipper.Area(U[0])
                    IoU = Ia / Ua
                else:
                    IoU = 0.0

                # intersection over union, shapely, much slower
                #I = poly1.intersection(poly2)
                #if not I.is_empty:
                #    Ia = I.area
                #    Ua = poly1.area + poly2.area - Ia
                #    IoU = Ia / Ua
                #else:
                #    IoU =  0.0

                gt_iou.append(IoU)
                #print(IoU)
            gt_iou = np.array(gt_iou)
            max_gt_idx = np.argmax(gt_iou)
            dt_idx = k

            if gt_iou[max_gt_idx] > iou_thresh:
                if not assignement[
                        max_gt_idx]:  # todo: use highest iou, not first
                    TP_img[dt_idx] = 1
                    assignement[max_gt_idx] = True
                    continue
            FP_img[dt_idx] = 1

        FN_img_sum = np.sum(np.logical_not(assignement))

        TP.append(TP_img)
        FP.append(FP_img)
        FN_sum += FN_img_sum

    TP = np.concatenate(TP)
    FP = np.concatenate(FP)

    TP_sum = np.sum(TP)
    FP_sum = np.sum(FP)

    return TP_sum, FP_sum, FN_sum

    recall = TP_sum / (TP_sum + FN_sum)
    precision = TP_sum / (TP_sum + FP_sum)
    print('TP %i FP %i FN %i' % (TP_sum, FP_sum, FN_sum))
    print('precision, recall, f-measure: %.2f, %.2f, %.2f' %
          (precision, recall, fscore(precision, recall)))
示例#29
0
文件: PAGE_xml.py 项目: herobd/atr
def assign_path_to_region(out, regions):

    trimmed_polys = e2e_postprocessing.get_trimmed_polygons(out)

    polys = []
    for t in trimmed_polys:
        p = t[:, :2, 0].tolist() + t[::-1, :2, 1].tolist()
        polys.append(p)

    scores = []
    for i, r in enumerate(regions):
        region_poly = r['bounding_poly']
        scores_i = []
        scores.append(scores_i)
        for p in polys:
            pc = pyclipper.Pyclipper()

            try:
                pc.AddPath(p, pyclipper.PT_CLIP, True)
            except:
                scores_i.append(0)
                # print p
                print("Failed to assign text line, probably not an issue")
                continue
            pc.AddPath(region_poly, pyclipper.PT_SUBJECT, True)

            solution = pc.Execute(pyclipper.CT_INTERSECTION,
                                  pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)

            # pts = np.array(region_poly, np.int32)
            # pts = pts.reshape((-1,1,2))
            # cv2.polylines(img,[pts],True,(0,0,255), thickness=3)

            area = 0
            for path in solution:
                area += pyclipper.Area(path)

            scores_i.append(area)

    background_scores = []
    total_areas = []
    for p in polys:
        pc = pyclipper.Pyclipper()
        try:
            pc.AddPath(p, pyclipper.PT_CLIP, True)
        except:
            total_areas.append(np.inf)
            background_scores.append(np.inf)
            # print p
            print("Failed to assign text line, probably not an issue")
            continue
        pc.AddPaths([r['bounding_poly'] for r in regions],
                    pyclipper.PT_SUBJECT, True)
        solution = pc.Execute(pyclipper.CT_INTERSECTION, pyclipper.PFT_NONZERO,
                              pyclipper.PFT_NONZERO)

        area = 0
        for path in solution:
            area += pyclipper.Area(path)

        simple_path = pyclipper.SimplifyPolygon(p, pyclipper.PFT_NONZERO)
        total_area = 0
        for path in simple_path:
            total_area += pyclipper.Area(path)

        total_areas.append(total_area)
        background_score = total_area - area
        background_scores.append(background_score)

    return np.array(scores), np.array(background_scores), np.array(total_areas)