rambo 1 ano atrás
pai
commit
7113512387

+ 28 - 5
python/api.py

@@ -1,7 +1,7 @@
 from models import *
 import datetime
 from services.SegmentService import SegmentService
-from services.deal_cutout import DealCutout
+from services.deal_cutout import DealCutout,DealCloths
 
 @app.get("/")
 async def index():
@@ -18,14 +18,37 @@ async def checkSelect(params: CheckSelectImages):
     file_path = params.path
     path_type = params.path_type
     image_list = params.image_list
-    deal_cutout_mode = DealCutout()
     if path_type == 0:
         need_cutout_images = service.initImages(image_list=image_list)
     else:
         need_cutout_images = service.check_need_cutout_images(file_path)
     if len([x for x in need_cutout_images if x["need_cutout"]]) == 0:
         raise UnicornException("您所选文件夹下没有jpg图片,或对应图片已扣图")
-    deal_cutout_mode.need_cutout_images = need_cutout_images
-    deal_cutout_mode.start()
-    # print("list_result", need_cutout_images)
+    return success(need_cutout_images)
+
+
+@app.post("/api/segment_images", description="检查目录或文件")
+async def segmentImages(params: SegmentImages):
+    image_type = params.image_type
+    segment_type = params.segment_type
+    need_cutout_images = params.need_cutout_images
+    if len([x for x in need_cutout_images if x["need_cutout"]]) == 0:
+        raise UnicornException("您所选文件夹下没有jpg图片,或对应图片已扣图")
+    if image_type == 1 and segment_type == 1:
+        raise UnicornException("服装暂不支持精细化抠图")
+    elif image_type == 1 and segment_type == 0:
+        deal_cutout_cloth = DealCloths()
+        # 服装抠图
+        # need_cutout_images = service.check_need_cutout_images(file_path)
+        deal_cutout_cloth.need_cutout_images = need_cutout_images
+        deal_cutout_cloth.startDispose()
+    elif image_type == 0 and segment_type == 1:
+        deal_cutout_mode = DealCutout()
+        # 通用-精细化抠图
+        deal_cutout_mode.need_cutout_images = need_cutout_images
+        deal_cutout_mode.startDispose()
+    elif image_type == 0 and segment_type == 0:
+        # 通用-普通抠图
+        # need_cutout_images = service.check_need_cutout_images(file_path)
+        pass
     return success(need_cutout_images)

+ 2 - 5
python/models.py

@@ -26,14 +26,11 @@ class CheckSelectImages(BaseModel):
     # 检查目录
     path_type: int = Field(default=0, description="地址类型;0图像;1目录")
     path: str = Field(default=None, description="目录地址")
-    image_list: list[str] = Field(default=None, description="图像地址")
+    image_list: list[str] = Field(default=[], description="图像地址")
 
 
 class SegmentImages(BaseModel):
     # 抠图
     image_type: int = Field(default=0, description="图像类型;0非服装;1服装")
-    output_type: int = Field(default=0, description="图像类型;0仅移除背景;1白底图")
-    path_type: int = Field(default=0, description="地址类型;0图像;1目录")
     segment_type: int = Field(default=0, description="抠图精细度;0普通;1精细")
-    path: int = Field(default=0, description="地址")
-    image_list: list[str] = Field(default=None, description="图像地址")
+    need_cutout_images: list = Field(default=None, description="图像地址集合")

+ 31 - 40
python/services/deal_cutout.py

@@ -7,7 +7,7 @@ from .deal_one_image import DealOneImage, DealOneImageBeforehand
 from .other.log import MyLogger
 
 
-class DealCutout(threading.Thread):
+class DealCutout:
 
     def __init__(self):
         super().__init__()
@@ -21,50 +21,41 @@ class DealCutout(threading.Thread):
         self.upload_pic_dict = {}
         self.logger = MyLogger().logger
 
-    def run(self):
+    def startDispose(self):
         self.get_online_data.refresh_headers()
+        num = 0
+        for image_data in self.need_cutout_images:
+            num += 1
+            upload_pic_dict = {}
+            upload_pic_dict = DealOneImageBeforehand(
+                image_data=image_data, lock=self.lock, windows=self, num=num
+            ).run(upload_pic_dict)
+            print("upload_pic_dict", upload_pic_dict)
+            DealOneImage(
+                image_data=image_data, lock=self.lock, windows=self, num=num
+            ).run(image_data, upload_pic_dict)
 
-        executor = ThreadPoolExecutor(max_workers=4)
-        executor_pic_upload = ThreadPoolExecutor(max_workers=2)
+class DealCloths:
 
-        tasks_1 = []
-        tasks_2 = []
-        self.state = 1
+    def __init__(self):
+        super().__init__()
+        self.lock = threading.Lock()
+        self.need_cutout_images = {}
+        self.state = 2  # 1进行中 2停止
+        self.get_online_data = GetOnlineData()
         self.is_upload_pic_num = 0
         self.is_deal_num = 0
+        # 图片列表
+        self.upload_pic_dict = {}
+        self.logger = MyLogger().logger
+
+    def startDispose(self):
+        self.get_online_data.refresh_headers()
         num = 0
         for image_data in self.need_cutout_images:
-            if not image_data["need_cutout"]:
-                continue
             num += 1
-            task_1 = executor.submit(DealOneImage(image_data=image_data, lock=self.lock, windows=self, num=num).run)
-            tasks_1.append(task_1)
-
-            task_2 = executor_pic_upload.submit(
-                DealOneImageBeforehand(image_data=image_data, lock=self.lock, windows=self, num=num).run)
-            tasks_2.append(task_2)
-        self.check_thread(tasks_1, tasks_2)
-
-    def check_thread(self, *tasks_list):
-        time.sleep(2)
-        while 1:
-            f = True
-            for tasks in tasks_list:
-                done, not_done = wait(tasks)
-                if not_done:
-                    time.sleep(2)
-                    f = False
-                    continue
-
-                for task in done:
-                    try:
-                        result = task.result()
-                        # print(result)
-                    except BaseException as e:
-                        self.logger.info("有线程出错:{}".format(e))
-
-            if f:
-                break
-
-        # self.signal_data.emit({"_type": "complete",
-        #                        "data": ""})
+            upload_pic_dict = {}
+            hand = DealOneImageBeforehand(
+                image_data=image_data, lock=self.lock, windows=self, num=num
+            )
+            upload_pic_dict = hand.get_image_cut_cloths()

+ 158 - 297
python/services/deal_one_image.py

@@ -120,261 +120,54 @@ class Base(object):
 class DealOneImage(Base):
     def __init__(self, image_data, lock, windows, num):
         super().__init__(image_data, lock, windows, num)
-        self.image_data = image_data
-        self.lock = lock
-        self.windows = windows
-        self.num = num
+        self.r_pixian = RemoveBgPiXian()
+
+    def run(self, image_data, upload_pic_dict):
         self.file_path = image_data["file_path"]
         self.file = os.path.split(self.file_path)[1]
         self.root_path = image_data["root_path"]
-        self.r_pixian = RemoveBgPiXian()
         self.file_name = image_data["file_name"]
-
-    def run(self):
         # 直接调用抠图
         # 1、增加获取key,2、key需要加密、3、429报错 重试再来拿一个KEY
         self.add_log("开始处理")
-        self.show_image_info(
-            {
-                "text": "处理中",
-                "info": "",
-            }
-        )
         remaining_times = self.get_online_data.get_cutout_image_times().get("balance")
         print("remaining_times", remaining_times)
         if remaining_times <= 0:
-            # self.send_info(text="次数不足,处理失败", is_success=False)
             raise UnicornException("次数不足,处理失败")
-            return
 
         # 检查图片上传是否有结束
         n = 60
-        while 1:
-            if self.windows.state != 1:
-                # self.show_image_info({"text": "已取消", "info": "", })
-                # self.send_info(text="用户主动终止", is_success=False)
-                raise UnicornException("用户主动终止")
-                return
-            n -= 1
-            # print(n)
-            if self.file_path in self.windows.upload_pic_dict:
-                break
-
-            else:
-                time.sleep(1)
-                if n <= 0:
-                    text = "处理超时"
-                    self.send_info(text=text, is_success=False)
-
-                    _data = {
-                        "text": "出错/超时",
-                        "info": "处理超时",
-                    }
-                    self.show_image_info(_data)
-                    return
-                continue
-
+        if self.file_path not in upload_pic_dict:
+            # 不扣图
+            raise UnicornException("处理失败")
         s = time.time()
-        # print(self.upload_pic_dict[file_path])
-        _flag = self.windows.upload_pic_dict[self.file_path]["flag"]
-        if not _flag:
-            self.add_log("未查到上传的图片地址")
-            _data = {
-                "text": "出错/超时",
-                "info": "上传错误",
-            }
-            self.show_image_info(_data)
-            # self.send_info(text="上传错误", is_success=False)
-            raise UnicornException("上传错误")
-            return
-
-        image_deal_info = self.windows.upload_pic_dict[self.file_path][
-            "image_deal_info"
-        ]
-        original_im = self.windows.upload_pic_dict[self.file_path]["_im"]
-
-        self.show_image_info(
-            {
-                "text": "开始抠图",
-                "info": "",
-            }
-        )
+        image_deal_info = upload_pic_dict[self.file_path]["image_deal_info"]
+        original_im = upload_pic_dict[self.file_path]["_im"]
         self.add_log("抠图中")
-
-        with self.lock:
-            self.windows.is_upload_pic_num -= 1
-
         # 抠图
         out_root_path = "{}/已扣图".format(self.root_path)
         self.check_path(out_root_path)
-
-        # 直接调用pixian
-        # second_cut_image,_ = self.r_pixian.run_by_image_url(image_url)
-
         try:
-            balance = self.get_online_data.get_cutout_image_times()["balance"]
+            balance = self.get_online_data.get_cutout_image_times().get("balance")
             self.add_log("查询balance:{}成功".format(balance))
             if balance <= 0:
                 self.add_log("次数不足,处理失败")
                 raise UnicornException("次数不足,处理失败")
-                self.send_info(text="次数不足,处理失败", is_success=False)
-                return
         except:
             self.add_log("查询balance失败")
             raise UnicornException("查询balance失败")
-            self.send_info(text="查询balance失败", is_success=False)
-            return
-
         n = 0
-        while 1:
-            # 获取key
-            if self.windows.state != 1:
-                self.show_image_info(
-                    {
-                        "text": "已取消",
-                        "info": "",
-                    }
-                )
-                raise UnicornException("用户主动终止")
-                # self.send_info(text="用户主动终止", is_success=False)
-                return
-            n += 1
-            data = self.get_online_data.get_key_secret()
-            key = (data["api_info"]["api_key"], data["api_info"]["api_serect"])
-            self.add_log("查询key成功")
-
-            if not key:
-                _data = {
-                    "text": "出错/超时",
-                    "info": "多次获取key失败",
-                }
-                self.add_log(text="多次获取key失败")
-                self.show_image_info(_data)
-                raise UnicornException("处理失败,请联系管理员")
-                self.send_info(text="处理失败,请联系管理员", is_success=False)
-                return
-
-            if self.is_once("sub_point"):
-                # 调用扣分
-                with self.lock:
-                    self.refresh_times(cumulative_frequency_times_change=1)
-                    f = self.dispose_point(_type="sub")
-                if not f:
-                    self.add_log(text="多次获取调用余额扣减失败")
-                    raise UnicornException("多次获取调用余额扣减失败")
-                    self.send_info(text="多次获取调用余额扣减失败", is_success=False)
-                    _data = {
-                        "text": "出错/超时",
-                        "info": "多次获取调用余额扣减失败",
-                    }
-                    self.show_image_info(_data)
-                    return
-
-            pixian_cutout_data = self.r_pixian.run_by_image_im(original_im, key)
-            # pixian_cutout_data = {"status_code":200}
-
-            if pixian_cutout_data["status_code"] == 200:
-                second_cut_image = pixian_cutout_data["im"]
-                # second_cut_image.save("xx.png")
-                # second_cut_image = Image.open("xx.png")
-                self.add_log(text="调用抠图完成")
-                break
-
-            elif pixian_cutout_data["status_code"] == 402:
-                if n >= 2:
-                    _data = {
-                        "text": "出错/超时",
-                        "info": "多次抠图失败:{}".format(
-                            pixian_cutout_data["status_code"]
-                        ),
-                    }
-                    self.add_log(
-                        text="多次抠图失败:{}".format(pixian_cutout_data["status_code"])
-                    )
-                    self.show_image_info(_data)
-                    self.send_info(
-                        text="处理失败,请联系管理员",
-                        is_success=False,
-                        need_point_return=True,
-                    )
-                    raise UnicornException("多次获取调用余额扣减失败")
-                    if self.is_once("余额不足报错"):
-                        # todo 余额不足报错,钉钉消息通知
-                        self.get_online_data.send_message(
-                            "Pixian:{} 余额不足".format(key)
-                        )
-                        pass
-                    return
-                self.add_log(
-                    text="抠图失败:{},延迟6秒".format(
-                        pixian_cutout_data["status_code"]
-                    )
-                )
-                time.sleep(6)
-                continue
-
-            elif pixian_cutout_data["status_code"] == 429:
-                if n >= 2:
-                    _data = {
-                        "text": "出错/超时",
-                        "info": "多次抠图失败:{}".format(
-                            pixian_cutout_data["status_code"]
-                        ),
-                    }
-
-                    self.show_image_info(_data)
-                    self.add_log(
-                        text="多次抠图失败:{}".format(pixian_cutout_data["status_code"])
-                    )
-                    self.send_info(
-                        text="处理失败,请联系管理员",
-                        is_success=False,
-                        need_point_return=True,
-                    )
-                    return
-
-                self.add_log(
-                    text="抠图失败:{},延迟10秒".format(
-                        pixian_cutout_data["status_code"]
-                    )
-                )
-                time.sleep(10)
-                continue
-            else:
-                _data = {
-                    "text": "出错/超时",
-                    "info": "抠图异常",
-                }
-                self.show_image_info(_data)
-                self.send_info(
-                    text="处理失败,请联系管理员",
-                    is_success=False,
-                    need_point_return=True,
-                )
-                if "message" in pixian_cutout_data:
-                    text = "抠图异常,code:{},message:{}".format(
-                        pixian_cutout_data["status_code"], pixian_cutout_data["message"]
-                    )
-                else:
-                    text = "抠图异常,code:{}".format(
-                        pixian_cutout_data["status_code"]
-                    )
-                self.add_log(text)
-                return
-
-        # 拼接处理
-        # print("耗时1:", time.time() - s)
-
+        second_cut_image = self.runPiXian(n, original_im=original_im)
+        if second_cut_image is None:
+            raise UnicornException("抠图失败")
         try:
             out_path = "{}/{}.png".format(out_root_path, self.file_name)
             if image_deal_info["二次抠图是否缩放"]:
-                # print("图片尺寸还原")
                 self.add_log(text="图片尺寸进行还原")
                 original_im = image_deal_info["抠图扩边后PIL对象"]
                 second_cut_image = self.picture_resize_to_original(
                     second_cut_image, original_im
                 )
-                # second_cut_image = second_cut_image.resize(image_deal_info["抠图扩边后图片大小"])
             # 创建空白图片并粘贴回去
             _img_im = Image.new(
                 mode="RGBA", size=image_deal_info["原始图片大小"], color=(0, 0, 0, 0)
@@ -393,20 +186,85 @@ class DealOneImage(Base):
             text = "{} 图片处理错误,代码44".format(e)
             self.add_log(text)
             self.send_info(text=text, is_success=False, need_point_return=True)
-            _data = {
-                "text": "出错/超时",
-                "info": text,
-            }
-            self.show_image_info(_data)
-            return
+            _data = {"text": "出错/超时", "info": text, "status": False}
+            return _data
 
         self.add_log(text="本张耗时:{}".format(time.time() - s))
         self.send_info(text="抠图已完成", is_success=True)
-        self.show_image_info(
-            {
-                "text": "已完成",
-                "info": "",
+        result = {"text": "已完成", "info": "", "status": True}
+        return result
+
+    def runPiXian(self, num, original_im):
+        """执行pixian抠图"""
+        num += 1
+        data = self.get_online_data.get_key_secret()
+        key = (data["api_info"]["api_key"], data["api_info"]["api_serect"])
+        self.add_log("查询key成功")
+        if not key:
+            raise UnicornException("处理失败,请联系管理员")
+        if self.is_once("sub_point"):
+            # 调用扣分
+            self.refresh_times(cumulative_frequency_times_change=1)
+            f = self.dispose_point(_type="sub")
+            if not f:
+                self.add_log(text="多次获取调用余额扣减失败")
+                raise UnicornException("多次获取调用余额扣减失败")
+
+        pixian_cutout_data = self.r_pixian.run_by_image_im(original_im, key)
+        if pixian_cutout_data["status_code"] == 200:
+            second_cut_image = pixian_cutout_data["im"]
+            self.add_log(text="调用抠图完成")
+            return second_cut_image
+
+        elif pixian_cutout_data["status_code"] == 402:
+            if num >= 2:
+                self.cutoutFail(pixian_cutout_data)
+                raise UnicornException("多次获取调用余额扣减失败")
+            self.add_log(
+                text="抠图失败:{},延迟6秒".format(pixian_cutout_data["status_code"])
+            )
+            time.sleep(6)
+            self.runPiXian(num, original_im=original_im)
+
+        elif pixian_cutout_data["status_code"] == 429:
+            if num >= 2:
+                self.cutoutFail(pixian_cutout_data)
+                return None
+
+            self.add_log(
+                text="抠图失败:{},延迟10秒".format(pixian_cutout_data["status_code"])
+            )
+            time.sleep(10)
+            self.runPiXian(num, original_im=original_im)
+        else:
+            _data = {
+                "text": "出错/超时",
+                "info": "抠图异常",
             }
+            self.show_image_info(_data)
+            self.get_online_data.dispose_point("add")
+            if "message" in pixian_cutout_data:
+                text = "抠图异常,code:{},message:{}".format(
+                    pixian_cutout_data["status_code"], pixian_cutout_data["message"]
+                )
+            else:
+                text = "抠图异常,code:{}".format(pixian_cutout_data["status_code"])
+            self.add_log(text)
+            return None
+        return second_cut_image
+
+    def cutoutFail(self, pixian_cutout_data):
+        """处理失败"""
+        _data = {
+            "text": "出错/超时",
+            "info": "多次抠图失败:{}".format(pixian_cutout_data["status_code"]),
+        }
+        self.show_image_info(_data)
+        self.add_log(text="多次抠图失败:{}".format(pixian_cutout_data["status_code"]))
+        self.send_info(
+            text="处理失败,请联系管理员",
+            is_success=False,
+            need_point_return=True,
         )
 
     def picture_resize_to_original(self, _img, original_im):
@@ -455,80 +313,20 @@ class DealOneImage(Base):
 class DealOneImageBeforehand(Base):
     def __init__(self, image_data, lock, windows, num):
         super().__init__(image_data, lock, windows, num)
-        self.image_data = image_data
-        self.lock = lock
-        self.windows = windows
-        self.get_online_data = GetOnlineData()
-        self.num = num
-        self.file_path = image_data["file_path"]
-        self.file = os.path.split(self.file_path)[1]
-        self.root_path = image_data["root_path"]
         self.r_ali = RemoveBgALi()
-        self.file_name = image_data["file_name"]
 
-    def run(self):
+    def run(self, upload_pic_dict):
         # 增加阿里调用报错的重试机制
-        # a = 1/0
-        # raise "11111111111111111"
-        while 1:
-            if self.windows.state != 1:
-                self.show_image_info(
-                    {
-                        "text": "已取消",
-                        "info": "",
-                    }
-                )
-                return
-            with self.lock:
-                if self.windows.is_upload_pic_num >= 4:
-                    f = False
-                else:
-                    self.windows.is_upload_pic_num += 1
-                    f = True
-            if f:
-                break
-            else:
-                time.sleep(1)
-                continue
         image_deal_info = {}
         try:
-            _data = {
-                "text": "开始上传",
-                "info": "",
-            }
-            self.show_image_info(_data)
             cut_image, image_deal_info = self.get_image_cut()
-
-            f = True
-            url = ""
-            self.show_image_info(
-                {
-                    "text": "上传成功",
-                    "info": "",
-                }
-            )
         except BaseException as e:
-            # print(e)
-            self.show_image_info(
-                {
-                    "text": "上传出错",
-                    "info": "{}".format(e),
-                }
-            )
-            f = False
-            url = ""
-            cut_image = ""
-
-        # cut_image.save("1.jpg",format="JPEG")
-        # raise 1
-
-        with self.lock:
-            self.windows.upload_pic_dict[self.file_path] = {
-                "url": url,
-                "image_deal_info": image_deal_info,
-                "flag": f,
-                "_im": cut_image,
-            }
+            raise UnicornException("上传出错")
+        upload_pic_dict[self.file_path] = {
+            "image_deal_info": image_deal_info,
+            "_im": cut_image,
+        }
+        return upload_pic_dict
 
     def get_image_cut(self):
         original_pic = Picture(self.file_path)
@@ -548,7 +346,7 @@ class DealOneImageBeforehand(Base):
             cut_image = self.r_ali.get_image_cut(
                 file_path=None, out_file_path=None, original_im=original_pic.im
             )
-            # cut_image.save("XX1.png")
+            cut_image.save("XX1.png")
 
             self.add_log("预抠图处理结束")
 
@@ -593,6 +391,69 @@ class DealOneImageBeforehand(Base):
                 image_deal_info["二次抠图是否缩放"] = False
         return cut_image, image_deal_info
 
+    def get_image_cut_cloths(self):
+        original_pic = Picture(self.file_path)
+        original_pic.im = self.get_image_orientation(original_pic.im)
+        original_pic.x, original_pic.y = original_pic.im.size
+
+        original_pic.im = original_pic.im.convert("RGB")
+        image_deal_info = {}
+        image_deal_info["原始图片大小"] = (original_pic.x, original_pic.y)
+        self.add_log("开始预抠图处理")
+        remaining_times = self.get_online_data.get_cutout_image_times().get("balance")
+        print("remaining_times", remaining_times)
+        if remaining_times <= 0:
+            raise UnicornException("次数不足,处理失败")
+        self.get_online_data.dispose_point("sub")
+        cut_images = self.r_ali.get_image_cut_cloths(
+            file_path=None, out_file_path=None, original_im=original_pic.im
+        )
+        if cut_images is None:
+            self.get_online_data.dispose_point("add")
+        self.add_log("预抠图处理结束")
+        print("cut_images", cut_images)
+        return
+        x1, y1, x2, y2 = cut_image.getbbox()
+        image_deal_info["鞋子原始位置"] = (x1, y1, x2, y2)
+        o_w, o_h = cut_image.size
+        image_deal_info["鞋子原始抠图后大小"] = (o_w, o_h)
+        # 扩边处理
+        _w, _h = x2 - x1, y2 - y1
+        out_px = 0.025
+        _w, _h = int(out_px * _w), int(out_px * _h)
+        n_x1, n_y1, n_x2, n_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h
+        if n_x1 < 0:
+            n_x1 = 0
+        if n_y1 < 0:
+            n_y1 = 0
+        if n_x2 > o_w:
+            n_x2 = o_w
+        if n_y2 > o_h:
+            n_y2 = o_h
+        image_deal_info["抠图扩边后位置"] = (n_x1, n_y1, n_x2, n_y2)
+        cut_image = original_pic.im.crop(image_deal_info["抠图扩边后位置"])
+
+        image_deal_info["抠图扩边后图片大小"] = cut_image.size
+        x, y = image_deal_info["抠图扩边后图片大小"]
+        # max_size = 32000000
+        max_size = 12000000
+        if x * y > max_size:
+            r = max_size / (x * y)
+            size = (int(x * r), int(y * r))
+            self.add_log(
+                text="图片进行压缩,压缩前:{},压缩后:{}".format(
+                    image_deal_info["抠图扩边后图片大小"], size
+                )
+            )
+            image_deal_info["抠图扩边后PIL对象"] = copy.deepcopy(cut_image)
+            cut_image = cut_image.resize(size=size)
+            # print(cut_image.size)
+            # print(image_deal_info["抠图扩边后PIL对象"].size)
+            image_deal_info["二次抠图是否缩放"] = True
+        else:
+            image_deal_info["二次抠图是否缩放"] = False
+        return cut_image, image_deal_info
+
     def get_image_orientation(self, img):
         # 获取EXIF数据
         exif = img._getexif()

+ 133 - 40
python/services/other/remove_bg_ali.py

@@ -21,7 +21,8 @@ from .module_online_data import GetOnlineData
 # 惠利玛的key
 AccessKeyId = "LTAI5tBdDVT9Wc5idJXdGHjw"
 AccessKeySecret = "bCSotQ7eAztOxx6AqHwJJPsb0hkECe"
-
+ALI_MAPPING = {"tops": "上衣", "coat": "外套", "skirt": "裙装", "pants": "裤装"}
+ALI_CLOTH_CLASSES = ["tops", "coat", "skirt", "pants"]
 
 # https://help.aliyun.com/zh/viapi/developer-reference/python?spm=a2c4g.11186623.0.i0#task-2252575
 # pip install alibabacloud_goodstech20191230
@@ -39,59 +40,43 @@ class Segment(object):
         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 get_no_bg_cloths(self, _im=None):
+        im = _im
+        img = BytesIO()
+        im.save(img, format="JPEG")  # format: PNG or JPEG
+        img.seek(0)  # rewind to the start
+        request = imageseg_20191230_models.SegmentClothAdvanceRequest()
+        request.image_urlobject = img
+        request.cloth_class = ALI_CLOTH_CLASSES
+        client = self.create_client()
+        # 5、调用api,注意,recognize_bank_card_advance需要更换为相应能力对应的方法名。方法名是根据能力名称按照一定规范形成的,如能力名称为SegmentCommonImage,对应方法名应该为segment_common_image_advance。
+        runtime = util_models.RuntimeOptions()
+        response = client.segment_cloth_advance(request, runtime)
         return response.body
 
     def create_client(self):
@@ -118,7 +103,7 @@ class Picture:
         if im:
             self.im = im
         else:
-            self.im = Image.open(in_path)
+            self.im = Image.open(in_path).convert("RGB")
         self.x, self.y = self.im.size
         # print(self.x, self.y)
 
@@ -216,6 +201,122 @@ class RemoveBgALi(object):
             _img_im.save(out_file_path)
         return _img_im
 
+    def get_image_cut_cloths(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)
+        body = self.segment.get_no_bg_cloths(_im=new_pic.im)
+        body = eval(str(body))
+        clothsArray = []
+        try:
+            Elements = body["Data"]["Elements"]
+            for idx, clothItem in enumerate(Elements):
+                if idx == 0:
+                    ImageURL = clothItem.get("ImageURL")
+                    print("clothItem", clothItem)
+                    response = requests.get(ImageURL)
+                    pic = response.content
+                    _img_im = Image.open(BytesIO(pic))
+                    clothsArray.append(
+                        {"type": "all", "cn_name": "合并图", "pilImage": _img_im}
+                    )
+                else:
+                    ClassUrl = clothItem.get("ClassUrl")
+                    classKeys = ClassUrl.keys()
+                    for classKey in classKeys:
+                        keyUrl = ClassUrl.get(classKey)
+                        response = requests.get(keyUrl)
+                        pic = response.content
+                        mask_image = Image.open(BytesIO(pic))
+                        if self.isEmptyMask(mask_image.convert("RGB")):
+                            continue
+                        if mask_image.mode != "L":
+                            mask_image = mask_image.convert("L")
+                        # 使用蒙版图像对原图进行抠图
+                        result_image = new_pic.im.copy()
+                        result_image.putalpha(mask_image)
+                        clothsArray.append(
+                            {
+                                "type": classKey,
+                                "cn_name": ALI_MAPPING[classKey],
+                                "pilImage": result_image,
+                            }
+                        )
+        except BaseException as e:
+            # todo 处理失败,需要删除过程图片
+            print(e)
+            return None
+        image_arrs = []
+        for _, item in enumerate(clothsArray):
+            _img_im = item["pilImage"]
+            type = item["type"]
+            cn_name = item["cn_name"]
+            # 原图更大,则需要执行CV处理
+            if after_need_resize:
+                _img_im = self.clothsDispose(
+                    _img_im, original_pic=original_pic, out_file_path=out_file_path
+                )
+            _img_im.save(f"{cn_name}.png")
+            image_arrs.append({"image_obj": _img_im, "type": type, "cn_name": cn_name})
+        return image_arrs
+
+    def isEmptyMask(self, img):
+        data = np.array(img)
+        max_index = np.unravel_index(np.argmax(data, axis=None), data.shape)
+        max_value = data[max_index]
+        return True if max_value == 0 else False
+
+    def clothsDispose(self, _img_im, original_pic, out_file_path):
+        # 将抠图结果转成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")
+        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)
@@ -237,20 +338,12 @@ class RemoveBgALi(object):
 
         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)

+ 19 - 0
python/services/other/remove_bg_cloth_ali.py

@@ -0,0 +1,19 @@
+# 服装背景抠图
+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 .module_online_data import GetOnlineData
+AccessKeyId = "LTAI5tBdDVT9Wc5idJXdGHjw"
+AccessKeySecret = "bCSotQ7eAztOxx6AqHwJJPsb0hkECe"