remove_bg_ali.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import copy
  2. import json
  3. import os
  4. from PIL import Image
  5. from alibabacloud_imageseg20191230.client import Client as imageseg20191230Client
  6. from alibabacloud_imageseg20191230.models import SegmentCommodityAdvanceRequest
  7. from alibabacloud_imageseg20191230 import models as imageseg_20191230_models
  8. from alibabacloud_tea_util.models import RuntimeOptions
  9. from alibabacloud_tea_openapi import models as open_api_models
  10. from alibabacloud_tea_openapi.models import Config
  11. from alibabacloud_tea_util import models as util_models
  12. import requests
  13. from io import BytesIO
  14. import cv2
  15. import numpy as np
  16. from .module_online_data import GetOnlineData
  17. from Tea.exceptions import TeaException
  18. from middleware import UnicornException
  19. # todo 获取密钥
  20. # key_id,key_secret = GetOnlineData().get_cutout_image_config()
  21. # 惠利玛的key
  22. AccessKeyId = "LTAI5tBdDVT9Wc5idJXdGHjw"
  23. AccessKeySecret = "bCSotQ7eAztOxx6AqHwJJPsb0hkECe"
  24. ALI_MAPPING = {"tops": "上衣", "coat": "外套", "skirt": "裙装", "pants": "裤装"}
  25. ALI_CLOTH_CLASSES = ["tops", "coat", "skirt", "pants"]
  26. # https://help.aliyun.com/zh/viapi/developer-reference/python?spm=a2c4g.11186623.0.i0#task-2252575
  27. # pip install alibabacloud_goodstech20191230
  28. # pip install alibabacloud_tea_openapi
  29. # pip install alibabacloud_tea_util
  30. class Segment(object):
  31. def __init__(self):
  32. self.client = self.create_client()
  33. def get_no_bg_common(self, file_path):
  34. # 初始化RuntimeObject
  35. runtime_option = RuntimeOptions()
  36. try:
  37. # 场景一:文件在本地
  38. img = open(file_path, "rb")
  39. request = SegmentCommodityAdvanceRequest()
  40. request.image_urlobject = img
  41. response = self.client.segment_common_image_advance(request, runtime_option)
  42. # 获取整体结果
  43. # print(response.body)
  44. img.close()
  45. return response.body
  46. except Exception as error:
  47. # 获取整体报错信息
  48. print("error", error)
  49. return None
  50. def get_no_bg_goods(self, file_path=None, _im=None):
  51. im = _im
  52. img = BytesIO()
  53. im.save(img, format="JPEG") # format: PNG or JPEG
  54. img.seek(0) # rewind to the start
  55. request = imageseg_20191230_models.SegmentCommodityAdvanceRequest()
  56. request.image_urlobject = img
  57. client = self.create_client()
  58. # 5、调用api,注意,recognize_bank_card_advance需要更换为相应能力对应的方法名。方法名是根据能力名称按照一定规范形成的,如能力名称为SegmentCommonImage,对应方法名应该为segment_common_image_advance。
  59. runtime = util_models.RuntimeOptions()
  60. response = client.segment_commodity_advance(request, runtime)
  61. return response.body
  62. def get_no_bg_cloths(self, _im=None):
  63. im = _im
  64. img = BytesIO()
  65. im.save(img, format="JPEG") # format: PNG or JPEG
  66. img.seek(0) # rewind to the start
  67. request = imageseg_20191230_models.SegmentClothAdvanceRequest()
  68. request.image_urlobject = img
  69. request.cloth_class = ALI_CLOTH_CLASSES
  70. client = self.create_client()
  71. # 5、调用api,注意,recognize_bank_card_advance需要更换为相应能力对应的方法名。方法名是根据能力名称按照一定规范形成的,如能力名称为SegmentCommonImage,对应方法名应该为segment_common_image_advance。
  72. runtime = util_models.RuntimeOptions()
  73. response = client.segment_cloth_advance(request, runtime)
  74. return response.body
  75. def create_client(self):
  76. """
  77. 使用AK&SK初始化账号Client
  78. @param access_key_id:
  79. @param access_key_secret:
  80. @return: Client
  81. @throws Exception
  82. """
  83. config = open_api_models.Config(
  84. # 必填,您的 AccessKey ID,
  85. access_key_id=AccessKeyId,
  86. # 必填,您的 AccessKey Secret,
  87. access_key_secret=AccessKeySecret,
  88. )
  89. # 访问的域名
  90. config.endpoint = f"imageseg.cn-shanghai.aliyuncs.com"
  91. return imageseg20191230Client(config)
  92. class Picture:
  93. def __init__(self, in_path, im=None):
  94. if im:
  95. self.im = im
  96. else:
  97. self.im = Image.open(in_path).convert("RGB")
  98. self.x, self.y = self.im.size
  99. # print(self.x, self.y)
  100. def save_img(self, outpath, quality=90):
  101. # self.im = self.im.convert("RGB")
  102. self.im.save(outpath, quality=quality)
  103. def resize(self, width):
  104. re_x = int(width)
  105. re_y = int(self.y * re_x / self.x)
  106. self.im = self.im.resize((re_x, re_y), Image.BICUBIC)
  107. self.x, self.y = self.im.size
  108. def resize_by_heigh(self, heigh):
  109. re_y = int(heigh)
  110. re_x = int(self.x * re_y / self.y)
  111. self.im = self.im.resize((re_x, re_y), Image.BICUBIC)
  112. self.x, self.y = self.im.size
  113. class RemoveBgALi(object):
  114. def __init__(self):
  115. self.segment = Segment()
  116. def get_image_cut(self, file_path, out_file_path=None, original_im=None):
  117. if original_im:
  118. original_pic = Picture(in_path=None, im=original_im)
  119. else:
  120. original_pic = Picture(file_path)
  121. if original_pic.im.mode != "RGB":
  122. print("抠图图片不能是PNG")
  123. return None
  124. new_pic = copy.copy(original_pic)
  125. after_need_resize = False
  126. if new_pic.x > new_pic.y:
  127. if new_pic.x > 2000:
  128. after_need_resize = True
  129. new_pic.resize(2000)
  130. else:
  131. if new_pic.y > 2000:
  132. after_need_resize = True
  133. new_pic.resize_by_heigh(heigh=2000)
  134. # new_pic.im.show()
  135. body = self.segment.get_no_bg_goods(file_path=None, _im=new_pic.im)
  136. body = eval(str(body))
  137. try:
  138. image_url = body["Data"]["ImageURL"]
  139. except BaseException as e:
  140. print("阿里抠图错误:", e)
  141. # todo 处理失败,需要删除过程图片
  142. return None
  143. # 字节流转PIL对象
  144. response = requests.get(image_url)
  145. pic = response.content
  146. _img_im = Image.open(BytesIO(pic)) # 阿里返回的抠图结果 已转PIL对象
  147. # 原图更大,则需要执行CV处理
  148. if after_need_resize:
  149. # 将抠图结果转成mask
  150. # _img_im = Image.open(_path)
  151. # 将抠图结果放大到原始图大小
  152. _img_im = _img_im.resize(original_pic.im.size)
  153. new_big_mask = Image.new("RGB", _img_im.size, (0, 0, 0))
  154. white = Image.new("RGB", _img_im.size, (255, 255, 255))
  155. new_big_mask.paste(white, mask=_img_im.split()[3])
  156. # ---------制作选区缩小的mask
  157. # mask = cv2.imread(mask_path)
  158. # mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
  159. mask = cv2.cvtColor(
  160. np.asarray(new_big_mask), cv2.COLOR_BGR2GRAY
  161. ) # 将PIL 格式转换为 CV对象
  162. mask[mask != 255] = 0
  163. # 黑白反转
  164. # mask = 255 - mask
  165. # 选区缩小10
  166. kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
  167. erode_im = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
  168. # -------再进行抠图处理
  169. mask = Image.fromarray(
  170. cv2.cvtColor(erode_im, cv2.COLOR_GRAY2RGBA)
  171. ) # CV 对象转 PIL
  172. transparent_im = Image.new("RGBA", original_pic.im.size, (0, 0, 0, 0))
  173. # original_pic.im.show()
  174. # mask.show()
  175. transparent_im.paste(original_pic.im, (0, 0), mask.convert("L"))
  176. # transparent_im.show()
  177. # 上述抠图结果进行拼接
  178. _img_im.paste(transparent_im, (0, 0), transparent_im)
  179. # _img_im.show("11111111111111111111111")
  180. if out_file_path:
  181. _img_im.save(out_file_path)
  182. return _img_im
  183. def get_image_cut_cloths(self, file_path, out_file_path=None, original_im=None):
  184. if original_im:
  185. original_pic = Picture(in_path=None, im=original_im)
  186. else:
  187. original_pic = Picture(file_path)
  188. if original_pic.im.mode != "RGB":
  189. print("抠图图片不能是PNG")
  190. return None
  191. new_pic = copy.copy(original_pic)
  192. after_need_resize = False
  193. if new_pic.x > new_pic.y:
  194. if new_pic.x > 2000:
  195. after_need_resize = True
  196. new_pic.resize(2000)
  197. else:
  198. if new_pic.y > 2000:
  199. after_need_resize = True
  200. new_pic.resize_by_heigh(heigh=2000)
  201. try:
  202. body = self.segment.get_no_bg_cloths(_im=new_pic.im)
  203. body = eval(str(body))
  204. clothsArray = []
  205. Elements = body["Data"]["Elements"]
  206. for idx, clothItem in enumerate(Elements):
  207. if idx == 0:
  208. ImageURL = clothItem.get("ImageURL")
  209. print("clothItem", clothItem)
  210. response = requests.get(ImageURL)
  211. pic = response.content
  212. _img_im = Image.open(BytesIO(pic))
  213. clothsArray.append(
  214. {"type": "all", "cn_name": "合并图", "pilImage": _img_im}
  215. )
  216. else:
  217. ClassUrl = clothItem.get("ClassUrl")
  218. classKeys = ClassUrl.keys()
  219. for classKey in classKeys:
  220. keyUrl = ClassUrl.get(classKey)
  221. response = requests.get(keyUrl)
  222. pic = response.content
  223. mask_image = Image.open(BytesIO(pic))
  224. if self.isEmptyMask(mask_image.convert("RGB")):
  225. continue
  226. if mask_image.mode != "L":
  227. mask_image = mask_image.convert("L")
  228. # 使用蒙版图像对原图进行抠图
  229. result_image = new_pic.im.copy()
  230. result_image.putalpha(mask_image)
  231. clothsArray.append(
  232. {
  233. "type": classKey,
  234. "cn_name": ALI_MAPPING[classKey],
  235. "pilImage": result_image,
  236. }
  237. )
  238. except TeaException as teaError:
  239. raise UnicornException(teaError.data.get("Message"))
  240. return None
  241. except BaseException as e:
  242. # todo 处理失败,需要删除过程图片
  243. print("Exception",e)
  244. return None
  245. image_arrs = []
  246. for _, item in enumerate(clothsArray):
  247. _img_im = item["pilImage"]
  248. type = item["type"]
  249. cn_name = item["cn_name"]
  250. # 原图更大,则需要执行CV处理
  251. if after_need_resize:
  252. _img_im = self.clothsDispose(
  253. _img_im, original_pic=original_pic, out_file_path=out_file_path
  254. )
  255. image_arrs.append({"image_obj": _img_im, "type": type, "cn_name": cn_name})
  256. return image_arrs
  257. def isEmptyMask(self, img):
  258. data = np.array(img)
  259. max_index = np.unravel_index(np.argmax(data, axis=None), data.shape)
  260. max_value = data[max_index]
  261. return True if max_value == 0 else False
  262. def clothsDispose(self, _img_im, original_pic, out_file_path):
  263. # 将抠图结果转成mask
  264. # _img_im = Image.open(_path)
  265. # 将抠图结果放大到原始图大小
  266. _img_im = _img_im.resize(original_pic.im.size)
  267. new_big_mask = Image.new("RGB", _img_im.size, (0, 0, 0))
  268. white = Image.new("RGB", _img_im.size, (255, 255, 255))
  269. new_big_mask.paste(white, mask=_img_im.split()[3])
  270. # ---------制作选区缩小的mask
  271. # mask = cv2.imread(mask_path)
  272. # mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
  273. mask = cv2.cvtColor(
  274. np.asarray(new_big_mask), cv2.COLOR_BGR2GRAY
  275. ) # 将PIL 格式转换为 CV对象
  276. mask[mask != 255] = 0
  277. # 黑白反转
  278. # mask = 255 - mask
  279. # 选区缩小10
  280. kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
  281. erode_im = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
  282. # -------再进行抠图处理
  283. mask = Image.fromarray(
  284. cv2.cvtColor(erode_im, cv2.COLOR_GRAY2RGBA)
  285. ) # CV 对象转 PIL
  286. transparent_im = Image.new("RGBA", original_pic.im.size, (0, 0, 0, 0))
  287. # original_pic.im.show()
  288. # mask.show()
  289. transparent_im.paste(original_pic.im, (0, 0), mask.convert("L"))
  290. # transparent_im.show()
  291. # 上述抠图结果进行拼接
  292. _img_im.paste(transparent_im, (0, 0), transparent_im)
  293. # _img_im.show("11111111111111111111111")
  294. return _img_im
  295. def get_image_cut1(self, file_path, out_file_path=None):
  296. original_pic = Picture(file_path)
  297. new_pic = copy.copy(original_pic)
  298. if new_pic.x > 2000:
  299. new_pic.resize(2000)
  300. # new_pic.im.show()
  301. body = self.segment.get_no_bg_goods(file_path=out_file_path, _im=new_pic.im)
  302. body = eval(str(body))
  303. try:
  304. image_url = body["Data"]["ImageURL"]
  305. except BaseException as e:
  306. print("阿里抠图错误:", e)
  307. # todo 处理失败,需要删除过程图片
  308. return None
  309. # 字节流转PIL对象
  310. response = requests.get(image_url)
  311. pic = response.content
  312. _img_im = Image.open(BytesIO(pic)) # 阿里返回的抠图结果 已转PIL对象
  313. if original_pic.x > 2000:
  314. # 原图更大,则需要执行CV处理
  315. # 对mask进行放大,然后进行抠图处理
  316. print("对mask进行放大,然后进行抠图处理")
  317. transparent_im = Image.new("RGBA", original_pic.im.size, (0, 0, 0, 0))
  318. _img_im = _img_im.resize((original_pic.x, original_pic.y))
  319. transparent_im.paste(original_pic.im, (0, 0), mask=_img_im)
  320. _img_im = transparent_im
  321. pass
  322. _img_im.save(out_file_path)
  323. return _img_im
  324. def download_picture(self, url, out_path):
  325. response = requests.get(url)
  326. pic = response.content
  327. with open(out_path, "wb") as f:
  328. f.write(pic)
  329. if __name__ == "__main__":
  330. r = RemoveBgALi()
  331. path = r"D:\MyDocuments\PythonCode\MyPython\red_dragonfly\deal_pics\auto_capture_V2\IPC\test\171112057820408.png"
  332. out_path = "{}._no_bg-out.png".format(path)
  333. r.get_image_cut(path, out_file_path=out_path)