base_deal.py 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. import json
  2. from module.view_control.generate_goods_art_no_table.module_generate_goods_art_no_table import GenerateGoodsArtNoTable
  3. from module.view_control.generate_main_image.grenerate_main_image_test import GeneratePic
  4. from import_qt_mode import *
  5. from threading import Lock
  6. import settings
  7. from collections import defaultdict
  8. from module.base_mode.remove_bg_ali import RemoveBgALi, Picture
  9. from module.cutout_mode.deal_cutout import DealCutout
  10. from module.view_control.matching_photos.data import DataModeMatchPhoto
  11. from module.base_mode.base import *
  12. from module.view_control.auto_deal_pics.data import DataModeAutoDealPics
  13. import time
  14. from module.base_mode.image_pic_deal import OnePicDeal
  15. """
  16. 照片自动货号匹配 将图片放置在指定文件夹下,并自动对应不同的货号进行整理
  17. """
  18. _Type = ['.png', '.PNG', '.jpg', '.JPG', '.gif', '.GIF', ".jpge", ".JPGE"]
  19. class BaseDealImage(object):
  20. def __init__(self, image_dir=None):
  21. self.goods_images_count_dict = defaultdict(int)
  22. self.dataModeMatchPhoto = DataModeMatchPhoto()
  23. # 数据模型
  24. self.data_mode_auto_deal_pics = DataModeAutoDealPics()
  25. self.image_dir = image_dir
  26. pass
  27. def run_main(self, all_goods_art_no_folder_data, callback_func=None, cutout_mode=None,
  28. resize_image_view=None, windows=None, logo_path=None, image_order_list=None):
  29. # 对所有缺失已抠图的进行抠图处理
  30. self.run_cutout_image(all_goods_art_no_folder_data=all_goods_art_no_folder_data,
  31. callback_func=callback_func,
  32. cutout_mode=cutout_mode,
  33. windows=windows,
  34. )
  35. error_num = 0
  36. successful_num = 0
  37. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  38. if goods_art_no_folder_data["label"] != "待处理":
  39. continue
  40. if windows:
  41. if windows.state != 1:
  42. break
  43. folder_name = goods_art_no_folder_data["folder_name"]
  44. callback_func("开始处理文件夹========== {} ".format(folder_name))
  45. if settings.IS_TEST:
  46. flag = self.shoes_run_one_folder_to_deal(goods_art_no_folder_data=goods_art_no_folder_data,
  47. resize_image_view=resize_image_view,
  48. logo_path=logo_path,
  49. image_order_list=image_order_list,
  50. callback_func=callback_func,
  51. windows=windows,
  52. )
  53. if flag is None:
  54. callback_func("货号:{} 数据异常".format(folder_name))
  55. else:
  56. if flag:
  57. successful_num += 1
  58. callback_func("货号:{} 图片生成处理成功".format(folder_name))
  59. else:
  60. error_num += 1
  61. callback_func("货号:{} 图片生成处理失败".format(folder_name))
  62. else:
  63. try:
  64. flag = self.shoes_run_one_folder_to_deal(goods_art_no_folder_data=goods_art_no_folder_data,
  65. resize_image_view=resize_image_view,
  66. logo_path=logo_path,
  67. image_order_list=image_order_list,
  68. callback_func=callback_func,
  69. windows=windows,
  70. )
  71. if flag is None:
  72. callback_func("货号:{} 数据异常".format(folder_name))
  73. else:
  74. if flag:
  75. successful_num += 1
  76. callback_func("货号:{} 图片生成处理成功".format(folder_name))
  77. else:
  78. error_num += 1
  79. callback_func("货号:{} 图片生成处理失败".format(folder_name))
  80. except BaseException as e:
  81. error_num += 1
  82. callback_func("货号:{} 图片生成处理异常,原因:{}".format(folder_name, e))
  83. callback_func("处理成功:{}个,失败:{}".format(successful_num, error_num))
  84. def checkImageAmount(self, image_dir: str, amount: int, todo_goods_art_no_folder_name_list=None) -> dict:
  85. result = {'code': 0, 'msg': '', 'data': {}}
  86. for goods_art_no_folder in self.list_dir(image_dir):
  87. # 指定内容检查
  88. if todo_goods_art_no_folder_name_list is not None:
  89. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  90. continue
  91. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  92. continue
  93. if "软件" in goods_art_no_folder:
  94. continue
  95. if "无法" in goods_art_no_folder:
  96. continue
  97. if "原始图" not in self.list_dir("{}/{}".format(image_dir, goods_art_no_folder)):
  98. result['data'][goods_art_no_folder] = '文件夹下,没有 原始图 文件夹\n'
  99. continue
  100. # 计算单个文件夹原图数量
  101. images = [x for x in self.list_dir("{}/{}/原始图".format(image_dir, goods_art_no_folder))]
  102. image_num = 0
  103. for pic_file_name in images:
  104. _, e = os.path.splitext(pic_file_name)
  105. if e in _Type:
  106. image_num += 1
  107. # if self.number_pictures != 0:
  108. if image_num > amount:
  109. result['data'][goods_art_no_folder] = '货号图片大于{}张~\n'.format(amount)
  110. if image_num < 2:
  111. result['data'][goods_art_no_folder] = '货号图片小于于2张~\n'
  112. if result['data']:
  113. result['code'] = 1
  114. return result
  115. def check_folders_image_amount(self, all_goods_art_no_folder_data, image_order_list):
  116. amount = len(image_order_list)
  117. message = ""
  118. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  119. if goods_art_no_folder_data["label"] != "待处理":
  120. continue
  121. folder_path = goods_art_no_folder_data["folder_path"]
  122. folder_name = goods_art_no_folder_data["folder_name"]
  123. images = [x for x in self.list_dir("{}/原始图".format(folder_path))]
  124. image_num = 0
  125. for pic_file_name in images:
  126. _, e = os.path.splitext(pic_file_name)
  127. if e in _Type:
  128. image_num += 1
  129. if image_num > amount:
  130. goods_art_no_folder_data["label"] = "错误"
  131. message += '货号{}:图片大于{}张~\n'.format(folder_name, amount)
  132. if image_num < 2:
  133. message += '货号{}:图片小于于2张~\n'.format(folder_name)
  134. return all_goods_art_no_folder_data, message
  135. def check_one_folder_image_amount(self, folder_data, amount: int):
  136. # 计算单个文件夹原图数量
  137. images = [x for x in self.list_dir("{}/原始图".format(folder_data["folder_path"]))]
  138. image_num = 0
  139. for pic_file_name in images:
  140. _, e = os.path.splitext(pic_file_name)
  141. if e in _Type:
  142. image_num += 1
  143. if image_num > amount:
  144. return False, '货号{}:图片大于{}张~\n'.format(folder_data["folder_name"], amount)
  145. if image_num < 2:
  146. return False, '货号{}:图片小于于2张~\n'.format(folder_data["folder_name"])
  147. return True, ""
  148. # 指定的图片顺序
  149. def getImageOrder(self, image_order: str, resize_image_view: str):
  150. imageOrderList = image_order.replace(",", ",").replace(' ', '').replace('图', '').split(",")
  151. if len(set(imageOrderList)) != len(imageOrderList):
  152. return {'code': 1, 'msg': '图片位置与顺序重复,请检查您的输入'}
  153. for val in imageOrderList:
  154. if val not in ["俯视", "侧视", "后跟", "鞋底", "内里", "组合", "组合2", "组合3", "组合4", "组合5"]:
  155. return {'code': 1, 'msg': '可选项为:俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5'}
  156. if resize_image_view not in imageOrderList:
  157. return {'code': 1, 'msg': '缩小的步骤必须是你填写的图片顺序中'}
  158. return {'code': 0, 'msg': 'sucess', 'imageOrderList': imageOrderList}
  159. def shoes_run_one_folder_to_deal(self,
  160. goods_art_no_folder_data,
  161. image_order_list: list,
  162. resize_image_view: str,
  163. logo_path="",
  164. windows=None,
  165. callback_func=None):
  166. """
  167. 操作步骤:
  168. 1、查询每个图片的角度
  169. 2、
  170. """
  171. is_successful = True
  172. folder_path = goods_art_no_folder_data["folder_path"]
  173. folder_name = goods_art_no_folder_data["folder_name"]
  174. all_original_images = self.get_images("{}/原始图".format(folder_path))
  175. self.check_path('{}/800x800'.format(folder_path))
  176. self.crate_all_folders(folder_path)
  177. if not all_original_images:
  178. return None
  179. # _ = ["俯视", "侧视", "后跟", "鞋底", "内里"]
  180. for index, image_dict in enumerate(all_original_images):
  181. if index < len(image_order_list):
  182. image_dict["image_view"] = image_order_list[index]
  183. else:
  184. image_dict["image_view"] = '其他{}'.format(len(image_order_list) - index + 1)
  185. # ====================处理所有图片的顺序====================
  186. # ["俯视", "侧视", "后跟", "鞋底", "内里"]
  187. _config = {"俯视": 1,
  188. "侧视": 2,
  189. "后跟": 3,
  190. "鞋底": 4,
  191. "内里": 5, }
  192. r = time.time()
  193. n = 0
  194. _index = 0
  195. # 检查是否有重复的角度
  196. _d_views = []
  197. f = True
  198. for image_dict in all_original_images:
  199. n += 1
  200. _index += 1
  201. image_dict["old_file_name"] = image_dict["file_name"]
  202. image_dict["random_name"] = "{}-{}".format(r, n)
  203. if image_dict["image_view"] in _config:
  204. if image_dict["image_view"] not in _d_views:
  205. _d_views.append(image_dict["image_view"])
  206. else:
  207. callback_func("货号:{} 处理失败".format(folder_name))
  208. # self.show_progress_detail("货号图{} 存在多个{} 角度~".format(goods_art_no_folder, image_dict["image_view"]))
  209. return None
  210. image_dict["index"] = _config[image_dict["image_view"]]
  211. else:
  212. image_dict["index"] = _index
  213. all_original_images.sort(key=lambda x: x["index"])
  214. # ==========直接进行处理=============
  215. i_n = 0
  216. image_index = 0 # 图片顺序
  217. is_image_deal_mode = 0
  218. # 删除目录再新建
  219. if os.path.exists('{}/阴影图处理'.format(folder_path)):
  220. shutil.rmtree('{}/阴影图处理'.format(folder_path))
  221. self.crate_all_folders(folder_path)
  222. for image_dict in all_original_images:
  223. if windows:
  224. if windows.state != 1:
  225. return None
  226. i_n += 1
  227. image_index += 1
  228. original_image_path = "{}/原始图/{}{}".format(folder_path, image_dict["file_name"], image_dict["e"])
  229. file_name = image_dict["file_name"]
  230. print("正在处理,货号:{}".format(folder_path))
  231. # self.show_progress_detail("正在处理,货号:{}".format(file_name))
  232. # 该文件在800images下没有时,则进行生成新的抠图
  233. # 检查是否存在已抠图文件,如没有再去抠图
  234. original_move_bg_image_path = "{}/原始图_已抠图/{}{}".format(folder_path, image_dict["file_name"], ".png")
  235. # 此处判断鞋子是否为左右脚
  236. if image_index == 1:
  237. is_image_deal_mode = 0
  238. if OnePicDeal().check_shoe_is_right(image_path=original_move_bg_image_path):
  239. is_image_deal_mode = 1 # 1表示要镜像,0表示不做镜像
  240. """进行800image 生成"""
  241. generate_pic = GeneratePic()
  242. out_pci_mode = "." + settings.getSysConfigs(
  243. "basic_configs", "image_out_format", "png"
  244. )
  245. if out_pci_mode == ".jpg":
  246. out_path = "{}/800x800/{}{}".format(folder_path, file_name, ".jpg")
  247. else:
  248. out_path = "{}/800x800/{}{}".format(folder_path, file_name, ".png")
  249. out_process_path_1 = "{}/阴影图处理/{}_{}_阴影{}".format(folder_path, file_name,
  250. image_dict["image_view"], ".png")
  251. out_process_path_2 = "{}/阴影图处理/{}_{}_抠图{}".format(folder_path, file_name,
  252. image_dict["image_view"], ".png")
  253. resize_mode = 1
  254. max_box = None
  255. print("------------1", image_dict["image_view"], resize_image_view)
  256. if image_dict["image_view"] == resize_image_view:
  257. print(image_dict["image_view"], resize_image_view)
  258. resize_mode = 2
  259. if settings.Mode == "皮具":
  260. max_box = (1000, 1200)
  261. if resize_mode == 2:
  262. print(
  263. is_image_deal_mode,
  264. resize_mode,
  265. settings.OUT_PIC_SIZE,
  266. True if i_n == 1 else False,
  267. max_box
  268. )
  269. if not generate_pic.run(image_path=original_image_path,
  270. cut_image_path=original_move_bg_image_path,
  271. out_path=out_path,
  272. image_deal_mode=is_image_deal_mode,
  273. resize_mode=resize_mode,
  274. out_pic_size=settings.OUT_PIC_SIZE,
  275. is_logo=True if i_n == 1 else False,
  276. out_process_path_1=out_process_path_1,
  277. out_process_path_2=out_process_path_2,
  278. max_box=max_box,
  279. logo_path=logo_path,
  280. ):
  281. is_successful = False
  282. if is_successful:
  283. return True
  284. else:
  285. return False
  286. def to_upload_pic(self, file_path, is_resize=True):
  287. file_name = os.path.split(file_path)[1]
  288. e = os.path.splitext(file_name)[1][1:]
  289. im = Picture(file_path)
  290. if im.x > 500:
  291. im.resize(width=500)
  292. _ = {"jpg": "JPEG",
  293. "JPG": "JPEG",
  294. "JPEG": "JPEG",
  295. "jpeg": "JPEG",
  296. "png": "PNG",
  297. "PNG": "PNG", }
  298. e = _[e]
  299. image_io = im.save_to_io(e)
  300. goods_data = {"file_path": os.path.split(file_path)[1],
  301. "image_io": image_io,
  302. "e": e
  303. }
  304. url = self.data_mode_image_cut.get_online_data.upload_pic(goods_data=goods_data)
  305. return url
  306. def get_images(self, path):
  307. image_list = [] # 过滤非图片数据
  308. for _file in self.list_dir(path):
  309. file_name, e = os.path.splitext(_file)
  310. if e in _Type:
  311. image_list.append({"file_path": "{}/{}".format(path, _file),
  312. "file_name": file_name,
  313. "e": e})
  314. return image_list
  315. def crate_all_folders(self, root_path):
  316. path_list = ["800x800", "原始图_已抠图", "阴影图处理"]
  317. for i in path_list:
  318. path = "{}/{}".format(root_path, i)
  319. self.check_path(path)
  320. def run_cutout_image(self, all_goods_art_no_folder_data, callback_func=None, cutout_mode=1, windows=None):
  321. """
  322. 处理所有的抠图
  323. """
  324. callback_func('开始处理抠图~')
  325. error_goods_art_no_folder = []
  326. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  327. if goods_art_no_folder_data["label"] != "待处理":
  328. continue
  329. folder_path = goods_art_no_folder_data["folder_path"]
  330. self.crate_all_folders(folder_path)
  331. # 检查是否存在已抠图文件,如没有再去抠图
  332. images = [x for x in self.list_dir("{}/原始图".format(folder_path))]
  333. cutImageList = []
  334. for pic_file_name in images:
  335. if windows:
  336. if windows.state != 1:
  337. break
  338. # 根据名称判断,没有抠图过的,进行统计
  339. file_name, suffix = os.path.splitext(pic_file_name)
  340. if suffix in _Type:
  341. original_image_path = "{}/原始图/{}".format(folder_path, pic_file_name)
  342. original_move_bg_image_path = "{}/原始图_已抠图/{}{}".format(folder_path, file_name, ".png")
  343. if not os.path.exists(original_move_bg_image_path):
  344. # 没有抠图文件,进行抠图生成
  345. callback_func("正在抠图 货号:{}".format(file_name))
  346. if cutout_mode == '2':
  347. cutImageList.append({
  348. "file_name": file_name, # 文件名
  349. "file_e": suffix, # 后缀,.jpg
  350. "file_path": original_image_path, # 完整路径
  351. "file": '{}{}'.format(file_name, suffix), # 图片文件名,带后缀
  352. "need_cutout": True, # 必须,需要抠图
  353. "out_path": original_move_bg_image_path
  354. })
  355. else:
  356. remove_pic_ins = RemoveBgALi()
  357. if settings.IS_TEST:
  358. im = remove_pic_ins.get_image_cut(file_path=original_image_path,
  359. out_file_path=original_move_bg_image_path)
  360. else:
  361. try:
  362. im = remove_pic_ins.get_image_cut(file_path=original_image_path,
  363. out_file_path=original_move_bg_image_path)
  364. except FunctionTimedOut as f:
  365. callback_func("货号图{} 抠图处理超时~".format(file_name))
  366. im = None
  367. except BaseException as e:
  368. callback_func("货号图{} 抠图处理失败,原因{}".format(file_name, e))
  369. im = None
  370. if not im:
  371. callback_func("货号图{} 抠图处理失败~".format(file_name))
  372. continue
  373. else:
  374. callback_func("货号图{} 抠图完成~".format(file_name))
  375. if cutout_mode == '2':
  376. dealCutout = DealCutout(windows=None)
  377. dealCutout.need_cutout_images = cutImageList
  378. dealCutout.run()
  379. while True:
  380. time.sleep(1)
  381. if windows:
  382. if windows.state != 1:
  383. break
  384. if dealCutout.state == 3:
  385. if len(dealCutout.resultData) != len(cutImageList):
  386. error_goods_art_no_folder.append(folder_path)
  387. break
  388. if error_goods_art_no_folder:
  389. print("以下货号抠图失败~\n {}".format(error_goods_art_no_folder))
  390. callback_func("以下货号抠图失败~\n {}".format(error_goods_art_no_folder))
  391. else:
  392. callback_func("完成抠图处理")
  393. def checkCutoutImage(self, image_dir: str, todo_goods_art_no_folder_name_list=None):
  394. """
  395. 进行图片检查,不合规的直接提示
  396. """
  397. error_goods_art_no_folder = []
  398. self.check_path("{}/软件-处理失败".format(image_dir))
  399. for goods_art_no_folder in self.list_dir(image_dir):
  400. # 指定内容检查
  401. if todo_goods_art_no_folder_name_list is not None:
  402. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  403. continue
  404. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  405. continue
  406. if "软件" in goods_art_no_folder:
  407. continue
  408. if "无法" in goods_art_no_folder:
  409. continue
  410. if "原始图" not in self.list_dir("{}/{}".format(image_dir, goods_art_no_folder)):
  411. error_goods_art_no_folder.append(goods_art_no_folder)
  412. continue
  413. self.check_path("{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder))
  414. self.check_path("{}/{}/800x800".format(image_dir, goods_art_no_folder))
  415. self.check_path("{}/{}/阴影图处理".format(image_dir, goods_art_no_folder))
  416. if error_goods_art_no_folder:
  417. self.move_folders(path_list=["{}/{}".format(self.image_dir, x) for x in error_goods_art_no_folder],
  418. target_folder="{}/软件-处理失败".format(self.image_dir))
  419. return False
  420. def move_folders(self, path_list, target_folder):
  421. for source_folder in path_list:
  422. shutil.move(source_folder, target_folder)
  423. def rename_folder_for_hqt(self, all_goods_art_no_folder_data):
  424. """
  425. 步骤:
  426. 规整红蜻蜓的文件名
  427. 重新按文件名进行命名
  428. """
  429. goods_art_no_list = []
  430. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  431. if "@" not in goods_art_no_folder_data["folder_name"]:
  432. goods_art_no_folder_data["label"] = "待处理"
  433. goods_art_no_list.append(goods_art_no_folder_data["folder_name"])
  434. else:
  435. goods_art_no_folder_data["label"] = "不处理"
  436. if goods_art_no_list:
  437. # goods_art_no_dict 文件夹与货号的字典
  438. goods_art_no_dict = self.dataModeMatchPhoto.get_data_from_hqt_with_goods_art_no(
  439. goods_art_no_list=goods_art_no_list)
  440. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  441. if goods_art_no_folder_data["label"] != "待处理":
  442. continue
  443. goods_art_no_folder = goods_art_no_folder_data["folder_name"]
  444. if goods_art_no_folder in goods_art_no_dict:
  445. print(goods_art_no_folder)
  446. old_folder_path = goods_art_no_folder_data["folder_path"]
  447. new_folder_name = "{}@NUM{}".format(goods_art_no_folder,
  448. goods_art_no_dict[goods_art_no_folder]["编号"])
  449. new_folder_path = "{}/{}".format(goods_art_no_folder_data["root_path"], new_folder_name)
  450. try:
  451. os.rename(old_folder_path, new_folder_path)
  452. goods_art_no_folder_data["folder_path"] = new_folder_path
  453. goods_art_no_folder_data["folder_name"] = new_folder_path
  454. goods_art_no_folder_data["label"] = "待处理"
  455. except BaseException as e:
  456. goods_art_no_folder_data["label"] = "不处理"
  457. print("521 文件夹重名命失败:{}".format(e))
  458. # 重新规整修改图片名称
  459. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  460. if goods_art_no_folder_data["label"] != "待处理":
  461. continue
  462. goods_art_no_folder = goods_art_no_folder_data["folder_name"]
  463. _img_all = self.list_dir("{}/原始图".format(goods_art_no_folder_data["folder_path"]))
  464. index = 0
  465. for _file in _img_all:
  466. file_name, suffix = os.path.splitext(_file)
  467. if suffix in _Type:
  468. index += 1
  469. folder_path = goods_art_no_folder_data["folder_path"]
  470. new_file_name = "{}({}){}".format(goods_art_no_folder, index, suffix)
  471. new_path = "{}/原始图/{}".format(folder_path, new_file_name)
  472. old_path = "{}/原始图/{}".format(folder_path, _file)
  473. crop_new_path = "{}/原始图_已抠图/{}".format(folder_path, "{}({}).png".format(goods_art_no_folder, index))
  474. crop_old_path = "{}/原始图_已抠图/{}".format(folder_path, "{}.png".format(file_name))
  475. if old_path != new_path:
  476. # 存在货号命名错误的,进行修正
  477. try:
  478. if os.path.exists(old_path):
  479. os.rename(old_path, new_path)
  480. if os.path.exists(crop_old_path):
  481. os.rename(crop_old_path, crop_new_path)
  482. except BaseException as e:
  483. goods_art_no_folder_data["label"] = "不处理"
  484. print("550 文件夹重名命失败:{}".format(e))
  485. def cutImagePiju(self, image_dir: str, image_order='', is_check_number=True, is_filter=True, resize_image_view='后跟',
  486. callback_func=None, event=None, todo_goods_art_no_folder_name_list=None):
  487. """
  488. 1、遍历文件夹,基于生成的结果图看哪些需要进行抠图等处理
  489. 2、压缩并上传平台获取抠图
  490. 3、抠图处理成白底图
  491. 4、做成800*800/200*200
  492. :return:
  493. """
  494. logo_path = ""
  495. res = self.getImageOrder(image_order=image_order, resize_image_view=resize_image_view)
  496. if res['code'] != 0:
  497. callback_func(res['msg'])
  498. return {'code': 1, 'msg': res['msg']}
  499. imageOrderList = res['imageOrderList']
  500. """扫描文档,检查有哪些需要进行抠图等处理"""
  501. self.lock = Lock()
  502. to_do_images_total = 0
  503. error_goods_art_no_folder = []
  504. for goods_art_no_folder in self.list_dir(image_dir):
  505. # 指定内容检查
  506. if todo_goods_art_no_folder_name_list is not None:
  507. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  508. continue
  509. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  510. continue
  511. self.check_path("{}/{}/原始图".format(image_dir, goods_art_no_folder))
  512. self.check_path("{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder))
  513. self.check_path("{}/{}/800x800".format(image_dir, goods_art_no_folder))
  514. self.check_path("{}/{}/阴影图处理".format(image_dir, goods_art_no_folder))
  515. # 遍历原始图片文件夹
  516. all_original_images = [x for x in
  517. self.list_dir(
  518. "{}/{}/原始图".format(image_dir, goods_art_no_folder))]
  519. # 检查已抠图文件夹
  520. all_moved_images = [os.path.splitext(x)[0] for x in
  521. self.list_dir(
  522. "{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder))]
  523. all_800images = [os.path.splitext(x)[0] for x in
  524. self.list_dir(
  525. "{}/{}/800x800".format(image_dir, goods_art_no_folder))]
  526. if is_check_number and len(imageOrderList) != len(all_original_images):
  527. callback_func("{} 文件夹下图片数量与订单数量不一致,请检查!".format(goods_art_no_folder))
  528. return {'code': 1, 'msg': '{} 文件夹下图片数量与订单数量不一致,请检查!'.format(goods_art_no_folder)}
  529. all_800images = []
  530. image_num = 0
  531. for pic_file_name in all_original_images:
  532. if pic_file_name not in all_800images:
  533. # 根据名称判断,没有抠图过的,进行统计
  534. _, e = os.path.splitext(pic_file_name)
  535. print(e)
  536. if e in _Type:
  537. image_num += 1
  538. print("----------》", goods_art_no_folder, pic_file_name)
  539. to_do_images_total += 1
  540. # if image_num > 5:
  541. # error_goods_art_no_folder.append(goods_art_no_folder)
  542. # if error_goods_art_no_folder:
  543. # self.show_progress_detail("以下货号图片张数超过5张~\n {}".format(error_goods_art_no_folder))
  544. # self.set_state(state_value=2)
  545. # return
  546. if to_do_images_total > 0:
  547. # self.progress_sign.emit({"type": "处理图片 抠图、加工等", "progress_bar_value": 0})
  548. for goods_art_no_folder in self.list_dir(image_dir):
  549. # 指定内容检查
  550. if todo_goods_art_no_folder_name_list is not None:
  551. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  552. continue
  553. if not os.path.isdir('{}/{}'.format(image_dir, goods_art_no_folder)):
  554. continue
  555. self.run_one_folder_to_deal(goods_art_no_folder=goods_art_no_folder,
  556. image_dir=image_dir,
  557. image_order=image_order,
  558. resize_image_view=resize_image_view,
  559. callback_func=callback_func,
  560. logo_path=logo_path,
  561. )
  562. else:
  563. # self.show_progress_detail("没有需要处理的图片~")
  564. callback_func('没有需要处理的图片~')
  565. # self.set_state(state_value=2)
  566. return {'code': 0, 'msg': 'ok'}
  567. def run_one_folder_to_deal(self, goods_art_no_folder, image_dir, image_order, resize_image_view,
  568. callback_func=None, logo_path=""):
  569. _img_all = self.list_dir("{}/{}/原始图".format(image_dir, goods_art_no_folder))
  570. all_original_images = [] # 过滤非图片数据
  571. index = 0
  572. for _file in _img_all:
  573. file_name, e = os.path.splitext(_file)
  574. if e in _Type:
  575. index += 1
  576. new_file_name = "{}({}){}".format(goods_art_no_folder, index, e)
  577. new_path = "{}/{}/原始图/{}".format(image_dir, goods_art_no_folder, new_file_name)
  578. old_path = "{}/{}/原始图/{}".format(image_dir, goods_art_no_folder, _file)
  579. if old_path != new_path:
  580. # 存在货号命名错误的,进行修正
  581. try:
  582. os.rename(old_path, new_path)
  583. except:
  584. pass
  585. all_original_images.append(new_file_name)
  586. if os.path.exists("{}/{}/原始图/镜像.txt".format(image_dir, goods_art_no_folder)):
  587. file_mirror_mark = True
  588. else:
  589. file_mirror_mark = None
  590. # if goods_art_no_folder == "AC51016112":
  591. # print(file_mirror_mark)
  592. # raise 111
  593. all_moved_images = [os.path.splitext(x)[0] for x in
  594. self.list_dir("{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder))]
  595. all_800images = [os.path.splitext(x)[0] for x in
  596. self.list_dir(
  597. "{}/{}/800x800".format(image_dir, goods_art_no_folder))]
  598. all_800images = []
  599. # 检查哪些图片没有做过抠图处理
  600. i_n = 0
  601. _name_list = ["视角{}".format(x) for x in range(1, len(all_original_images) + 1)]
  602. # if goods_art_no_folder == "AC51028001":
  603. # _name_list = ["正视", "45度", "侧视", "后视", "底视", "其他1", "其他2", "其他3"]
  604. image_index = 0 # 图片顺序
  605. is_image_deal_mode = 0
  606. max_box = None
  607. for file in all_original_images:
  608. i_n += 1
  609. image_index += 1
  610. original_image_path = "{}/{}/原始图/{}".format(image_dir, goods_art_no_folder, file)
  611. file_name = os.path.splitext(file)[0]
  612. """
  613. 当第三张就是为后跟
  614. """
  615. if file_name not in all_800images: # 所有都重新生成
  616. # if goods_art_no_folder != "AC51016112":
  617. # continue
  618. goods_art_no_folder_path = "{}/{}".format(image_dir, goods_art_no_folder)
  619. print("正在处理,货号:{}".format(goods_art_no_folder_path))
  620. # self.show_progress_detail("正在处理,货号:{}".format(file_name))
  621. callback_func("正在处理,货号:{}".format(file_name))
  622. # 该文件在800images下没有时,则进行生成新的抠图
  623. # 检查是否存在已抠图文件,如没有再去抠图
  624. original_move_bg_image_path = "{}/原始图_已抠图/{}{}".format(goods_art_no_folder_path, file_name,
  625. ".png")
  626. image_deal_mode = 0 # 默认图片不做镜像处理
  627. if not os.path.exists(original_move_bg_image_path):
  628. # 没有抠图文件,进行抠图生成
  629. # self.show_progress_detail("正在抠图 货号:{}".format(file_name))
  630. callback_func("正在抠图 货号:{}".format(file_name))
  631. remove_pic_ins = RemoveBgALi()
  632. im = remove_pic_ins.get_image_cut(file_path=original_image_path,
  633. out_file_path=original_move_bg_image_path)
  634. if not im:
  635. # self.show_progress_detail("货号图{} 抠图处理失败~".format(file_name))
  636. callback_func("货号图{} 抠图处理失败~".format(file_name))
  637. continue
  638. if image_index == 1:
  639. is_image_deal_mode = 0
  640. if settings.Mode == "鞋类":
  641. goods_class = "鞋"
  642. # 如果图片已存在,则需要通过加载图片判断是否为左右脚
  643. if OnePicDeal().check_shoe_is_right(image_path=original_move_bg_image_path):
  644. image_deal_mode = 1 # 1表示要镜像,0表示不做镜像
  645. is_image_deal_mode = 1
  646. if settings.Mode == "皮具":
  647. # 图片对应的商品类型
  648. # goods_class = self.get_goods_class(goods_art_no_folder, original_image_path)
  649. max_box = (1000, 1200)
  650. # _ = {"AC51028001": "女包",
  651. # "AC51028002": "男包",
  652. # "AC51028003": "皮带",
  653. # "AC51028004": "女包"}
  654. # if goods_class in _:
  655. # goods_class = _[goods_class]
  656. # else:
  657. # goods_class = "女包"
  658. #
  659. # _ = {"女包": (1000, 1200),
  660. # "男包": (1000, 1200),
  661. # "皮带": (1000, 1000), }
  662. # max_box = _[goods_class]
  663. # 获取图片信息非必要程序,用于处理图片模式
  664. date_time_original = self.get_date_time_original(original_image_path) # 获取照片拍照时间
  665. if date_time_original:
  666. # 基于照片的时间,与数据库匹配goods_art_no
  667. self.lock.acquire()
  668. _data = self.dataModeMatchPhoto.get_goods_art_no(date_time_original)
  669. self.lock.release()
  670. if _data:
  671. # 能匹配上数据库
  672. goods_art_no, _image_index, _image_deal_mode = _data
  673. if _image_index < 10:
  674. image_index = _image_index
  675. if _image_deal_mode == 1:
  676. image_deal_mode = 1
  677. # print(goods_art_no, image_index, image_deal_mode)
  678. if file_mirror_mark:
  679. image_deal_mode = 1
  680. """进行800image 生成"""
  681. generate_pic = GeneratePic()
  682. out_pci_mode = "." + settings.getSysConfigs(
  683. "basic_configs", "image_out_format", "png"
  684. )
  685. if out_pci_mode == ".jpg":
  686. out_path = "{}/800x800/{}{}".format(goods_art_no_folder_path, file_name, ".jpg")
  687. else:
  688. out_path = "{}/800x800/{}{}".format(goods_art_no_folder_path, file_name, ".png")
  689. out_process_path_1 = "{}/阴影图处理/{}_{}_阴影{}".format(goods_art_no_folder_path, file_name,
  690. _name_list[i_n - 1], ".png")
  691. out_process_path_2 = "{}/阴影图处理/{}_{}_抠图{}".format(goods_art_no_folder_path, file_name,
  692. _name_list[i_n - 1], ".png")
  693. print("image_index", image_index)
  694. image_index = 99
  695. if generate_pic.run(image_path=original_image_path,
  696. cut_image_path=original_move_bg_image_path,
  697. out_path=out_path,
  698. image_deal_mode=is_image_deal_mode,
  699. image_index=image_index,
  700. out_pic_size=settings.OUT_PIC_SIZE,
  701. is_logo=True if i_n == 1 else False,
  702. out_process_path_1=out_process_path_1,
  703. out_process_path_2=out_process_path_2,
  704. max_box=max_box,
  705. logo_path=logo_path,
  706. ):
  707. # self.show_progress_detail("货号图{} _{} 已完成800*800图片制作~".format(image_index, file_name))
  708. callback_func("货号图{} _{} 已完成800*800图片制作~".format(image_index, file_name))
  709. else:
  710. # self.show_progress_detail("货号图{} _{} 图片生成处理失败~".format(image_index, file_name))
  711. callback_func("货号图{} _{} 图片生成处理失败~".format(image_index, file_name))
  712. # 完成处理的图片进度
  713. self.lock.acquire()
  714. # self.set_progress()
  715. self.lock.release()
  716. def dealMoveImage(self, image_dir: str, callback_func=None) -> dict:
  717. if not self.check_path(image_dir=image_dir + "/历史"):
  718. if callback_func:
  719. callback_func('文件夹创建失败')
  720. return {'code': 1, 'msg': '文件夹创建失败', 'data': {}}
  721. # 遍历目标文件夹,获取有拍摄信息的图片,并按拍摄时间排序
  722. files = self.list_dir(image_dir)
  723. original_photo_list = [] # 原始图片列表
  724. for file in files:
  725. # -----图片清洗
  726. file_path = image_dir + "/" + file
  727. if os.path.isdir(file_path): # 忽略文件夹
  728. continue
  729. file_name, suffix = os.path.splitext(file)
  730. if suffix not in _Type: # 非图片进行移除
  731. shutil.move(file_path, image_dir + "/历史/" + file)
  732. continue
  733. date_time_original = self.get_date_time_original(file_path) # 获取照片拍照时间
  734. if date_time_original:
  735. # 基于照片的时间,与数据库匹配goods_art_no
  736. _data = self.dataModeMatchPhoto.get_goods_art_no(date_time_original)
  737. if _data:
  738. # 能匹配上数据库
  739. goods_art_no, image_index, image_deal_mode = _data
  740. print("与数据库匹配goods_art_no", file_name, date_time_original, goods_art_no)
  741. original_photo_list.append({"file_path": file_path,
  742. "file": file,
  743. "date_time_original": date_time_original,
  744. "goods_art_no": goods_art_no,
  745. "image_index": image_index,
  746. "real_goods_art_no": "",
  747. "real_goods_number": "",
  748. })
  749. else:
  750. # 匹配不上报错
  751. # self.show_progress_detail("图片:{} 无法对应货号,不做处理".format(file))
  752. if callback_func:
  753. callback_func("图片:{} 无对应货号".format(file))
  754. # shutil.move(photo_dict["file_path"], self.image_dir + "/历史/" + photo_dict["file"])
  755. continue
  756. else:
  757. shutil.move(file_path, image_dir + "/历史/" + file)
  758. if not original_photo_list:
  759. # self.show_progress_detail("没有任何匹配的图片~")
  760. if callback_func:
  761. callback_func('没有任何匹配的图片')
  762. # self.set_state(state_value=2)
  763. return {"code": 1, "msg": "没有任何匹配的图片", 'data': {}}
  764. if settings.PROJECT == "红蜻蜓":
  765. # 批量请求货号图信息
  766. goods_art_no_list = [x["goods_art_no"] for x in original_photo_list]
  767. goods_art_no_list = list(set(goods_art_no_list))
  768. goods_art_no_list = [x for x in goods_art_no_list if "NUM" not in x]
  769. if goods_art_no_list:
  770. goods_art_no_dict = self.dataModeMatchPhoto.get_data_from_hqt_with_goods_art_no(
  771. goods_art_no_list=goods_art_no_list)
  772. for i in original_photo_list:
  773. if i["goods_art_no"] in goods_art_no_dict:
  774. i["real_goods_art_no"] = i["goods_art_no"]
  775. i["real_goods_number"] = "NUM{}".format(goods_art_no_dict[i["goods_art_no"]]["编号"])
  776. # 批量请求编号对应信息
  777. goods_number_list = [x["goods_art_no"] for x in original_photo_list]
  778. goods_number_list = list(set(goods_number_list))
  779. goods_number_list = [x for x in goods_number_list if "NUM" in x]
  780. if goods_number_list:
  781. goods_number_dict = self.dataModeMatchPhoto.get_data_from_hqt(goods_number_list=goods_number_list)
  782. for i in original_photo_list:
  783. if i["goods_art_no"] in goods_number_dict:
  784. i["real_goods_number"] = i["goods_art_no"]
  785. i["real_goods_art_no"] = goods_number_dict[i["goods_art_no"]]["商品货号"]
  786. # 排序需要基于拍照的文件序号进行处理
  787. original_photo_list.sort(
  788. key=lambda x: "{}-{}-{}".format(x["goods_art_no"], x["image_index"], x["file"]))
  789. print(original_photo_list)
  790. # 对有拍摄信息的图片进行数据库比对,如有比对上,则移动至货号文件夹,否则移入历史文件夹
  791. total_num = len(original_photo_list)
  792. # 当天日期作为文件夹
  793. seconds = time.time()
  794. output_path = "output/{f_name}".format(f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
  795. # 遍历每个匹配好的数据进行处理
  796. n = 0
  797. for photo_dict in original_photo_list:
  798. n += 1
  799. # 进度条
  800. goods_art_no = photo_dict["goods_art_no"]
  801. original_image_path = photo_dict["file_path"]
  802. # 输出货号文件夹
  803. if photo_dict["real_goods_art_no"]:
  804. goods_art_no = "{}@{}".format(photo_dict["real_goods_art_no"], photo_dict["real_goods_number"])
  805. goods_art_no_path = "{output_path}/{goods_art_no}".format(output_path=output_path,
  806. goods_art_no=goods_art_no)
  807. # 创建货号下的一系列文件夹
  808. self.create_folder(goods_art_no_path)
  809. # 重命名并进行移动
  810. self.move_images(goods_art_no, goods_art_no_path, original_image_path) # 货号、货号文件路径、原始图路径
  811. # self.progress_sign.emit({"type": "移动原始图片", "progress_bar_value": int(n / total_num * 100)})
  812. # self.show_progress_detail("货号{} 相关文件夹创建完成,已移动原图~".format(goods_art_no))
  813. if callback_func:
  814. callback_func("货号{} 相关文件夹创建完成,已移动原图~".format(goods_art_no))
  815. if n != 0:
  816. # if settings.MattingPics:
  817. # # 检查所有未处理的货号文件夹,查看是否有完成图片加工处理
  818. # self.deal_images()
  819. # 自动生成一个货号表
  820. print("output_path", output_path)
  821. GenerateGoodsArtNoTable.deal(output_path)
  822. # 完成处理
  823. # self.set_state(state_value=2)
  824. return {'code': 0, 'msg': '处理完成', 'target_path': output_path, 'data': {}}
  825. def check_path(self, image_dir: str):
  826. if not os.path.exists(image_dir):
  827. os.mkdir(image_dir)
  828. return True
  829. def get_date_time_original(self, file_path):
  830. with open(file_path, 'rb') as file_data:
  831. tags = exifread.process_file(file_data)
  832. if "EXIF DateTimeOriginal" in tags:
  833. return str(tags["EXIF DateTimeOriginal"])
  834. else:
  835. return False
  836. def create_folder(self, path):
  837. def check_folder(__path):
  838. if not os.path.exists(__path):
  839. os.makedirs(__path)
  840. return False
  841. return True
  842. # 文件夹不存在,创建货号子集文件夹
  843. if not check_folder(path):
  844. for name in ["原始图", "原始图_已抠图", "800x800", "200images"]:
  845. other_path = path + "/" + name
  846. check_folder(other_path)
  847. def move_images(self, goods_art_no, goods_art_no_path, old_image_path):
  848. """
  849. 步骤:
  850. 1、移动到原始图
  851. Args:
  852. goods_art_no:
  853. goods_art_no_path:
  854. old_image_path:
  855. Returns:
  856. """
  857. # 移动到原始图
  858. file = os.path.split(old_image_path)[1]
  859. # 扩展名
  860. e = os.path.splitext(file)[1]
  861. # 获取图片序列
  862. self.goods_images_count_dict[goods_art_no] += 1
  863. # A9999(1).jpg
  864. new_file_name = "{}({})".format(goods_art_no, self.goods_images_count_dict[goods_art_no])
  865. original_image_path = "{}/原始图/{}{}".format(goods_art_no_path, new_file_name, e)
  866. # 移动图片
  867. shutil.move(old_image_path, original_image_path)
  868. def pixianRemoveImageBg(self, file_path: str, out_file_path: str, callbackek_func=None):
  869. url = self.dataModeMatchPhoto.get_online_data.uploadImage(local_path=file_path)
  870. remonveUrl = settings.AIGC_DOMAIN + '/api/ai_image/main/remove_background'
  871. param = {'base_image': url}
  872. post_headers = {"Authorization": settings.Authorization,
  873. "Content-Length": "",
  874. "Content-Type": "application/json",
  875. "Accept": "application/json"}
  876. result = requests.post(remonveUrl, data=json.dumps(param), headers=post_headers).json()
  877. print(result)
  878. if "code" in result and result['code'] == 0:
  879. response = requests.get(result['data']['image'][0])
  880. with open(out_file_path, 'wb') as file:
  881. file.write(response.content)
  882. return result['data']['image'][0]
  883. else:
  884. callbackek_func("精细化抠图处理失败 {}".format(result['message']))
  885. return ''
  886. def list_dir(self, path):
  887. listdir = os.listdir(path)
  888. return natsorted(listdir, alg=ns.PATH)