python图像标注,可根据需求自行配置参数(单线程版本)

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路python图像标注,可根据需求自行配置参数(单线程版本),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

# !/usr/bin/env python3
# -*- coding: UTF-8 -*-
# !/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@author  : v_jiaohaicheng@baidu.com
@des     : 

"""
import os
import json
from PIL import ImageFont, Image, ImageDraw
import cv2 as cv
import numpy as np
# from threading import Thread
from Project.util import bos_util


class MarkImage():

    def __init__(self):
        self.bos_client = bos_util.get_bos_client()
        # 是否标注文字
        self.TEXT = False
        # 是否标注方框
        self.BOX = True
        # 是否标注文字索引
        self.INDEX = False
        # 标注文字大小
        self.SIZE = 20
        # 是否旋转
        self.TRANSPOSE = False
        # 标注字体格式
        self.Font = R'C:\\Windows\\Fonts\\simkai.ttf'
        # 标注颜色
        self.COLOR = (255,0,0)
        self.TXT_COLOR = (0,0,255)
        # 标注线粗
        self.THICKNESS = 2
        # bos路径唯一标识符
        self.SINGLE = "MarkImage_9407"
        # 是否上传处理结果到bos
        self.UPLOAD = True
        # 标注数字位置 True:左上,False:右下
        self.num_opt = True
        # 绘制 框/线 True:框 False:线
        self.LINE = True

    def save_log(self, file, text):
        """
        保存日志
        :param file:
        :param text:
        :return:
        """
        with open(file, "a", encoding="utf-8")as fp:
            fp.write("{}\n".format(text))

    def upload(self, file, retry=3):
        """
        上传
        :param file:
        :param retry:
        :return:
        """
        source_bucket = 'collection-data'
        bos_file = "/jiaohaicheng/{}/{}".format(
            self.SINGLE, "/".join(file.split("\\")[-3:]))
        status = False

        while not status and retry > 0:
            try:
                if self.UPLOAD:
                    bos_util.upload_file(
                        self.bos_client, source_bucket, bos_file, file)
                    status = True
                else:
                    retry = 0
            except Exception as e:
                print(e,e.__traceback__.tb_lineno)
                retry -= 1

        if not status:
            if self.UPLOAD:
                return "Error Upload File : "+"https://bj.bcebos.com/collection-data" + bos_file
            else:
                return file
        else:
            if self.UPLOAD:
                return "https://bj.bcebos.com/collection-data" + bos_file

    def transpose(self, image, key: int):
        """
        旋转,逆时针
        """
        return image.rotate(key)

    def read_image(self, file, key=0):
        """
        读取图像,带旋转功能
        :param file:
        :param key:
        :return:
        """
        img = Image.open(file)

        if self.TRANSPOSE:
            img = self.transpose(img, key)
        img = np.asarray(img)
        return img

    def save_img(self, img, file, name=".jpg"):
        """
        保存图像到本地
        :param img:
        :param file:
        :param name:
        :return:
        """
        img = cv.cvtColor(img, cv.COLOR_RGB2BGR)
        cv.imencode(name, img)[1].tofile(file)

    def draw_polygon(self, img, opt_lis):
        """
        标注框
        :param img:图像 numpy
        :param opt_lis: 标注位置坐标
        :return:
        """
        if self.BOX:
            if len(opt_lis) != 2:
                pts = np.array(opt_lis, dtype=np.int32)
                # print(self.LINE)
                cv.polylines(img,
                             [pts],
                             self.LINE,
                             self.COLOR,
                             self.THICKNESS
                             )
            else:
                if self.LINE:
                    # print("框")
                    cv.rectangle(
                        img,
                        tuple(opt_lis[0]),
                        tuple(opt_lis[1]),
                        color=self.COLOR,
                        thickness=self.THICKNESS

                    )
                else:
                    # print("线")
                    cv.line(img, tuple(opt_lis[0]), tuple(opt_lis[1]), color=self.COLOR, thickness=self.THICKNESS)

    def calculate_max_opt(self, opt):
        """
        计算最大横纵坐标,横坐标加上偏移量(字体大小的1/5)
        :param opt: [[,],[,]]
        :return:
        """
        max_x = []
        max_y = []
        for i in opt:
            if len(i) == 2:
                max_x.append(i[0])
                max_y.append(i[1])
        return max(max_x) + self.SIZE / 5, max(max_y) - self.SIZE

    def calculate_min_opt(self, opt):
        """
        计算最小横纵坐标,横坐标减去偏移量(字体大小的1/5)
        :param opt: [[,],[,]]
        :return:
        """
        min_x = []
        min_y = []
        for i in opt:
            if len(i) == 2:
                min_x.append(i[0])
                min_y.append(i[1])
        return min(min_x) - self.SIZE / 5, min(min_y) - self.SIZE

    def add_words_on_pic(self, opt, index, text, image):
        """
        添加文字
        :param opt: tuple (,)
        :param index: 标注文本序号
        :param text: 标注文本
        :param image: 图像 ,numpy
        :return:
        """
        _text = ""
        if self.INDEX:
            _text = str(index)
            if self.TEXT:
                _text = _text + "." + text
        else:
            if self.TEXT:
                _text = text
        try:
            font = ImageFont.truetype(self.Font, size=self.SIZE)
            img_PIL = Image.fromarray(image)
            draw = ImageDraw.Draw(img_PIL)
            draw.text(xy=(opt[0], opt[1] - (self.SIZE / 2)),
                      text=_text, font=font, fill=self.TXT_COLOR)
            image = cv.cvtColor(np.asarray(img_PIL), cv.COLOR_RGB2RGBA)
        except Exception as e:
            print("add_words_on_pic error", e, e.__traceback__.tb_lineno)
        return image

    def process_map_lis(self,map_lis):
        new_map_lis = {}
        for index, value in map_lis.items():
            new_map_lis[str(index)] = value
        return new_map_lis



    def process(self, file, map_lis, save_file):
        """
        图像处理流程
        :param file:图像位置
        :param map_lis: 标注坐标[1:{opt:value}]
        :param id: 标注文本序号
        :param text: 标注文本
        :param save_file: 图像存储位置
        :return:
        """
        map = {}
        map["origin_file"] = file
        map["opt_lis"] = self.process_map_lis(map_lis)
        map["up_file"] = ""
        map["name"] = os.path.split(file)[-1]
        try:
            # 读取图像
            img = self.read_image(file)

            for index,value in map_lis.items():
                # 标注框
                self.draw_polygon(img, value["opt"])
                # 计算文本标注位置(x最大值+偏移量,y最大值-偏移量)
                if self.num_opt == True:
                    opt = self.calculate_min_opt(value["opt"])
                else:
                    opt = self.calculate_max_opt(value["opt"])
                # 标注文字
                img = self.add_words_on_pic(opt=opt, index=index, text=value["text"], image=img)
            # 保存图像
            self.save_img(img, save_file)
            # bos_file_status:上传状态,成功只返回bos路径,若失败,路径前有error upload file : 标识,未开启上传功能,返回本地待上传图片路径
            bos_file_status = self.upload(save_file)
            map["up_file"] = bos_file_status
            # print("bos_file_status",bos_file_status)
        except Exception as e:
            print("Process {} Error : ".format(file),e,e.__traceback__.tb_lineno)

        return map


    # def get_info(self,file):
    #     with open(file,"r",encoding="utf-8")as fp:
    #         header = fp.readline()
    #         for i in fp:
    def process_input_answer(self,data=None, file=None):
        """
        处理 直接解析的point 和txt中读取的point
        :param data:
        :return:
        """
        try:
            res_map = {}
            if data:
                json_data = json.loads(data, strict=False)
                for result in json_data["result"]:
                    for index, element in enumerate(result["elements"]):
                        text = element["text"]
                        point = element["points"]
                        res_map[index + 1] = {
                            "opt": [[int(i["x"]), int(i["y"])] for i in point],
                            "text": text
                        }

            if file:
                with open(file, "r", encoding="utf-8")as fp:
                    header = fp.readline().strip().split("\t")
                    for index, value in enumerate(fp):
                        value = value.strip().split("\t")
                        text = value[header.index("text")]
                        point = value[header.index("point")]
                        res_map[index + 1] = {
                            "opt": [[int(i["x"]), int(i["y"])] for i in json.loads(point.replace("'",'"'))],
                            "text": text
                        }
            else:
                pass

            return res_map

        except:
            return 0

if __name__ == '__main__':
    mi = MarkImage()
    file = R"E:\Desktop\20170427101835143.png"
    save_path = R"F:\BaiduCodingSpace\SupportRequirements\Project\image\mark"
    img_name = os.path.split(file)[-1]
    os.makedirs(save_path, exist_ok=True)
    save_file = os.path.join(save_path, img_name)

    map_lis = {
        1:{
            "opt":[
                [100, 200],
                [130, 210],
                [135, 282],
                [100, 260],
            ],
            "text":"中国"
        },
        2:{
            "opt": [
                [200, 200],
                [230, 210],
                [235, 282],
                [200, 260],
            ],
            "text":"日本"
        }
    }
    mi.process(file, map_lis, save_file)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156878.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!