base_deal.py 49 KB

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