base_deal.py 50 KB

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