module_generate_main_image.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. """
  2. 步骤:
  3. 1、抠图
  4. 2、色阶处理,保留阴影
  5. 3、定位商品中心,并进行抠图
  6. 4、缩放定位,并粘贴到中心位置
  7. 5、粘贴水印
  8. """
  9. import copy
  10. import time
  11. import cv2
  12. import numpy as np
  13. from PIL import Image, ImageEnhance
  14. import os
  15. from module.log.log import MyLogger
  16. if __name__ != '__main__':
  17. import settings
  18. class GeneratePic(object):
  19. def __init__(self):
  20. self.logger = MyLogger()
  21. pass
  22. def to_resize(self, _im, width=None, high=None):
  23. _im_x, _im_y = _im.size
  24. if width and high:
  25. if _im_x >= _im_y:
  26. high = None
  27. else:
  28. width = None
  29. if width:
  30. re_x = int(width)
  31. re_y = int(_im_y * re_x / _im_x)
  32. else:
  33. re_y = int(high)
  34. re_x = int(_im_x * re_y / _im_y)
  35. _im = _im.resize((re_x, re_y))
  36. return _im
  37. def clean_colors(self, img):
  38. img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  39. return img
  40. def levels_adjust(self, img, Shadow, Midtones, Highlight, OutShadow, OutHighlight, Dim):
  41. # print(img)
  42. # dim = 3的时候调节RGB三个分量, 0调节B,1调节G,2调节R
  43. if Dim == 3:
  44. mask_shadow = img < Shadow
  45. img[mask_shadow] = Shadow
  46. mask_Highlight = img > Highlight
  47. img[mask_Highlight] = Highlight
  48. else:
  49. mask_shadow = img[..., Dim] < Shadow
  50. img[mask_shadow] = Shadow
  51. mask_Highlight = img[..., Dim] > Highlight
  52. img[mask_Highlight] = Highlight
  53. if Dim == 3:
  54. Diff = Highlight - Shadow
  55. rgbDiff = img - Shadow
  56. clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
  57. outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
  58. data = np.array(outClRgb * 255, dtype='uint8')
  59. img = data
  60. else:
  61. Diff = Highlight - Shadow
  62. rgbDiff = img[..., Dim] - Shadow
  63. clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
  64. outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
  65. data = np.array(outClRgb * 255, dtype='uint8')
  66. img[..., Dim] = data
  67. return img
  68. def calculate_average_brightness_opencv(self, img_gray, rows_to_check):
  69. # 二值化的图片 CV对象
  70. height, width = img_gray.shape
  71. brightness_list = []
  72. for row in rows_to_check:
  73. if 0 <= row < height:
  74. # 直接计算该行的平均亮度
  75. row_data = img_gray[row, :]
  76. average_brightness = np.mean(row_data)
  77. brightness_list.append(average_brightness)
  78. else:
  79. print(f"警告:行号{row}超出图片范围,已跳过。")
  80. return brightness_list
  81. def run(self, image_path, cut_image_path, out_path, image_deal_mode=0, image_index=99,
  82. out_pic_size=1024, is_logo=True, out_process_path_1=None, out_process_path_2=None,
  83. resize_mode=None, **kwargs): # im 为cv对象
  84. """
  85. image_path:原始图
  86. cut_image_path:抠图结果
  87. out_path:输出文件夹
  88. image_deal_mode:图片处理模式,1表示需要镜像处理
  89. """
  90. # ==========先进行剪切原图
  91. im = Image.open(image_path)
  92. old_x, old_y = im.size
  93. cut_image = Image.open(cut_image_path)
  94. try:
  95. x1, y1, x2, y2 = cut_image.getbbox()
  96. # im_shadow.crop((x1, y1, x2, y2)).show()# 切图
  97. except BaseException as e:
  98. print("抠图失败")
  99. return False
  100. goods_w, goods_h = x2 - x1, y2 - y1
  101. _w, _h = int(goods_w / 10), int(goods_h / 10) # 上下左右扩展位置
  102. new_x1, new_y1, new_x2, new_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h # 防止超限
  103. new_x1 = 0 if new_x1 < 0 else new_x1
  104. new_y1 = 0 if new_y1 < 0 else new_y1
  105. new_x2 = old_x if new_x2 > old_x else new_x2
  106. new_y2 = old_y if new_y2 > old_y else new_y2
  107. im = im.crop((new_x1, new_y1, new_x2, new_y2)) # 切图
  108. cut_image = cut_image.crop((new_x1, new_y1, new_x2, new_y2)) # 切图
  109. new_x, new_y = im.size
  110. # ================自动色阶处理
  111. _im = cv2.cvtColor(np.asarray(im), cv2.COLOR_RGB2BGR)
  112. # 背景阴影
  113. im_shadow = cv2.cvtColor(_im, cv2.COLOR_BGR2GRAY)
  114. s = time.time()
  115. rows = [int(new_y * 19.8 / 20)]
  116. # draw = ImageDraw.Draw(im)
  117. # for row in rows:
  118. # draw.line((0, row, new_x, row), fill=128, width=3)
  119. # im.show()
  120. _im_shadow = copy.copy(im_shadow)
  121. Midtones = 0.52
  122. Highlight = 235
  123. k = 20
  124. while k:
  125. k -= 1
  126. Midtones += 0.1
  127. Highlight -= 5
  128. _im_shadow = self.levels_adjust(img=im_shadow, Shadow=0, Midtones=Midtones, Highlight=Highlight,
  129. OutShadow=0,
  130. OutHighlight=255, Dim=3)
  131. brightness_list = self.calculate_average_brightness_opencv(img_gray=_im_shadow, rows_to_check=rows)
  132. print(brightness_list)
  133. if brightness_list[0] >= 254:
  134. break
  135. print(time.time() - s)
  136. im_shadow = Image.fromarray(cv2.cvtColor(_im_shadow, cv2.COLOR_BGR2RGB))
  137. im_shadow.paste(cut_image, (0, 0), cut_image) # 把原图粘贴回去,避免色差
  138. # 保存带有阴影的底图,没有logo
  139. if out_process_path_1:
  140. out_image_1 = im_shadow.copy()
  141. if image_deal_mode == 1:
  142. out_image_1 = out_image_1.transpose(Image.FLIP_LEFT_RIGHT)
  143. out_image_1.save(out_process_path_1)
  144. # 保存抠图结果,没有底图,没有logo
  145. if out_process_path_2:
  146. out_image_2 = cut_image.copy()
  147. if image_deal_mode == 1:
  148. out_image_2 = out_image_2.transpose(Image.FLIP_LEFT_RIGHT)
  149. out_image_2.save(out_process_path_2)
  150. # im_shadow.show()
  151. # 主图物体的缩放依据大小
  152. if resize_mode is None:
  153. im_shadow = self.to_resize(_im=im_shadow, width=1400, high=1400)
  154. cut_image = self.to_resize(_im=cut_image, width=1400, high=1400)
  155. elif resize_mode == 1:
  156. im_shadow = self.to_resize(_im=im_shadow, width=1400, high=1400)
  157. cut_image = self.to_resize(_im=cut_image, width=1400, high=1400)
  158. elif resize_mode == 2:
  159. if im_shadow.height <= im_shadow.width * 1.2:
  160. im_shadow = self.to_resize(_im=im_shadow, width=650)
  161. cut_image = self.to_resize(_im=cut_image, width=650)
  162. else:
  163. im_shadow = self.to_resize(_im=im_shadow, high=1400)
  164. cut_image = self.to_resize(_im=cut_image, high=1400)
  165. if image_deal_mode == 1:
  166. # 翻转
  167. im_shadow = im_shadow.transpose(Image.FLIP_LEFT_RIGHT)
  168. cut_image = cut_image.transpose(Image.FLIP_LEFT_RIGHT)
  169. # 创建底层背景
  170. image_bg = Image.new("RGB", (1600, 1600), (255, 255, 255))
  171. image_bg_x, image_bg_y = image_bg.size
  172. image_x, image_y = im_shadow.size
  173. _x = int((image_bg_x - image_x) / 2)
  174. _y = int((image_bg_y - image_y) / 2)
  175. image_bg.paste(im_shadow, (_x, _y))
  176. image_bg.paste(cut_image, (_x, _y), cut_image) # 再叠加原图避免色差
  177. if is_logo:
  178. logo_path = ""
  179. if settings.PROJECT == "红蜻蜓":
  180. logo_path = r"resources\LOGO\HQT\logo.png"
  181. elif settings.PROJECT == "惠利玛":
  182. if "小苏" in settings.Company:
  183. logo_path = r"resources\LOGO\xiaosushuoxie\logo.png"
  184. elif "惠利玛" in settings.Company:
  185. logo_path = r"resources\LOGO\HLM\logo.png"
  186. else:
  187. pass
  188. if not logo_path:
  189. logo_im = Image.new("RGBA", (1600, 1600), (0, 0, 0, 0))
  190. else:
  191. if os.path.exists(logo_path):
  192. logo_im = Image.open(logo_path)
  193. else:
  194. logo_im = Image.new("RGBA", (1600, 1600), (0, 0, 0, 0))
  195. image_bg.paste(logo_im, (0, 0), logo_im)
  196. image_bg = image_bg.resize((out_pic_size, out_pic_size), Image.BICUBIC)
  197. # image_bg.show()
  198. image_bg.save(out_path, quality=100, dpi=(300, 300), format="JPEG")
  199. return True
  200. class GeneratePicPiJu(object):
  201. def __init__(self):
  202. pass
  203. def calculate_average_brightness_opencv(self, img_gray, rows_to_check):
  204. # 二值化的图片 CV对象
  205. height, width = img_gray.shape
  206. brightness_list = []
  207. for row in rows_to_check:
  208. if 0 <= row < height:
  209. # 直接计算该行的平均亮度
  210. row_data = img_gray[row, :]
  211. average_brightness = np.mean(row_data)
  212. brightness_list.append(average_brightness)
  213. else:
  214. print(f"警告:行号{row}超出图片范围,已跳过。")
  215. return brightness_list
  216. def to_resize(self, _im, width=None, high=None):
  217. _im_x, _im_y = _im.size
  218. if width and high:
  219. if _im_x >= _im_y:
  220. high = None
  221. else:
  222. width = None
  223. if width:
  224. re_x = int(width)
  225. re_y = int(_im_y * re_x / _im_x)
  226. else:
  227. re_y = int(high)
  228. re_x = int(_im_x * re_y / _im_y)
  229. _im = _im.resize((re_x, re_y))
  230. return _im
  231. def run(self, image_path, cut_image_path, out_path, image_deal_mode=0, image_index=99,
  232. out_pic_size=800, is_logo=True, out_process_path_1=None, out_process_path_2=None, max_box=None): # im 为cv对象
  233. """
  234. image_path:原始图
  235. cut_image_path:抠图结果
  236. out_path:输出文件夹
  237. image_deal_mode:图片处理模式,1表示需要镜像处理
  238. """
  239. # ==========先进行剪切原图
  240. im = Image.open(image_path)
  241. old_x, old_y = im.size
  242. cut_image = Image.open(cut_image_path)
  243. try:
  244. x1, y1, x2, y2 = cut_image.getbbox()
  245. # im_shadow.crop((x1, y1, x2, y2)).show()# 切图
  246. except BaseException as e:
  247. print("抠图失败")
  248. return False
  249. goods_w, goods_h = x2 - x1, y2 - y1
  250. _w, _h = int(goods_w / 10), int(goods_h / 10) # 上下左右扩展位置
  251. new_x1, new_y1, new_x2, new_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h # 防止超限
  252. new_x1 = 0 if new_x1 < 0 else new_x1
  253. new_y1 = 0 if new_y1 < 0 else new_y1
  254. new_x2 = old_x if new_x2 > old_x else new_x2
  255. new_y2 = old_y if new_y2 > old_y else new_y2
  256. im = im.crop((new_x1, new_y1, new_x2, new_y2)) # 切图
  257. cut_image = cut_image.crop((new_x1, new_y1, new_x2, new_y2)) # 切图
  258. new_x, new_y = im.size
  259. # ================自动色阶处理
  260. _im = cv2.cvtColor(np.asarray(im), cv2.COLOR_RGB2BGR)
  261. # 背景阴影
  262. im_shadow = cv2.cvtColor(_im, cv2.COLOR_BGR2GRAY)
  263. s = time.time()
  264. rows = [int(new_y * 19.8 / 20)]
  265. # draw = ImageDraw.Draw(im)
  266. # for row in rows:
  267. # draw.line((0, row, new_x, row), fill=128, width=3)
  268. # im.show()
  269. _im_shadow = copy.copy(im_shadow)
  270. Midtones = 0.52
  271. Highlight = 235
  272. k = 20
  273. while k:
  274. k -= 1
  275. Midtones += 0.1
  276. Highlight -= 5
  277. _im_shadow = self.levels_adjust(img=im_shadow, Shadow=0, Midtones=Midtones, Highlight=Highlight,
  278. OutShadow=0,
  279. OutHighlight=255, Dim=3)
  280. brightness_list = self.calculate_average_brightness_opencv(img_gray=_im_shadow, rows_to_check=rows)
  281. print(brightness_list)
  282. if brightness_list[0] >= 254:
  283. break
  284. print(time.time() - s)
  285. im_shadow = Image.fromarray(cv2.cvtColor(_im_shadow, cv2.COLOR_BGR2RGB))
  286. im_shadow.paste(cut_image, (0, 0), cut_image) # 把原图粘贴回去,避免色差
  287. # 保存带有阴影的底图,没有logo
  288. if out_process_path_1:
  289. out_image_1 = im_shadow.copy()
  290. if image_deal_mode == 1:
  291. out_image_1 = out_image_1.transpose(Image.FLIP_LEFT_RIGHT)
  292. out_image_1.save(out_process_path_1)
  293. # 保存抠图结果,没有底图,没有logo
  294. if out_process_path_2:
  295. out_image_2 = cut_image.copy()
  296. if image_deal_mode == 1:
  297. out_image_2 = out_image_2.transpose(Image.FLIP_LEFT_RIGHT)
  298. out_image_2.save(out_process_path_2)
  299. # im_shadow.show()
  300. if max_box:
  301. im_shadow = self.to_resize(_im=im_shadow, width=max_box[0], high=max_box[1])
  302. cut_image = self.to_resize(_im=cut_image, width=max_box[0], high=max_box[1])
  303. else:
  304. if image_index != 3:
  305. im_shadow = self.to_resize(_im=im_shadow, width=1000, high=1000)
  306. cut_image = self.to_resize(_im=cut_image, width=1000, high=1000)
  307. else:
  308. im_shadow = self.to_resize(_im=im_shadow, width=650)
  309. cut_image = self.to_resize(_im=cut_image, width=650)
  310. if image_deal_mode == 1:
  311. # 翻转
  312. im_shadow = im_shadow.transpose(Image.FLIP_LEFT_RIGHT)
  313. cut_image = cut_image.transpose(Image.FLIP_LEFT_RIGHT)
  314. # 创建底层背景
  315. image_bg = Image.new("RGB", (1600, 1600), (255, 255, 255))
  316. image_bg_x, image_bg_y = image_bg.size
  317. image_x, image_y = im_shadow.size
  318. _x = int((image_bg_x - image_x) / 2)
  319. _y = int((image_bg_y - image_y) / 2)
  320. image_bg.paste(im_shadow, (_x, _y))
  321. image_bg.paste(cut_image, (_x, _y), cut_image)
  322. if is_logo:
  323. logo_path = ""
  324. if settings.PROJECT == "红蜻蜓":
  325. logo_path = r"resources\LOGO\HQT\logo.png"
  326. elif settings.PROJECT == "惠利玛":
  327. if "小苏" in settings.Company:
  328. logo_path = r"resources\LOGO\xiaosushuoxie\logo.png"
  329. elif "惠利玛" in settings.Company:
  330. logo_path = r"resources\LOGO\HLM\logo.png"
  331. else:
  332. pass
  333. if not logo_path:
  334. logo_im = Image.new("RGBA", (1600, 1600), (0, 0, 0, 0))
  335. else:
  336. if os.path.exists(logo_path):
  337. logo_im = Image.open(logo_path)
  338. else:
  339. logo_im = Image.new("RGBA", (1600, 1600), (0, 0, 0, 0))
  340. image_bg.paste(logo_im, (0, 0), logo_im)
  341. image_bg = image_bg.resize((out_pic_size, out_pic_size), Image.BICUBIC)
  342. # image_bg.show()
  343. image_bg.save(out_path, quality=100, dpi=(300, 300), format="JPEG")
  344. return True
  345. def increase_brightness(self, im, brightness_factor):
  346. # 打开图片
  347. # 将图片转换为RGB模式
  348. # image = image.convert("RGBA")
  349. # 获取图片的亮度值
  350. enhancer = ImageEnhance.Brightness(im)
  351. brightness = enhancer.enhance(brightness_factor)
  352. return brightness
  353. def clean_colors(self, img):
  354. img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  355. return img
  356. def levels_adjust(self, img, Shadow, Midtones, Highlight, OutShadow, OutHighlight, Dim):
  357. # print(img)
  358. # dim = 3的时候调节RGB三个分量, 0调节B,1调节G,2调节R
  359. if Dim == 3:
  360. mask_shadow = img < Shadow
  361. img[mask_shadow] = Shadow
  362. mask_Highlight = img > Highlight
  363. img[mask_Highlight] = Highlight
  364. else:
  365. mask_shadow = img[..., Dim] < Shadow
  366. img[mask_shadow] = Shadow
  367. mask_Highlight = img[..., Dim] > Highlight
  368. img[mask_Highlight] = Highlight
  369. if Dim == 3:
  370. Diff = Highlight - Shadow
  371. rgbDiff = img - Shadow
  372. clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
  373. outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
  374. data = np.array(outClRgb * 255, dtype='uint8')
  375. img = data
  376. else:
  377. Diff = Highlight - Shadow
  378. rgbDiff = img[..., Dim] - Shadow
  379. clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
  380. outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
  381. data = np.array(outClRgb * 255, dtype='uint8')
  382. img[..., Dim] = data
  383. return img
  384. if __name__ == '__main__':
  385. # 测试皮具主图生成
  386. for jpg_name in os.listdir("image"):
  387. if "png" in jpg_name:
  388. continue
  389. file_name = os.path.splitext(jpg_name)[0]
  390. original_image_path = r"image\{}.jpg".format(file_name)
  391. original_move_bg_image_path = r"image\{}.png".format(file_name)
  392. out_path = r"out\{}.jpg".format(file_name)
  393. is_image_deal_mode = 1
  394. resize_mode = 1
  395. print(original_image_path)
  396. GeneratePicPiJu().run(image_path=original_image_path,
  397. cut_image_path=original_move_bg_image_path,
  398. out_path=out_path,
  399. image_deal_mode=is_image_deal_mode,
  400. # resize_mode=resize_mode,
  401. out_pic_size=1600,
  402. is_logo=False,
  403. max_box=None
  404. )