remove_bg_ali.py 14 KB

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