コード例 #1
0
ファイル: labelme.py プロジェクト: XLPRUtils/pyxllib
    def update_labelattr(cls, lmdict, *, points=False, inplace=True):
        """

        :param points: 是否更新labelattr中的points、bbox等几何信息
            并且在无任何几何信息的情况下,增设points
        """
        if not inplace:
            lmdict = copy.deepcopy(lmdict)

        for shape in lmdict['shapes']:
            # 1 属性字典,至少先初始化一个label属性
            labelattr = DictTool.json_loads(shape['label'], 'label')
            # 2 填充其他扩展属性值
            keys = set(shape.keys())
            stdkeys = set('label,points,group_id,shape_type,flags'.split(','))
            for k in (keys - stdkeys):
                labelattr[k] = shape[k]
                del shape[k]  # 要删除原有的扩展字段值

            # 3 处理points等几何信息
            if points:
                if 'bbox' in labelattr:
                    labelattr['bbox'] = ltrb2xywh(rect_bounds(shape['points']))
                else:
                    labelattr['points'] = shape['points']

            # + 写回shape
            shape['label'] = json.dumps(labelattr, ensure_ascii=False)
        return lmdict
コード例 #2
0
    def gen_annotation(cls, **kwargs):
        """ 智能地生成一个annotation字典

        这个略微有点过度封装了
        但没事,先放着,可以不拿出来用~~

        :param points: 必须是n*2的结构
        """
        a = kwargs.copy()

        # a = {'id': 0, 'area': 0, 'bbox': [0, 0, 0, 0],
        #       'category_id': 1, 'image_id': 0, 'iscrowd': 0, 'segmentation': []}

        if 'points' in a:  # points是一个特殊参数,使用“一个”多边形来标注(注意区别segmentation是多个多边形)
            if 'segmentation' not in a:
                a['segmentation'] = [cls.points2segmentation(a['points'])]
            del a['points']
        if 'bbox' not in a:
            pts = []
            for seg in a['segmentation']:
                pts += seg
            a['bbox'] = ltrb2xywh(rect_bounds(pts))
        if 'area' not in a:  # 自动计算面积
            a['area'] = int(a['bbox'][2] * a['bbox'][3])
        for k in ['id', 'image_id']:
            if k not in a:
                a[k] = 0
        if 'category_id' not in a:
            a['category_id'] = 1

        return a
コード例 #3
0
    def _get_subrect_image(im, pts, fill=0):
        """
        :return:
            dst_img 按外接四边形截取的子图
            new_pts 新的变换后的点坐标
        """
        # 1 计算需要pad的宽度
        x1, y1, x2, y2 = [round_int(v) for v in rect_bounds(pts)]
        h, w = im.shape[:2]
        pad = [-y1, y2 - h, -x1, x2 - w]  # 各个维度要补充的宽度
        pad = [max(0, v) for v in pad]  # 负数宽度不用补充,改为0

        # 2 pad并定位rect局部图
        tmp_img = xlcv.pad(im, pad, fill) if max(pad) > 0 else im
        dst_img = tmp_img[y1 + pad[0]:y2,
                          x1 + pad[2]:x2]  # 这里越界不会报错,只是越界的那个维度shape为0
        new_pts = [(pt[0] - x1, pt[1] - y1) for pt in pts]
        return dst_img, new_pts
コード例 #4
0
    def gen_quad_annotations(cls,
                             file,
                             *,
                             image_id,
                             start_box_id,
                             category_id=1,
                             **kwargs):
        """ 解析一张图片对应的txt标注文件

        :param file: 标注文件,有多行标注
            每行是x1,y1,x2,y2,x3,y3,x4,y4[,label] (label可以不存在)
        :param image_id: 该图片id
        :param start_box_id: box_id起始编号
        :param category_id: 归属类别
        """
        lines = File(file).read()
        box_id = start_box_id
        annotations = []
        for line in lines.splitlines():
            vals = line.split(',', maxsplit=8)
            if len(vals) < 2: continue
            attrs = {
                'id': box_id,
                'image_id': image_id,
                'category_id': category_id
            }
            if len(vals) == 9:
                attrs['label'] = vals[8]
            # print(vals)
            seg = [int(v) for v in vals[:8]]
            attrs['segmentation'] = [seg]
            attrs['bbox'] = ltrb2xywh(rect_bounds(seg))
            if kwargs:
                attrs.update(kwargs)
            annotations.append(cls.gen_annotation(**attrs))
            box_id += 1
        return annotations
コード例 #5
0
    def warp(im,
             warp_mat,
             dsize=None,
             *,
             view_rate=False,
             max_zoom=1,
             reserve_struct=False):
        """ 对图像进行透视变换
    
        :param im: np.ndarray的图像数据
            TODO 支持PIL.Image格式?
        :param warp_mat: 变换矩阵
        :param dsize: 目标图片尺寸
            没有任何输入时,同原图
            如果有指定,则会决定最终的图片大小
            如果使用了view_rate、max_zoom,会改变变换矩阵所展示的内容
        :param view_rate: 视野比例,默认不开启,当输入非0正数时,几个数值功能效果如下
            1,关注原图四个角点位置在变换后的位置,确保新的4个点依然在目标图中
                为了达到该效果,会增加【平移】变换,以及自动控制dsize
            2,将原图依中心面积放到至2倍,记录新的4个角点变换后的位置,确保变换后的4个点依然在目标图中
            0.5,同理,只是只关注原图局部的一半位置
        :param max_zoom: 默认1倍,当设置时(只在开启view_rate时有用),会增加【缩小】变换,限制view_rate扩展的上限
        :param reserve_struct: 是否保留原来im的数据类型返回,默认True
            关掉该功能可以提高性能,此时返回结果统一为 np 矩阵
        :return: 见 reserve_struct
        """
        from math import sqrt

        # 1 得到3*3的变换矩阵
        warp_mat = np.array(warp_mat)
        if warp_mat.shape[0] == 2:
            warp_mat = np.concatenate([warp_mat, [[0, 0, 1]]], axis=0)

        # 2 view_rate,视野比例改变导致的变换矩阵规则变化
        if view_rate:
            # 2.1 视野变化后的四个角点
            h, w = im.shape[:2]
            y, x = h / 2, w / 2  # 图片中心点坐标
            h1, w1 = view_rate * h / 2, view_rate * w / 2
            l, t, r, b = [-w1 + x, -h1 + y, w1 + x, h1 + y]
            pts1 = np.array([[l, t], [r, t], [r, b], [l, b]])
            # 2.2 变换后角点位置产生的外接矩形
            left, top, right, bottom = rect_bounds(warp_points(pts1, warp_mat))
            # 2.3 增加平移变换确保左上角在原点
            warp_mat = np.dot([[1, 0, -left], [0, 1, -top], [0, 0, 1]],
                              warp_mat)
            # 2.4 控制面积变化率
            h2, w2 = (bottom - top, right - left)
            if max_zoom:
                rate = w2 * h2 / w / h  # 目标面积比原面积
                if rate > max_zoom:
                    r = 1 / sqrt(rate / max_zoom)
                    warp_mat = np.dot([[r, 0, 0], [0, r, 0], [0, 0, 1]],
                                      warp_mat)
                    h2, w2 = round(h2 * r), round(w2 * r)
            if not dsize:
                dsize = (w2, h2)

        # 3 标准操作,不做额外处理,按照原图默认的图片尺寸展示
        if dsize is None:
            dsize = (im.shape[1], im.shape[0])
        dst = cv2.warpPerspective(im, warp_mat, dsize)

        # 4 返回值
        return dst