import copy
import json
import os
from PIL import Image
from alibabacloud_imageseg20191230.client import Client as imageseg20191230Client
from alibabacloud_imageseg20191230.models import SegmentCommodityAdvanceRequest
from alibabacloud_imageseg20191230 import models as imageseg_20191230_models
from alibabacloud_tea_util.models import RuntimeOptions
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_openapi.models import Config
from alibabacloud_tea_util import models as util_models
import requests
from io import BytesIO
import cv2
import numpy as np
from func_timeout import func_set_timeout
from func_timeout import FunctionTimedOut
from .multi_threaded_image_saving import ImageSaver

# 自己的
AccessKeyId = "LTAI5tCk4p881X8hymj2FYFk"
AccessKeySecret = "yBYIYzX8CL24r5ZgEx2AgZyDBmFkIK"

# 惠利玛公司的KEY
# AccessKeyId = 'LTAI5tCk4p881X8hymj2FYFk'
# AccessKeySecret = 'rQMgHwciTN4Gusbpt8CM8tflgsxh1V'


# https://help.aliyun.com/zh/viapi/developer-reference/python?spm=a2c4g.11186623.0.i0#task-2252575
# pip install alibabacloud_goodstech20191230
# pip install alibabacloud_tea_openapi
# pip install alibabacloud_tea_util

class Segment(object):
    def __init__(self):
        self.client = self.create_client()

    def get_no_bg_common(self, file_path):
        # 初始化RuntimeObject
        runtime_option = RuntimeOptions()
        try:
            # 场景一：文件在本地
            img = open(file_path, 'rb')
            # 使用完成之后记得调用img.close()关闭流
            # 场景二，使用任意可访问的url
            # url = 'https://viapi-test-bj.oss-cn-beijing.aliyuncs.com/viapi-3.0domepic/ocr/RecognizeBankCard/yhk1.jpg'
            # img = io.BytesIO(urlopen(url).read())
            # 4、初始化Request，这里只是以RecognizeBankCard为例，其他能力请使用相应能力对应的类
            request = SegmentCommodityAdvanceRequest()
            request.image_urlobject = img

            # 5、调用api，注意，recognize_bank_card_advance需要更换为相应能力对应的方法名。方法名是根据能力名称按照一定规范形成的，如能力名称为SegmentCommonImage，对应方法名应该为segment_common_image_advance。
            response = self.client.segment_common_image_advance(request, runtime_option)
            # 获取整体结果
            # print(response.body)
            img.close()
            return response.body
            # 获取单个字段，这里只是一个例子，具体能力下的字段需要看具体能力的文档
            # print(response.body.data.card_number)
            # tips: 可通过response.body.__dict__查看属性名称
        except Exception as error:
            # 获取整体报错信息
            print("error", error)
            return None
            # 获取单个字段
            # print(error.code)
            # tips: 可通过error.__dict__查看属性名称

    def get_no_bg_goods(self, file_path=None, _im=None):
        # file_path = r"D:\MyDocuments\PythonCode\MyPython\red_dragonfly\deal_pics\change_color_2\test\_MG_9061.jpg"
        # file_path_1 = r"D:\MyDocuments\PythonCode\MyPython\red_dragonfly\deal_pics\change_color_2\test\_MG_9061_resize.png"
        # if file_path:
        #     img = open(file_path, 'rb')
        # if _im:
        # https://blog.csdn.net/weixin_43411585/article/details/107780941
        im = _im
        # im.save(file_path)
        img = BytesIO()
        im.save(img, format='JPEG')  # format: PNG or JPEG
        img.seek(0)  # rewind to the start

        # img = img_byte.getvalue()  # im对象转为二进制流
        # with open(file_path, "wb") as binary_file:
        #     binary_file.write(im.tobytes())

        # file_path = r"D:\MyDocuments\PythonCode\MyPython\red_dragonfly\deal_pics\change_color_2\test\1.png"
        # img = open(file_path, 'rb')

        request = imageseg_20191230_models.SegmentCommodityAdvanceRequest()
        request.image_urlobject = img
        client = self.create_client()
        # 5、调用api，注意，recognize_bank_card_advance需要更换为相应能力对应的方法名。方法名是根据能力名称按照一定规范形成的，如能力名称为SegmentCommonImage，对应方法名应该为segment_common_image_advance。
        runtime = util_models.RuntimeOptions()
        response = client.segment_commodity_advance(request, runtime)
        # img.close()
        # print("1111111111111", response.body)
        return response.body

    def create_client(self):
        """
        使用AK&SK初始化账号Client
        @param access_key_id:
        @param access_key_secret:
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            # 必填，您的 AccessKey ID,
            access_key_id=AccessKeyId,
            # 必填，您的 AccessKey Secret,
            access_key_secret=AccessKeySecret
        )
        # 访问的域名
        config.endpoint = f'imageseg.cn-shanghai.aliyuncs.com'
        return imageseg20191230Client(config)


class Picture:
    def __init__(self, in_path, im=None):
        if im:
            self.im = im
        else:
            self.im = Image.open(in_path)
        self.x, self.y = self.im.size
        # print(self.x, self.y)

    def save_img(self, outpath, quality=90):
        # self.im = self.im.convert("RGB")
        self.im.save(outpath, quality=quality)

    def resize(self, width):
        re_x = int(width)
        re_y = int(self.y * re_x / self.x)
        self.im = self.im.resize((re_x, re_y), Image.BICUBIC)
        self.x, self.y = self.im.size

    def resize_by_heigh(self, heigh):
        re_y = int(heigh)
        re_x = int(self.x * re_y / self.y)
        self.im = self.im.resize((re_x, re_y), Image.BICUBIC)
        self.x, self.y = self.im.size


class RemoveBgALi(object):
    def __init__(self):
        self.saver = ImageSaver()
        self.segment = Segment()

    @func_set_timeout(40)
    def get_image_cut(self, file_path, out_file_path=None, original_im=None):
        if original_im:
            original_pic = Picture(in_path=None, im=original_im)
        else:
            original_pic = Picture(file_path)

        if original_pic.im.mode != "RGB":
            print("抠图图片不能是PNG")
            return None

        new_pic = copy.copy(original_pic)
        after_need_resize = False
        if new_pic.x > new_pic.y:
            if new_pic.x > 2000:
                after_need_resize = True
                new_pic.resize(2000)
        else:
            if new_pic.y > 2000:
                after_need_resize = True
                new_pic.resize_by_heigh(heigh=2000)

        # new_pic.im.show()
        body = self.segment.get_no_bg_goods(file_path=None, _im=new_pic.im)
        body = eval(str(body))
        try:
            image_url = body["Data"]["ImageURL"]
        except BaseException as e:
            print("阿里抠图错误：", e)
            # 处理失败，需要删除过程图片
            return None
        # 字节流转PIL对象
        response = requests.get(image_url)
        pic = response.content
        _img_im = Image.open(BytesIO(pic))  # 阿里返回的抠图结果 已转PIL对象
        # 原图更大，则需要执行CV处理
        if after_need_resize:
            # 将抠图结果转成mask
            # _img_im = Image.open(_path)
            # 将抠图结果放大到原始图大小
            _img_im = _img_im.resize(original_pic.im.size)
            new_big_mask = Image.new('RGB', _img_im.size, (0, 0, 0))
            white = Image.new('RGB', _img_im.size, (255, 255, 255))
            new_big_mask.paste(white, mask=_img_im.split()[3])

            # ---------制作选区缩小的mask
            # mask = cv2.imread(mask_path)
            # mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
            mask = cv2.cvtColor(np.asarray(new_big_mask), cv2.COLOR_BGR2GRAY)  # 将PIL 格式转换为 CV对象
            mask[mask != 255] = 0
            # 黑白反转
            # mask = 255 - mask
            # 选区缩小10
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
            erode_im = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)

            # -------再进行抠图处理
            mask = Image.fromarray(cv2.cvtColor(erode_im, cv2.COLOR_GRAY2RGBA))  # CV 对象转 PIL
            transparent_im = Image.new('RGBA', original_pic.im.size, (0, 0, 0, 0))
            # original_pic.im.show()
            # mask.show()
            transparent_im.paste(original_pic.im, (0, 0), mask.convert('L'))
            # transparent_im.show()
            # 上述抠图结果进行拼接
            _img_im.paste(transparent_im, (0, 0), transparent_im)
            # _img_im.show("11111111111111111111111")
        if out_file_path:
            self.saver.save_image(
                image=_img_im, file_path=out_file_path, save_mode="png"
            )
            # _img_im.save(out_file_path)
        return _img_im

    def get_image_cut1(self, file_path, out_file_path=None):
        original_pic = Picture(file_path)
        new_pic = copy.copy(original_pic)
        if new_pic.x > 2000:
            new_pic.resize(2000)
        # new_pic.im.show()
        body = self.segment.get_no_bg_goods(file_path=out_file_path, _im=new_pic.im)
        body = eval(str(body))
        try:
            image_url = body["Data"]["ImageURL"]
        except BaseException as e:
            print("阿里抠图错误：", e)
            # 处理失败，需要删除过程图片
            return None
        # 字节流转PIL对象
        response = requests.get(image_url)
        pic = response.content
        _img_im = Image.open(BytesIO(pic))  # 阿里返回的抠图结果 已转PIL对象

        if original_pic.x > 2000:
            # 原图更大，则需要执行CV处理
            # _img_im.show()
            # 对mask进行放大，然后进行抠图处理
            print("对mask进行放大，然后进行抠图处理")
            transparent_im = Image.new('RGBA', original_pic.im.size, (0, 0, 0, 0))
            # original_pic.im.show()
            # mask.show()
            _img_im = _img_im.resize((original_pic.x, original_pic.y))
            # _img_im.show()
            transparent_im.paste(original_pic.im, (0, 0), mask=_img_im)
            # transparent_im.show()
            # transparent_im.show()
            _img_im = transparent_im
            # 上述抠图结果进行拼接
            # _img_im.paste(transparent_im, (0, 0), transparent_im)
            pass

        _img_im.save(out_file_path)
        return _img_im

    def download_picture(self, url, out_path):
        response = requests.get(url)
        pic = response.content
        with open(out_path, 'wb') as f:
            f.write(pic)


if __name__ == '__main__':
    r = RemoveBgALi()
    path = r"D:\MyDocuments\PythonCode\MyPython\red_dragonfly\deal_pics\auto_capture_V2\IPC\test\171112057820408.png"
    out_path = "{}._no_bg-out.png".format(path)
    r.get_image_cut(path, out_file_path=out_path)
