base_deal.py 50 KB

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