base_deal.py 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603
  1. import json
  2. from .module_generate_goods_art_no_table import GenerateGoodsArtNoTable
  3. from func_timeout import FunctionTimedOut
  4. from .grenerate_main_image_test import GeneratePic
  5. from threading import Lock
  6. from middleware import UnicornException
  7. import settings
  8. from collections import defaultdict
  9. from .remove_bg_ali import RemoveBgALi, Picture, RemoveUltraBackground
  10. from .deal_cutout import DealCutout
  11. import time
  12. from .image_pic_deal import OnePicDeal
  13. from natsort import natsorted, ns
  14. import os
  15. import shutil
  16. import exifread
  17. import datetime
  18. from databases import DeviceConfig, SqlQuery, CRUD
  19. from model.photo_record import PhotoRecord
  20. import requests
  21. import copy, asyncio
  22. from settings import sendSocketMessage
  23. from utils.common import message_queue
  24. from logger import logger
  25. from .online_request.ding_robot import sendDingMsg
  26. def sendAsyncMessage(msg="", goods_arts=[], status="", progress={}):
  27. """异步发送消息"""
  28. data = {
  29. "code": 0,
  30. "msg": msg,
  31. "status": 2,
  32. "data": {
  33. "status": status,
  34. "goods_art_nos": goods_arts,
  35. },
  36. "progress": {
  37. "msg_type": "segment_progress",
  38. "name": "抠图",
  39. "goods_art_no": progress.get("goods_art_no", ""),
  40. "status": progress.get("status"),
  41. "current": progress.get("current", 0),
  42. "total": progress.get("total", 0),
  43. "error": progress.get("error", 0)
  44. },
  45. "msg_type": "segment_progress",
  46. }
  47. message_queue.put_nowait(data)
  48. """
  49. 照片自动货号匹配 将图片放置在指定文件夹下,并自动对应不同的货号进行整理
  50. """
  51. _Type = [".png", ".PNG", ".jpg", ".JPG", ".gif", ".GIF", ".jpge", ".JPGE"]
  52. class BaseDealImage(object):
  53. def __init__(self, image_dir=None, token=None):
  54. self.token = token
  55. self.goods_images_count_dict = defaultdict(int)
  56. # 数据模型
  57. # self.data_mode_auto_deal_pics = DataModeAutoDealPics()
  58. self.image_dir = image_dir
  59. pass
  60. def run_main(
  61. self,
  62. all_goods_art_no_folder_data,
  63. callback_func=None,
  64. cutout_mode=None,
  65. resize_image_view=None,
  66. windows=None,
  67. logo_path=None,
  68. image_order_list=None,
  69. ):
  70. """
  71. 执行主流程处理
  72. Returns:
  73. dict: {
  74. 'success': bool, # 是否全部成功
  75. 'successful_folders': list, # 成功的货号列表
  76. 'failed_folders': list, # 失败的货号列表
  77. 'successful_num': int, # 成功数量
  78. 'error_num': int # 失败数量
  79. }
  80. """
  81. from logger import logger
  82. # 对所有缺失已抠图的进行抠图处理
  83. self.run_cutout_image(
  84. all_goods_art_no_folder_data=all_goods_art_no_folder_data,
  85. callback_func=callback_func,
  86. cutout_mode=cutout_mode,
  87. windows=windows,
  88. )
  89. error_num = 0
  90. successful_num = 0
  91. successful_folders = []
  92. failed_folders = []
  93. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  94. if goods_art_no_folder_data["label"] != "待处理":
  95. continue
  96. if windows:
  97. if windows.state != 1:
  98. break
  99. folder_name = goods_art_no_folder_data["folder_name"]
  100. callback_func("开始处理文件夹========== {} ".format(folder_name))
  101. flag = None
  102. try:
  103. flag = self.shoes_run_one_folder_to_deal(
  104. goods_art_no_folder_data=goods_art_no_folder_data,
  105. resize_image_view=resize_image_view,
  106. logo_path=logo_path,
  107. image_order_list=image_order_list,
  108. callback_func=callback_func,
  109. windows=windows,
  110. )
  111. except BaseException as e:
  112. error_num += 1
  113. import traceback
  114. traceback.print_exc()
  115. logger.error(f"货号 {folder_name} 处理异常: {e}")
  116. callback_func(
  117. "货号:{} 图片生成处理异常,原因:{}".format(folder_name, e)
  118. )
  119. failed_folders.append(goods_art_no_folder_data)
  120. continue
  121. # 判断处理结果
  122. if flag is None:
  123. callback_func("货号:{} 数据异常".format(folder_name))
  124. error_num += 1
  125. failed_folders.append(goods_art_no_folder_data)
  126. else:
  127. if flag:
  128. successful_num += 1
  129. callback_func("货号:{} 图片生成处理成功".format(folder_name))
  130. successful_folders.append(goods_art_no_folder_data)
  131. else:
  132. error_num += 1
  133. callback_func("货号:{} 图片生成处理失败".format(folder_name))
  134. failed_folders.append(goods_art_no_folder_data)
  135. callback_func("处理成功:{}个,失败:{}个".format(successful_num, error_num))
  136. # 返回详细的处理结果
  137. result = {
  138. 'success': error_num == 0,
  139. 'successful_folders': successful_folders,
  140. 'failed_folders': failed_folders,
  141. 'successful_num': successful_num,
  142. 'error_num': error_num
  143. }
  144. logger.info(f"[主流程完成] 成功: {successful_num}, 失败: {error_num}")
  145. if failed_folders:
  146. logger.warning(f"[主流程完成] 失败货号列表: {[f['folder_name'] for f in failed_folders]}")
  147. return result
  148. def checkImageAmount(
  149. self, image_dir: str, amount: int, todo_goods_art_no_folder_name_list=None
  150. ) -> dict:
  151. result = {"code": 0, "msg": "", "data": {}}
  152. for goods_art_no_folder in self.list_dir(image_dir):
  153. # 指定内容检查
  154. if todo_goods_art_no_folder_name_list is not None:
  155. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  156. continue
  157. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  158. continue
  159. if "软件" in goods_art_no_folder:
  160. continue
  161. if "无法" in goods_art_no_folder:
  162. continue
  163. if "原始图" not in self.list_dir(
  164. "{}/{}".format(image_dir, goods_art_no_folder)
  165. ):
  166. result["data"][goods_art_no_folder] = "文件夹下,没有 原始图 文件夹\n"
  167. continue
  168. # 计算单个文件夹原图数量
  169. images = [
  170. x
  171. for x in self.list_dir(
  172. "{}/{}/原始图".format(image_dir, goods_art_no_folder)
  173. )
  174. ]
  175. image_num = 0
  176. for pic_file_name in images:
  177. _, e = os.path.splitext(pic_file_name)
  178. if e in _Type:
  179. image_num += 1
  180. # if self.number_pictures != 0:
  181. if image_num > amount:
  182. result["data"][goods_art_no_folder] = "货号图片大于{}张~\n".format(
  183. amount
  184. )
  185. if image_num < 2:
  186. result["data"][goods_art_no_folder] = "货号图片小于于2张~\n"
  187. if result["data"]:
  188. result["code"] = 1
  189. return result
  190. def check_folders_image_amount(
  191. self, all_goods_art_no_folder_data, image_order_list
  192. ):
  193. print("*****************check_folders_image_amount************************")
  194. amount = len(image_order_list)
  195. # print("图片数量检查===>", amount)
  196. message = ""
  197. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  198. if goods_art_no_folder_data["label"] != "待处理":
  199. continue
  200. folder_path = goods_art_no_folder_data["folder_path"]
  201. folder_name = goods_art_no_folder_data["folder_name"]
  202. images = [x for x in self.list_dir("{}/原始图".format(folder_path))]
  203. image_num = 0
  204. for pic_file_name in images:
  205. _, e = os.path.splitext(pic_file_name)
  206. if e in _Type:
  207. image_num += 1
  208. # print("图片数量判断===>", image_num)
  209. # if image_num > amount:
  210. # goods_art_no_folder_data["label"] = "错误"
  211. # message += '货号{}:图片大于{}张~\n'.format(folder_name, amount)
  212. # if image_num < 2:
  213. # message += '货号{}:图片小于于2张~\n'.format(folder_name)
  214. return all_goods_art_no_folder_data, message
  215. def check_one_folder_image_amount(self, folder_data, amount: int):
  216. print("*****************check_one_folder_image_amount************************")
  217. # 计算单个文件夹原图数量
  218. images = [
  219. x for x in self.list_dir("{}/原始图".format(folder_data["folder_path"]))
  220. ]
  221. image_num = 0
  222. for pic_file_name in images:
  223. _, e = os.path.splitext(pic_file_name)
  224. if e in _Type:
  225. image_num += 1
  226. if image_num > amount:
  227. return False, "货号{}:图片大于{}张~\n".format(
  228. folder_data["folder_name"], amount
  229. )
  230. if image_num < 2:
  231. return False, "货号{}:图片小于于2张~\n".format(folder_data["folder_name"])
  232. return True, ""
  233. # 指定的图片顺序
  234. def getImageOrder(self, image_order: str, resize_image_view: str):
  235. imageOrderList = (
  236. image_order.replace(",", ",").replace(" ", "").replace("图", "").split(",")
  237. )
  238. print("imageOrderList", imageOrderList)
  239. if len(set(imageOrderList)) != len(imageOrderList):
  240. return {"code": 1, "msg": "图片位置与顺序重复,请检查您的输入"}
  241. for val in imageOrderList:
  242. image_orders = [
  243. "俯视",
  244. "侧视",
  245. "后跟",
  246. "鞋底",
  247. "内里",
  248. "组合",
  249. "组合2",
  250. "组合3",
  251. "组合4",
  252. "组合5",
  253. "组合6",
  254. "组合7",
  255. "组合8",
  256. "组合9",
  257. "组合10",
  258. "组合11",
  259. "组合12",
  260. "组合13",
  261. "组合14",
  262. "组合15",
  263. "组合16",
  264. "组合17",
  265. "组合18",
  266. "组合19",
  267. "组合20",
  268. "组合21",
  269. "组合22",
  270. "组合23",
  271. "组合24",
  272. "组合25",
  273. "组合26",
  274. ]
  275. if val not in image_orders:
  276. print("val", val)
  277. image_orders_str = ','.join(map(str, image_orders))
  278. return {
  279. "code": 1,
  280. "msg": f"可选项为:{image_orders_str}",
  281. }
  282. if resize_image_view not in imageOrderList:
  283. return {"code": 1, "msg": "缩小的步骤必须是你填写的图片顺序中"}
  284. return {"code": 0, "msg": "sucess", "imageOrderList": imageOrderList}
  285. def shoes_run_one_folder_to_deal(
  286. self,
  287. goods_art_no_folder_data,
  288. image_order_list: list,
  289. resize_image_view: str,
  290. logo_path="",
  291. windows=None,
  292. callback_func=None,
  293. ):
  294. """
  295. 操作步骤:
  296. 1、查询每个图片的角度
  297. 2、
  298. """
  299. is_successful = True
  300. folder_path = goods_art_no_folder_data["folder_path"]
  301. folder_name = goods_art_no_folder_data["folder_name"]
  302. all_original_images = self.get_images("{}/原始图".format(folder_path))
  303. self.check_path("{}/800x800".format(folder_path))
  304. self.crate_all_folders(folder_path)
  305. print("all_original_images====>", all_original_images)
  306. if len(all_original_images) == 1:
  307. time.sleep(1.5)
  308. if not all_original_images:
  309. return None
  310. # _ = ["俯视", "侧视", "后跟", "鞋底", "内里"]
  311. for index, image_dict in enumerate(all_original_images):
  312. if index < len(image_order_list):
  313. image_dict["image_view"] = image_order_list[index]
  314. else:
  315. image_dict["image_view"] = "其他{}".format(
  316. len(image_order_list) - index + 1
  317. )
  318. # ====================处理所有图片的顺序====================
  319. # ["俯视", "侧视", "后跟", "鞋底", "内里"]
  320. _config = {
  321. "俯视": 1,
  322. "侧视": 2,
  323. "后跟": 3,
  324. "鞋底": 4,
  325. "内里": 5,
  326. }
  327. r = time.time()
  328. n = 0
  329. _index = 0
  330. # 检查是否有重复的角度
  331. _d_views = []
  332. f = True
  333. for image_dict in all_original_images:
  334. n += 1
  335. _index += 1
  336. image_dict["old_file_name"] = image_dict["file_name"]
  337. image_dict["random_name"] = "{}-{}".format(r, n)
  338. if image_dict["image_view"] in _config:
  339. if image_dict["image_view"] not in _d_views:
  340. _d_views.append(image_dict["image_view"])
  341. else:
  342. callback_func("货号:{} 处理失败".format(folder_name))
  343. # self.show_progress_detail("货号图{} 存在多个{} 角度~".format(goods_art_no_folder, image_dict["image_view"]))
  344. return None
  345. image_dict["index"] = _config[image_dict["image_view"]]
  346. else:
  347. image_dict["index"] = _index
  348. all_original_images.sort(key=lambda x: x["index"])
  349. # ==========直接进行处理=============
  350. i_n = 0
  351. image_index = 0 # 图片顺序
  352. is_image_deal_mode = 0
  353. # 删除目录再新建
  354. try:
  355. if os.path.exists("{}/阴影图处理".format(folder_path)):
  356. shutil.rmtree("{}/阴影图处理".format(folder_path), onerror=settings.handle_remove_readonly)
  357. except Exception as e:
  358. print('An exception occurred')
  359. logger.info(f"base deal 抠图前目录删除出现问题:{str(e)}")
  360. self.crate_all_folders(folder_path)
  361. print(
  362. "***************all_original_images*********************",
  363. all_original_images,
  364. )
  365. is_flip_800image = settings.getSysConfigs(
  366. "basic_configs", "is_flip_800image", 1
  367. )
  368. image_deal_mode = int(is_flip_800image)
  369. for image_dict in all_original_images:
  370. if windows:
  371. if windows.state != 1:
  372. return None
  373. i_n += 1
  374. image_index += 1
  375. original_image_path = "{}/原始图/{}{}".format(
  376. folder_path, image_dict["file_name"], image_dict["e"]
  377. )
  378. file_name = image_dict["file_name"]
  379. print("正在处理,货号:{}".format(folder_path))
  380. # self.show_progress_detail("正在处理,货号:{}".format(file_name))
  381. # 该文件在800images下没有时,则进行生成新的抠图
  382. # 检查是否存在已抠图文件,如没有再去抠图
  383. original_move_bg_image_path = "{}/原始图_已抠图/{}{}".format(
  384. folder_path, image_dict["file_name"], ".png"
  385. )
  386. print(
  387. f"*****************此处判断鞋子是否为左右脚====>{image_index}<======={is_image_deal_mode}=======>**********************"
  388. )
  389. # 此处判断鞋子是否为左右脚
  390. if image_deal_mode == 1:
  391. if image_index == 1:
  392. is_image_deal_mode = 0
  393. print("开始识别左右脚=========>")
  394. if OnePicDeal(self.token).check_shoe_is_right(
  395. image_path=original_move_bg_image_path
  396. ):
  397. is_image_deal_mode = 1 # 1表示要镜像,0表示不做镜像
  398. print(
  399. "*************************进行800image 生成********************************************"
  400. )
  401. """进行800image 生成"""
  402. generate_pic = GeneratePic()
  403. print(
  404. "*************************进行800image 结束====>>>>********************************************"
  405. )
  406. out_pci_mode = "." + settings.getSysConfigs(
  407. "basic_configs", "image_out_format", "png"
  408. )
  409. if out_pci_mode == ".jpg":
  410. out_path = "{}/800x800/{}{}".format(folder_path, file_name, ".jpg")
  411. elif out_pci_mode == ".png":
  412. out_path = "{}/800x800/{}{}".format(folder_path, file_name, ".png")
  413. else:
  414. out_path = "{}/800x800/{}{}".format(
  415. folder_path, file_name, out_pci_mode
  416. )
  417. out_process_path_1 = "{}/阴影图处理/{}_{}_阴影{}".format(
  418. folder_path, file_name, image_dict["image_view"], ".png"
  419. )
  420. out_process_path_2 = "{}/阴影图处理/{}_{}_抠图{}".format(
  421. folder_path, file_name, image_dict["image_view"], ".png"
  422. )
  423. resize_mode = 1
  424. max_box = None
  425. print("------------1", image_dict["image_view"], resize_image_view)
  426. if image_dict["image_view"] == resize_image_view:
  427. print(image_dict["image_view"], resize_image_view)
  428. resize_mode = 2
  429. if (
  430. settings.getSysConfigs("other_configs", "product_type", "鞋类")
  431. == "皮具"
  432. ):
  433. max_box = (1000, 1200)
  434. out_pic_size = (
  435. [1600]
  436. if settings.getSysConfigs("basic_configs", "main_image_size", [1600])
  437. == ""
  438. else settings.getSysConfigs("basic_configs", "main_image_size", [1600])
  439. ) # 主图大小
  440. if resize_mode == 2:
  441. print(
  442. "参数打印================》",
  443. is_image_deal_mode,
  444. resize_mode,
  445. out_pic_size,
  446. True if i_n == 1 else False,
  447. max_box,
  448. )
  449. print("**********123456********************")
  450. curve_mask = True if "俯视" in image_order_list else False
  451. try:
  452. if not generate_pic.run(
  453. image_path=original_image_path,
  454. cut_image_path=original_move_bg_image_path,
  455. out_path=out_path,
  456. image_deal_mode=is_image_deal_mode,
  457. # resize_mode=resize_mode,
  458. resize_mode=1, # 将这里得缩放模式改为强制不缩放 2025-10-22
  459. out_pic_size=out_pic_size,
  460. is_logo=True if i_n == 1 else False,
  461. out_process_path_1=out_process_path_1,
  462. out_process_path_2=out_process_path_2,
  463. max_box=max_box,
  464. logo_path=logo_path,
  465. curve_mask=curve_mask,
  466. ):
  467. print("**********222222222222222222222222222********************")
  468. is_successful = False
  469. except Exception as e:
  470. import traceback
  471. logger.error(f"货号 {folder_name} - 图片 {file_name} 生成失败: {e}\n{traceback.format_exc()}")
  472. callback_func(f"货号 {folder_name} - 图片 {file_name} 处理异常: {e}")
  473. is_successful = False
  474. if is_successful:
  475. return True
  476. else:
  477. return False
  478. def to_upload_pic(self, file_path, is_resize=True):
  479. file_name = os.path.split(file_path)[1]
  480. e = os.path.splitext(file_name)[1][1:]
  481. im = Picture(file_path)
  482. if im.x > 500:
  483. im.resize(width=500)
  484. _ = {
  485. "jpg": "JPEG",
  486. "JPG": "JPEG",
  487. "JPEG": "JPEG",
  488. "jpeg": "JPEG",
  489. "png": "PNG",
  490. "PNG": "PNG",
  491. }
  492. e = _[e]
  493. image_io = im.save_to_io(e)
  494. goods_data = {
  495. "file_path": os.path.split(file_path)[1],
  496. "image_io": image_io,
  497. "e": e,
  498. }
  499. url = self.data_mode_image_cut.get_online_data.upload_pic(goods_data=goods_data)
  500. return url
  501. def get_images(self, path):
  502. image_list = [] # 过滤非图片数据
  503. for _file in self.list_dir(path):
  504. file_name, e = os.path.splitext(_file)
  505. if e in _Type:
  506. image_list.append(
  507. {
  508. "file_path": "{}/{}".format(path, _file),
  509. "file_name": file_name,
  510. "e": e,
  511. }
  512. )
  513. return image_list
  514. def crate_all_folders(self, root_path):
  515. path_list = ["800x800", "原始图_已抠图", "阴影图处理"]
  516. for i in path_list:
  517. path = "{}/{}".format(root_path, i)
  518. self.check_path(path)
  519. def run_cutout_image(
  520. self,
  521. all_goods_art_no_folder_data,
  522. callback_func=None,
  523. cutout_mode=1,
  524. windows=None,
  525. ):
  526. cutout_mode_str = "普通抠图"
  527. match cutout_mode:
  528. case "1":
  529. cutout_mode_str = "普通抠图"
  530. case "2":
  531. cutout_mode_str = "精细化抠图"
  532. case "3":
  533. cutout_mode_str = "旗舰AI抠图"
  534. logger.info(f"当前抠图模式:{cutout_mode_str}")
  535. """
  536. 处理所有的抠图
  537. """
  538. callback_func("开始处理抠图~")
  539. goods_art_nos = [
  540. goods_art_item["folder_name"]
  541. for goods_art_item in all_goods_art_no_folder_data
  542. ]
  543. total_progress = len(all_goods_art_no_folder_data)
  544. finish_progress = 0
  545. error_progress = 0
  546. progress = {"status": "正在处理",
  547. "current": finish_progress,
  548. "total": total_progress,
  549. "error": error_progress}
  550. sendAsyncMessage(
  551. msg="开始处理抠图", goods_arts=goods_art_nos, status="开始处理", progress=progress
  552. )
  553. error_goods_art_no_folder = []
  554. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  555. if goods_art_no_folder_data["label"] != "待处理":
  556. continue
  557. folder_path = goods_art_no_folder_data["folder_path"]
  558. self.crate_all_folders(folder_path)
  559. # 检查是否存在已抠图文件,如没有再去抠图
  560. images = [x for x in self.list_dir("{}/原始图".format(folder_path))]
  561. cutImageList = []
  562. goods_art_floder_name = goods_art_no_folder_data["folder_name"]
  563. progress = {"status": "正在处理",
  564. "current": finish_progress,
  565. "total": total_progress,
  566. "error": error_progress,
  567. "goods_art_no": goods_art_floder_name
  568. }
  569. sendAsyncMessage(
  570. msg="正在抠图",
  571. goods_arts=[goods_art_floder_name],
  572. status="处理中",
  573. progress=progress
  574. )
  575. for pic_file_name in images:
  576. if windows:
  577. if windows.state != 1:
  578. break
  579. # 根据名称判断,没有抠图过的,进行统计
  580. file_name, suffix = os.path.splitext(pic_file_name)
  581. if suffix in _Type:
  582. original_image_path = "{}/原始图/{}".format(
  583. folder_path, pic_file_name
  584. )
  585. original_move_bg_image_path = "{}/原始图_已抠图/{}{}".format(
  586. folder_path, file_name, ".png"
  587. )
  588. if not os.path.exists(original_move_bg_image_path):
  589. # 没有抠图文件,进行抠图生成
  590. callback_func("正在抠图 货号:{}".format(file_name))
  591. print("cutout_mode=============>", cutout_mode)
  592. if cutout_mode == "2":
  593. cutImageList.append(
  594. {
  595. "file_name": file_name, # 文件名
  596. "file_e": suffix, # 后缀,.jpg
  597. "file_path": original_image_path, # 完整路径
  598. "file": "{}{}".format(
  599. file_name, suffix
  600. ), # 图片文件名,带后缀
  601. "need_cutout": True, # 必须,需要抠图
  602. "out_path": original_move_bg_image_path,
  603. }
  604. )
  605. else:
  606. try:
  607. if cutout_mode == "1":
  608. remove_pic_ins = RemoveBgALi()
  609. im = remove_pic_ins.get_image_cut(
  610. file_path=original_image_path,
  611. out_file_path=original_move_bg_image_path,
  612. )
  613. if cutout_mode == "3":
  614. remove_pic_ins = RemoveUltraBackground()
  615. im = remove_pic_ins.run_ultra_segment(
  616. file_path=original_image_path,
  617. out_file_path=original_move_bg_image_path,
  618. )
  619. except FunctionTimedOut as f:
  620. callback_func(
  621. "货号图{} 抠图处理超时~".format(file_name)
  622. )
  623. sendDingMsg(f"抠图服务:{cutout_mode_str}", f"货号图{file_name} 抠图处理超时~")
  624. error_goods_art_no_folder.append(folder_path)
  625. im = None
  626. except BaseException as e:
  627. callback_func(
  628. "货号图{} 抠图处理失败,原因{}".format(
  629. file_name, e
  630. )
  631. )
  632. sendDingMsg(f"抠图服务:{cutout_mode_str}", f"货号图{file_name} 抠图处理失败,原因:{e}")
  633. error_goods_art_no_folder.append(folder_path)
  634. im = None
  635. if not im:
  636. callback_func(
  637. "货号图{} 抠图处理失败~".format(file_name)
  638. )
  639. sendDingMsg(f"抠图服务:{cutout_mode_str}", f"货号图{file_name} 抠图处理失败")
  640. error_goods_art_no_folder.append(folder_path)
  641. continue
  642. else:
  643. callback_func("货号图{} 抠图完成~".format(file_name))
  644. progress = {
  645. "status": "正在处理",
  646. "current": finish_progress,
  647. "total": total_progress,
  648. "error": error_progress,
  649. "goods_art_no": goods_art_floder_name
  650. }
  651. if goods_art_floder_name not in error_goods_art_no_folder:
  652. finish_progress += 1
  653. sendAsyncMessage(
  654. msg="正在处理",
  655. goods_arts=[goods_art_floder_name],
  656. status="正在处理",
  657. progress=progress
  658. )
  659. else:
  660. progress["status"] = "处理失败"
  661. sendAsyncMessage(
  662. msg="处理失败",
  663. goods_arts=[goods_art_floder_name],
  664. status="处理失败",
  665. progress=progress
  666. )
  667. if cutout_mode == "2":
  668. dealCutout = DealCutout(windows=None, token=self.token)
  669. dealCutout.need_cutout_images = cutImageList
  670. dealCutout.run()
  671. while True:
  672. time.sleep(0.5)
  673. if dealCutout.state == 3:
  674. if len(dealCutout.resultData) != len(cutImageList):
  675. error_goods_art_no_folder.append(folder_path)
  676. break
  677. error_progress = len(error_goods_art_no_folder)
  678. progress = {
  679. "status": "处理完成",
  680. "current": finish_progress,
  681. "total": total_progress,
  682. "error": error_progress
  683. }
  684. if error_goods_art_no_folder:
  685. print("以下货号抠图失败~\n {}".format(error_goods_art_no_folder))
  686. callback_func("以下货号抠图失败~\n {}".format(error_goods_art_no_folder))
  687. sendAsyncMessage(
  688. msg=f"抠图处理失败",
  689. goods_arts=error_goods_art_no_folder,
  690. status="抠图处理失败",
  691. # progress=progress
  692. )
  693. else:
  694. pass
  695. progress["status"] = "处理失败" if error_progress == total_progress else "处理完成"
  696. def checkCutoutImage(self, image_dir: str, todo_goods_art_no_folder_name_list=None):
  697. """
  698. 进行图片检查,不合规的直接提示
  699. """
  700. error_goods_art_no_folder = []
  701. self.check_path("{}/软件-处理失败".format(image_dir))
  702. for goods_art_no_folder in self.list_dir(image_dir):
  703. # 指定内容检查
  704. if todo_goods_art_no_folder_name_list is not None:
  705. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  706. continue
  707. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  708. continue
  709. if "软件" in goods_art_no_folder:
  710. continue
  711. if "无法" in goods_art_no_folder:
  712. continue
  713. if "原始图" not in self.list_dir(
  714. "{}/{}".format(image_dir, goods_art_no_folder)
  715. ):
  716. error_goods_art_no_folder.append(goods_art_no_folder)
  717. continue
  718. self.check_path(
  719. "{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder)
  720. )
  721. self.check_path("{}/{}/800x800".format(image_dir, goods_art_no_folder))
  722. self.check_path("{}/{}/阴影图处理".format(image_dir, goods_art_no_folder))
  723. if error_goods_art_no_folder:
  724. self.move_folders(
  725. path_list=[
  726. "{}/{}".format(self.image_dir, x) for x in error_goods_art_no_folder
  727. ],
  728. target_folder="{}/软件-处理失败".format(self.image_dir),
  729. )
  730. return False
  731. def move_folders(self, path_list, target_folder):
  732. for source_folder in path_list:
  733. shutil.move(source_folder, target_folder)
  734. def rename_folder_for_hqt(self, all_goods_art_no_folder_data):
  735. """
  736. 步骤:
  737. 规整红蜻蜓的文件名
  738. 重新按文件名进行命名
  739. """
  740. goods_art_no_list = []
  741. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  742. if "@" not in goods_art_no_folder_data["folder_name"]:
  743. goods_art_no_folder_data["label"] = "待处理"
  744. goods_art_no_list.append(goods_art_no_folder_data["folder_name"])
  745. else:
  746. goods_art_no_folder_data["label"] = "不处理"
  747. if goods_art_no_list:
  748. # goods_art_no_dict 文件夹与货号的字典
  749. goods_art_no_dict = self.get_data_from_hqt_with_goods_art_no(
  750. goods_art_no_list=goods_art_no_list
  751. )
  752. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  753. if goods_art_no_folder_data["label"] != "待处理":
  754. continue
  755. goods_art_no_folder = goods_art_no_folder_data["folder_name"]
  756. if goods_art_no_folder in goods_art_no_dict:
  757. print(goods_art_no_folder)
  758. old_folder_path = goods_art_no_folder_data["folder_path"]
  759. new_folder_name = "{}@NUM{}".format(
  760. goods_art_no_folder,
  761. goods_art_no_dict[goods_art_no_folder]["编号"],
  762. )
  763. new_folder_path = "{}/{}".format(
  764. goods_art_no_folder_data["root_path"], new_folder_name
  765. )
  766. try:
  767. os.rename(old_folder_path, new_folder_path)
  768. goods_art_no_folder_data["folder_path"] = new_folder_path
  769. goods_art_no_folder_data["folder_name"] = new_folder_path
  770. goods_art_no_folder_data["label"] = "待处理"
  771. except BaseException as e:
  772. goods_art_no_folder_data["label"] = "不处理"
  773. print("521 文件夹重名命失败:{}".format(e))
  774. # 重新规整修改图片名称
  775. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  776. if goods_art_no_folder_data["label"] != "待处理":
  777. continue
  778. goods_art_no_folder = goods_art_no_folder_data["folder_name"]
  779. _img_all = self.list_dir(
  780. "{}/原始图".format(goods_art_no_folder_data["folder_path"])
  781. )
  782. index = 0
  783. for _file in _img_all:
  784. file_name, suffix = os.path.splitext(_file)
  785. if suffix in _Type:
  786. index += 1
  787. folder_path = goods_art_no_folder_data["folder_path"]
  788. new_file_name = "{}({}){}".format(
  789. goods_art_no_folder, index, suffix
  790. )
  791. new_path = "{}/原始图/{}".format(folder_path, new_file_name)
  792. old_path = "{}/原始图/{}".format(folder_path, _file)
  793. crop_new_path = "{}/原始图_已抠图/{}".format(
  794. folder_path, "{}({}).png".format(goods_art_no_folder, index)
  795. )
  796. crop_old_path = "{}/原始图_已抠图/{}".format(
  797. folder_path, "{}.png".format(file_name)
  798. )
  799. if old_path != new_path:
  800. # 存在货号命名错误的,进行修正
  801. try:
  802. if os.path.exists(old_path):
  803. os.rename(old_path, new_path)
  804. if os.path.exists(crop_old_path):
  805. os.rename(crop_old_path, crop_new_path)
  806. except BaseException as e:
  807. goods_art_no_folder_data["label"] = "不处理"
  808. print("550 文件夹重名命失败:{}".format(e))
  809. def cutImagePiju(
  810. self,
  811. image_dir: str,
  812. image_order="",
  813. is_check_number=True,
  814. is_filter=True,
  815. resize_image_view="后跟",
  816. callback_func=None,
  817. event=None,
  818. todo_goods_art_no_folder_name_list=None,
  819. ):
  820. """
  821. 1、遍历文件夹,基于生成的结果图看哪些需要进行抠图等处理
  822. 2、压缩并上传平台获取抠图
  823. 3、抠图处理成白底图
  824. 4、做成800*800/200*200
  825. :return:
  826. """
  827. logo_path = ""
  828. res = self.getImageOrder(
  829. image_order=image_order, resize_image_view=resize_image_view
  830. )
  831. if res["code"] != 0:
  832. callback_func(res["msg"])
  833. return {"code": 1, "msg": res["msg"]}
  834. imageOrderList = res["imageOrderList"]
  835. """扫描文档,检查有哪些需要进行抠图等处理"""
  836. self.lock = Lock()
  837. to_do_images_total = 0
  838. error_goods_art_no_folder = []
  839. for goods_art_no_folder in self.list_dir(image_dir):
  840. # 指定内容检查
  841. if todo_goods_art_no_folder_name_list is not None:
  842. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  843. continue
  844. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  845. continue
  846. self.check_path("{}/{}/原始图".format(image_dir, goods_art_no_folder))
  847. self.check_path(
  848. "{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder)
  849. )
  850. self.check_path("{}/{}/800x800".format(image_dir, goods_art_no_folder))
  851. self.check_path("{}/{}/阴影图处理".format(image_dir, goods_art_no_folder))
  852. # 遍历原始图片文件夹
  853. all_original_images = [
  854. x
  855. for x in self.list_dir(
  856. "{}/{}/原始图".format(image_dir, goods_art_no_folder)
  857. )
  858. ]
  859. # 检查已抠图文件夹
  860. all_moved_images = [
  861. os.path.splitext(x)[0]
  862. for x in self.list_dir(
  863. "{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder)
  864. )
  865. ]
  866. all_800images = [
  867. os.path.splitext(x)[0]
  868. for x in self.list_dir(
  869. "{}/{}/800x800".format(image_dir, goods_art_no_folder)
  870. )
  871. ]
  872. if is_check_number and len(imageOrderList) != len(all_original_images):
  873. callback_func(
  874. "{} 文件夹下图片数量与订单数量不一致,请检查!".format(
  875. goods_art_no_folder
  876. )
  877. )
  878. return {
  879. "code": 1,
  880. "msg": "{} 文件夹下图片数量与订单数量不一致,请检查!".format(
  881. goods_art_no_folder
  882. ),
  883. }
  884. all_800images = []
  885. image_num = 0
  886. for pic_file_name in all_original_images:
  887. if pic_file_name not in all_800images:
  888. # 根据名称判断,没有抠图过的,进行统计
  889. _, e = os.path.splitext(pic_file_name)
  890. print(e)
  891. if e in _Type:
  892. image_num += 1
  893. print("----------》", goods_art_no_folder, pic_file_name)
  894. to_do_images_total += 1
  895. # if image_num > 5:
  896. # error_goods_art_no_folder.append(goods_art_no_folder)
  897. # if error_goods_art_no_folder:
  898. # self.show_progress_detail("以下货号图片张数超过5张~\n {}".format(error_goods_art_no_folder))
  899. # self.set_state(state_value=2)
  900. # return
  901. if to_do_images_total > 0:
  902. # self.progress_sign.emit({"type": "处理图片 抠图、加工等", "progress_bar_value": 0})
  903. for goods_art_no_folder in self.list_dir(image_dir):
  904. # 指定内容检查
  905. if todo_goods_art_no_folder_name_list is not None:
  906. if goods_art_no_folder not in todo_goods_art_no_folder_name_list:
  907. continue
  908. if not os.path.isdir("{}/{}".format(image_dir, goods_art_no_folder)):
  909. continue
  910. self.run_one_folder_to_deal(
  911. goods_art_no_folder=goods_art_no_folder,
  912. image_dir=image_dir,
  913. image_order=image_order,
  914. resize_image_view=resize_image_view,
  915. callback_func=callback_func,
  916. logo_path=logo_path,
  917. )
  918. else:
  919. # self.show_progress_detail("没有需要处理的图片~")
  920. callback_func("没有需要处理的图片~")
  921. # self.set_state(state_value=2)
  922. return {"code": 0, "msg": "ok"}
  923. def run_one_folder_to_deal(
  924. self,
  925. goods_art_no_folder,
  926. image_dir,
  927. image_order,
  928. resize_image_view,
  929. callback_func=None,
  930. logo_path="",
  931. ):
  932. _img_all = self.list_dir("{}/{}/原始图".format(image_dir, goods_art_no_folder))
  933. all_original_images = [] # 过滤非图片数据
  934. index = 0
  935. for _file in _img_all:
  936. file_name, e = os.path.splitext(_file)
  937. if e in _Type:
  938. index += 1
  939. new_file_name = "{}({}){}".format(goods_art_no_folder, index, e)
  940. new_path = "{}/{}/原始图/{}".format(
  941. image_dir, goods_art_no_folder, new_file_name
  942. )
  943. old_path = "{}/{}/原始图/{}".format(
  944. image_dir, goods_art_no_folder, _file
  945. )
  946. if old_path != new_path:
  947. # 存在货号命名错误的,进行修正
  948. try:
  949. os.rename(old_path, new_path)
  950. except:
  951. pass
  952. all_original_images.append(new_file_name)
  953. if os.path.exists(
  954. "{}/{}/原始图/镜像.txt".format(image_dir, goods_art_no_folder)
  955. ):
  956. file_mirror_mark = True
  957. else:
  958. file_mirror_mark = None
  959. # if goods_art_no_folder == "AC51016112":
  960. # print(file_mirror_mark)
  961. # raise 111
  962. all_moved_images = [
  963. os.path.splitext(x)[0]
  964. for x in self.list_dir(
  965. "{}/{}/原始图_已抠图".format(image_dir, goods_art_no_folder)
  966. )
  967. ]
  968. all_800images = [
  969. os.path.splitext(x)[0]
  970. for x in self.list_dir(
  971. "{}/{}/800x800".format(image_dir, goods_art_no_folder)
  972. )
  973. ]
  974. all_800images = []
  975. # 检查哪些图片没有做过抠图处理
  976. i_n = 0
  977. _name_list = [
  978. "视角{}".format(x) for x in range(1, len(all_original_images) + 1)
  979. ]
  980. # if goods_art_no_folder == "AC51028001":
  981. # _name_list = ["正视", "45度", "侧视", "后视", "底视", "其他1", "其他2", "其他3"]
  982. image_index = 0 # 图片顺序
  983. is_image_deal_mode = 0
  984. max_box = None
  985. for file in all_original_images:
  986. i_n += 1
  987. image_index += 1
  988. original_image_path = "{}/{}/原始图/{}".format(
  989. image_dir, goods_art_no_folder, file
  990. )
  991. file_name = os.path.splitext(file)[0]
  992. """
  993. 当第三张就是为后跟
  994. """
  995. if file_name not in all_800images: # 所有都重新生成
  996. # if goods_art_no_folder != "AC51016112":
  997. # continue
  998. goods_art_no_folder_path = "{}/{}".format(
  999. image_dir, goods_art_no_folder
  1000. )
  1001. print("正在处理,货号:{}".format(goods_art_no_folder_path))
  1002. # self.show_progress_detail("正在处理,货号:{}".format(file_name))
  1003. callback_func("正在处理,货号:{}".format(file_name))
  1004. # 该文件在800images下没有时,则进行生成新的抠图
  1005. # 检查是否存在已抠图文件,如没有再去抠图
  1006. original_move_bg_image_path = "{}/原始图_已抠图/{}{}".format(
  1007. goods_art_no_folder_path, file_name, ".png"
  1008. )
  1009. image_deal_mode = 0 # 默认图片不做镜像处理
  1010. if not os.path.exists(original_move_bg_image_path):
  1011. # 没有抠图文件,进行抠图生成
  1012. # self.show_progress_detail("正在抠图 货号:{}".format(file_name))
  1013. callback_func("正在抠图 货号:{}".format(file_name))
  1014. remove_pic_ins = RemoveBgALi()
  1015. im = remove_pic_ins.get_image_cut(
  1016. file_path=original_image_path,
  1017. out_file_path=original_move_bg_image_path,
  1018. )
  1019. if not im:
  1020. # self.show_progress_detail("货号图{} 抠图处理失败~".format(file_name))
  1021. callback_func("货号图{} 抠图处理失败~".format(file_name))
  1022. continue
  1023. if image_index == 1:
  1024. is_image_deal_mode = 0
  1025. if settings.Mode == "鞋类":
  1026. goods_class = "鞋"
  1027. # 如果图片已存在,则需要通过加载图片判断是否为左右脚
  1028. if OnePicDeal().check_shoe_is_right(
  1029. image_path=original_move_bg_image_path
  1030. ):
  1031. image_deal_mode = 1 # 1表示要镜像,0表示不做镜像
  1032. is_image_deal_mode = 1
  1033. if settings.Mode == "皮具":
  1034. # 图片对应的商品类型
  1035. # goods_class = self.get_goods_class(goods_art_no_folder, original_image_path)
  1036. max_box = (1000, 1200)
  1037. # _ = {"AC51028001": "女包",
  1038. # "AC51028002": "男包",
  1039. # "AC51028003": "皮带",
  1040. # "AC51028004": "女包"}
  1041. # if goods_class in _:
  1042. # goods_class = _[goods_class]
  1043. # else:
  1044. # goods_class = "女包"
  1045. #
  1046. # _ = {"女包": (1000, 1200),
  1047. # "男包": (1000, 1200),
  1048. # "皮带": (1000, 1000), }
  1049. # max_box = _[goods_class]
  1050. # 获取图片信息非必要程序,用于处理图片模式
  1051. date_time_original = self.get_date_time_original(
  1052. original_image_path
  1053. ) # 获取照片拍照时间
  1054. if date_time_original:
  1055. # 基于照片的时间,与数据库匹配goods_art_no
  1056. self.lock.acquire()
  1057. _data = self.dataModeMatchPhoto.get_goods_art_no(date_time_original)
  1058. self.lock.release()
  1059. if _data:
  1060. # 能匹配上数据库
  1061. goods_art_no, _image_index, _image_deal_mode = _data
  1062. if _image_index < 10:
  1063. image_index = _image_index
  1064. if _image_deal_mode == 1:
  1065. image_deal_mode = 1
  1066. # print(goods_art_no, image_index, image_deal_mode)
  1067. if file_mirror_mark:
  1068. image_deal_mode = 1
  1069. """进行800image 生成"""
  1070. generate_pic = GeneratePic()
  1071. out_pci_mode = "." + settings.getSysConfigs(
  1072. "basic_configs", "image_out_format", "png"
  1073. )
  1074. if out_pci_mode == ".jpg":
  1075. out_path = "{}/800x800/{}{}".format(
  1076. goods_art_no_folder_path, file_name, ".jpg"
  1077. )
  1078. elif out_pci_mode == ".png":
  1079. out_path = "{}/800x800/{}{}".format(
  1080. goods_art_no_folder_path, file_name, ".png"
  1081. )
  1082. else:
  1083. out_path = "{}/800x800/{}{}".format(
  1084. goods_art_no_folder_path, file_name, out_pci_mode
  1085. )
  1086. out_process_path_1 = "{}/阴影图处理/{}_{}_阴影{}".format(
  1087. goods_art_no_folder_path, file_name, _name_list[i_n - 1], ".png"
  1088. )
  1089. out_process_path_2 = "{}/阴影图处理/{}_{}_抠图{}".format(
  1090. goods_art_no_folder_path, file_name, _name_list[i_n - 1], ".png"
  1091. )
  1092. print("image_index", image_index)
  1093. image_index = 99
  1094. curve_mask = True if "俯视" in image_order["image_view"] else False
  1095. out_pic_size = (
  1096. [1600]
  1097. if settings.getSysConfigs(
  1098. "basic_configs", "main_image_size", [1600]
  1099. )
  1100. == ""
  1101. else settings.getSysConfigs(
  1102. "basic_configs", "main_image_size", [1600]
  1103. )
  1104. ) # 主图大小
  1105. if generate_pic.run(
  1106. image_path=original_image_path,
  1107. cut_image_path=original_move_bg_image_path,
  1108. out_path=out_path,
  1109. image_deal_mode=is_image_deal_mode,
  1110. image_index=image_index,
  1111. out_pic_size=out_pic_size,
  1112. is_logo=True if i_n == 1 else False,
  1113. out_process_path_1=out_process_path_1,
  1114. out_process_path_2=out_process_path_2,
  1115. max_box=max_box,
  1116. logo_path=logo_path,
  1117. curve_mask=curve_mask,
  1118. ):
  1119. # self.show_progress_detail("货号图{} _{} 已完成800*800图片制作~".format(image_index, file_name))
  1120. callback_func(
  1121. "货号图{} _{} 已完成800*800图片制作~".format(
  1122. image_index, file_name
  1123. )
  1124. )
  1125. else:
  1126. # self.show_progress_detail("货号图{} _{} 图片生成处理失败~".format(image_index, file_name))
  1127. callback_func(
  1128. "货号图{} _{} 图片生成处理失败~".format(image_index, file_name)
  1129. )
  1130. # 完成处理的图片进度
  1131. self.lock.acquire()
  1132. # self.set_progress()
  1133. self.lock.release()
  1134. def get_goods_art_no(self, date_time_original):
  1135. time_array = time.strptime(date_time_original, "%Y:%m:%d %H:%M:%S")
  1136. time_array = time.mktime(time_array)
  1137. datetime_obj = datetime.fromtimestamp(time_array)
  1138. session = SqlQuery()
  1139. configModel = CRUD(DeviceConfig)
  1140. result = configModel.read(
  1141. session,
  1142. conditions={"photo_create_time": datetime_obj},
  1143. order_by="id",
  1144. ascending=True,
  1145. )
  1146. session.close()
  1147. if result:
  1148. return result.goods_art_no, result.image_index, result.image_deal_mode
  1149. else:
  1150. return None
  1151. def get_goods_art_no_info(
  1152. self, numbers_list=None, goods_art_list=None, headers=None
  1153. ):
  1154. # 获取商品基础信息,入参为商品的编号
  1155. url = "{domain}/api/backend/goods_client/goods_query".format(
  1156. domain=settings.APP_HOST
  1157. )
  1158. data = {"goods_art_list": goods_art_list}
  1159. data = json.dumps(data)
  1160. _s = requests.session().post(url=url, data=data, headers=headers)
  1161. response_data = _s.json()
  1162. goods_number_data = {}
  1163. # ["", "", "", "", "", "", "", "", "", "", "", ]
  1164. if "data" not in response_data:
  1165. return {}
  1166. for data in response_data["data"]:
  1167. goods_number_data[data["goods_art_no"]] = {}
  1168. goods_number_data[data["goods_art_no"]]["商品货号"] = data[
  1169. "goods_art_no"
  1170. ].upper()
  1171. goods_number_data[data["goods_art_no"]]["款号"] = data[
  1172. "goods_number"
  1173. ].upper()
  1174. goods_number_data[data["goods_art_no"]]["商品面料"] = data["fabric"]
  1175. goods_number_data[data["goods_art_no"]]["商品内里"] = data["lining"]
  1176. goods_number_data[data["goods_art_no"]]["商品鞋底"] = data["sole"]
  1177. goods_number_data[data["goods_art_no"]]["鞋垫"] = data["insole"]
  1178. goods_number_data[data["goods_art_no"]]["颜色名称"] = data["color"]
  1179. return goods_number_data
  1180. def get_data_from_hqt_with_goods_art_no(self, goods_art_no_list):
  1181. _goods_art_no_list = copy.deepcopy(goods_art_no_list)
  1182. _list = []
  1183. # 单次请求数少于20个
  1184. goods_art_no_dict = {}
  1185. while _goods_art_no_list:
  1186. goods_art_no = _goods_art_no_list.pop()
  1187. _list.append(goods_art_no)
  1188. if len(_list) == 20 or len(_goods_art_no_list) == 0:
  1189. online_goods_art_data = self.get_goods_art_no_info(goods_art_list=_list)
  1190. if online_goods_art_data:
  1191. for _goods_art_no in online_goods_art_data:
  1192. goods_art_no_dict[_goods_art_no] = online_goods_art_data[
  1193. _goods_art_no
  1194. ]
  1195. _list = []
  1196. return goods_art_no_dict
  1197. def get_goods_art_no_info(
  1198. self, numbers_list=None, goods_art_list=None, headers=None
  1199. ):
  1200. # 获取商品基础信息,入参为商品的编号
  1201. url = "{domain}/api/backend/goods_client/goods_query".format(
  1202. domain=settings.APP_HOST
  1203. )
  1204. data = {"goods_art_list": goods_art_list}
  1205. data = json.dumps(data)
  1206. _s = requests.session().post(url=url, data=data, headers=headers)
  1207. # _s = self.s.get(url=url, params=params, headers=settings.Headers)
  1208. response_data = _s.json()
  1209. goods_number_data = {}
  1210. # ["", "", "", "", "", "", "", "", "", "", "", ]
  1211. if "data" not in response_data:
  1212. return {}
  1213. for data in response_data["data"]:
  1214. goods_number_data[data["goods_art_no"]] = {}
  1215. goods_number_data[data["goods_art_no"]]["商品货号"] = data[
  1216. "goods_art_no"
  1217. ].upper()
  1218. goods_number_data[data["goods_art_no"]]["款号"] = data[
  1219. "goods_number"
  1220. ].upper()
  1221. goods_number_data[data["goods_art_no"]]["商品面料"] = data["fabric"]
  1222. goods_number_data[data["goods_art_no"]]["商品内里"] = data["lining"]
  1223. goods_number_data[data["goods_art_no"]]["商品鞋底"] = data["sole"]
  1224. goods_number_data[data["goods_art_no"]]["鞋垫"] = data["insole"]
  1225. goods_number_data[data["goods_art_no"]]["颜色名称"] = data["color"]
  1226. return goods_number_data
  1227. def get_data_from_hqt(self, goods_number_list):
  1228. _goods_number_list = copy.deepcopy(goods_number_list)
  1229. _list = []
  1230. # 单次请求数少于20个
  1231. goods_number_dict = {}
  1232. while _goods_number_list:
  1233. goods_art_no = _goods_number_list.pop()
  1234. if "NUM" in goods_art_no:
  1235. goods_art_no = goods_art_no.replace("NUM", "")
  1236. _list.append(goods_art_no)
  1237. if len(_list) == 20 or len(_goods_number_list) == 0:
  1238. online_goods_art_data = self.get_goods_art_no_info(numbers_list=_list)
  1239. if online_goods_art_data:
  1240. for number in online_goods_art_data:
  1241. goods_number_dict["NUM" + number] = online_goods_art_data[
  1242. number
  1243. ]
  1244. _list = []
  1245. return goods_number_dict
  1246. def dealMoveImage(self, image_dir: str, callback_func=None) -> dict:
  1247. if not self.check_path(image_dir=image_dir + "/历史"):
  1248. return {"code": 1, "msg": "文件夹创建失败", "data": {}}
  1249. # 遍历目标文件夹,获取有拍摄信息的图片,并按拍摄时间排序
  1250. files = self.list_dir(image_dir)
  1251. original_photo_list = [] # 原始图片列表
  1252. for file in files:
  1253. # -----图片清洗
  1254. file_path = image_dir + "/" + file
  1255. if os.path.isdir(file_path): # 忽略文件夹
  1256. continue
  1257. file_name, suffix = os.path.splitext(file)
  1258. if suffix not in _Type: # 非图片进行移除
  1259. shutil.move(file_path, image_dir + "/历史/" + file)
  1260. continue
  1261. date_time_original = self.get_date_time_original(
  1262. file_path
  1263. ) # 获取照片拍照时间
  1264. if date_time_original:
  1265. # 基于照片的时间,与数据库匹配goods_art_no
  1266. _data = self.get_goods_art_no(date_time_original)
  1267. if _data:
  1268. # 能匹配上数据库
  1269. goods_art_no, image_index, image_deal_mode = _data
  1270. print(
  1271. "832 与数据库匹配goods_art_no",
  1272. file_name,
  1273. date_time_original,
  1274. goods_art_no,
  1275. )
  1276. original_photo_list.append(
  1277. {
  1278. "file_path": file_path,
  1279. "file": file,
  1280. "date_time_original": date_time_original,
  1281. "goods_art_no": goods_art_no,
  1282. "image_index": image_index,
  1283. "real_goods_art_no": "",
  1284. "real_goods_number": "",
  1285. }
  1286. )
  1287. else:
  1288. # 匹配不上报错
  1289. # self.show_progress_detail("图片:{} 无法对应货号,不做处理".format(file))
  1290. if callback_func:
  1291. callback_func("图片:{} 无对应货号".format(file))
  1292. # shutil.move(photo_dict["file_path"], self.image_dir + "/历史/" + photo_dict["file"])
  1293. continue
  1294. else:
  1295. shutil.move(file_path, image_dir + "/历史/" + file)
  1296. if not original_photo_list:
  1297. return {"code": 1, "msg": "没有任何匹配的图片", "data": {}}
  1298. if settings.PROJECT == "红蜻蜓":
  1299. # 批量请求货号图信息
  1300. goods_art_no_list = [x["goods_art_no"] for x in original_photo_list]
  1301. goods_art_no_list = list(set(goods_art_no_list))
  1302. goods_art_no_list = [x for x in goods_art_no_list if "NUM" not in x]
  1303. if goods_art_no_list:
  1304. goods_art_no_dict = self.get_data_from_hqt_with_goods_art_no(
  1305. goods_art_no_list=goods_art_no_list
  1306. )
  1307. for i in original_photo_list:
  1308. if i["goods_art_no"] in goods_art_no_dict:
  1309. i["real_goods_art_no"] = i["goods_art_no"]
  1310. i["real_goods_number"] = "NUM{}".format(
  1311. goods_art_no_dict[i["goods_art_no"]]["编号"]
  1312. )
  1313. # 批量请求编号对应信息
  1314. goods_number_list = [x["goods_art_no"] for x in original_photo_list]
  1315. goods_number_list = list(set(goods_number_list))
  1316. goods_number_list = [x for x in goods_number_list if "NUM" in x]
  1317. if goods_number_list:
  1318. goods_number_dict = self.get_data_from_hqt(
  1319. goods_number_list=goods_number_list
  1320. )
  1321. for i in original_photo_list:
  1322. if i["goods_art_no"] in goods_number_dict:
  1323. i["real_goods_number"] = i["goods_art_no"]
  1324. i["real_goods_art_no"] = goods_number_dict[i["goods_art_no"]][
  1325. "商品货号"
  1326. ]
  1327. # 排序需要基于拍照的文件序号进行处理
  1328. original_photo_list.sort(
  1329. key=lambda x: "{}-{}-{}".format(
  1330. x["goods_art_no"], x["image_index"], x["file"]
  1331. )
  1332. )
  1333. # print(original_photo_list)
  1334. # 对有拍摄信息的图片进行数据库比对,如有比对上,则移动至货号文件夹,否则移入历史文件夹
  1335. total_num = len(original_photo_list)
  1336. # 当天日期作为文件夹
  1337. seconds = time.time()
  1338. output_path = "output/{f_name}".format(
  1339. f_name=time.strftime("%Y-%m-%d", time.localtime(seconds))
  1340. )
  1341. # 遍历每个匹配好的数据进行处理
  1342. n = 0
  1343. for photo_dict in original_photo_list:
  1344. n += 1
  1345. # 进度条
  1346. goods_art_no = photo_dict["goods_art_no"]
  1347. original_image_path = photo_dict["file_path"]
  1348. # 输出货号文件夹
  1349. if photo_dict["real_goods_art_no"]:
  1350. goods_art_no = "{}@{}".format(
  1351. photo_dict["real_goods_art_no"], photo_dict["real_goods_number"]
  1352. )
  1353. goods_art_no_path = "{output_path}/{goods_art_no}".format(
  1354. output_path=output_path, goods_art_no=goods_art_no
  1355. )
  1356. # 创建货号下的一系列文件夹
  1357. self.create_folder(goods_art_no_path)
  1358. # 重命名并进行移动
  1359. print(
  1360. "开始移动:{} {} 命名为:{}".format(
  1361. goods_art_no, original_image_path, goods_art_no_path
  1362. )
  1363. )
  1364. self.move_images(
  1365. goods_art_no, goods_art_no_path, original_image_path
  1366. ) # 货号、货号文件路径、原始图路径
  1367. time.sleep(0.2)
  1368. # self.progress_sign.emit({"type": "移动原始图片", "progress_bar_value": int(n / total_num * 100)})
  1369. # self.show_progress_detail("货号{} 相关文件夹创建完成,已移动原图~".format(goods_art_no))
  1370. if callback_func:
  1371. callback_func(
  1372. "货号{} 相关文件夹创建完成,已移动原图~".format(goods_art_no)
  1373. )
  1374. print("已完成移动处理")
  1375. if n != 0:
  1376. # if settings.MattingPics:
  1377. # # 检查所有未处理的货号文件夹,查看是否有完成图片加工处理
  1378. # self.deal_images()
  1379. # 自动生成一个货号表
  1380. print("output_path", output_path)
  1381. GenerateGoodsArtNoTable.deal(output_path)
  1382. # 完成处理
  1383. # self.set_state(state_value=2)
  1384. return {"code": 0, "msg": "处理完成", "target_path": output_path, "data": {}}
  1385. def check_path(self, image_dir: str):
  1386. if not os.path.exists(image_dir):
  1387. os.mkdir(image_dir)
  1388. return True
  1389. def get_date_time_original(self, file_path):
  1390. with open(file_path, "rb") as file_data:
  1391. tags = exifread.process_file(file_data)
  1392. if "EXIF DateTimeOriginal" in tags:
  1393. return str(tags["EXIF DateTimeOriginal"])
  1394. else:
  1395. return False
  1396. def create_folder(self, path):
  1397. def check_folder(__path):
  1398. if not os.path.exists(__path):
  1399. os.makedirs(__path)
  1400. return False
  1401. return True
  1402. # 文件夹不存在,创建货号子集文件夹
  1403. if not check_folder(path):
  1404. for name in ["原始图", "原始图_已抠图", "800x800", "200images"]:
  1405. other_path = path + "/" + name
  1406. check_folder(other_path)
  1407. def move_images(self, goods_art_no, goods_art_no_path, old_image_path):
  1408. """
  1409. 步骤:
  1410. 1、移动到原始图
  1411. Args:
  1412. goods_art_no:
  1413. goods_art_no_path:
  1414. old_image_path:
  1415. Returns:
  1416. """
  1417. # 移动到原始图
  1418. file = os.path.split(old_image_path)[1]
  1419. # 扩展名
  1420. e = os.path.splitext(file)[1]
  1421. # 获取图片序列
  1422. self.goods_images_count_dict[goods_art_no] += 1
  1423. # A9999(1).jpg
  1424. new_file_name = "{}({})".format(
  1425. goods_art_no, self.goods_images_count_dict[goods_art_no]
  1426. )
  1427. original_image_path = "{}/原始图/{}{}".format(
  1428. goods_art_no_path, new_file_name, e
  1429. )
  1430. # 移动图片
  1431. shutil.move(old_image_path, original_image_path)
  1432. def pixianRemoveImageBg(
  1433. self, file_path: str, out_file_path: str, callbackek_func=None
  1434. ):
  1435. url = self.dataModeMatchPhoto.get_online_data.uploadImage(local_path=file_path)
  1436. remonveUrl = settings.DOMAIN + "/api/ai_image/main/remove_background"
  1437. param = {"base_image": url}
  1438. post_headers = {
  1439. "Authorization": self.token,
  1440. "Content-Length": "",
  1441. "Content-Type": "application/json",
  1442. "Accept": "application/json",
  1443. }
  1444. result = requests.post(
  1445. remonveUrl, data=json.dumps(param), headers=post_headers
  1446. ).json()
  1447. print(result)
  1448. if "code" in result and result["code"] == 0:
  1449. response = requests.get(result["data"]["image"][0])
  1450. with open(out_file_path, "wb") as file:
  1451. file.write(response.content)
  1452. return result["data"]["image"][0]
  1453. else:
  1454. callbackek_func("精细化抠图处理失败 {}".format(result["message"]))
  1455. return ""
  1456. def list_dir(self, path):
  1457. listdir = os.listdir(path)
  1458. return natsorted(listdir, alg=ns.PATH)