image_deal_base_func.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import cv2
  2. import numpy as np
  3. from PIL import Image, ImageEnhance, ImageFilter, ImageOps
  4. import settings
  5. # 锐化图片
  6. def sharpen_image(img, factor=1.0):
  7. # 创建一个ImageEnhance对象
  8. enhancer = ImageEnhance.Sharpness(img)
  9. # 应用增强,值为0.0给出模糊图像,1.0给出原始图像,大于1.0给出锐化效果
  10. # 调整这个值来增加或减少锐化的程度
  11. sharp_img = enhancer.enhance(factor)
  12. return sharp_img
  13. def to_resize(_im, width=None, high=None) -> Image:
  14. _im_x, _im_y = _im.size
  15. if width and high:
  16. if _im_x >= _im_y:
  17. high = None
  18. else:
  19. width = None
  20. if width:
  21. re_x = int(width)
  22. re_y = int(_im_y * re_x / _im_x)
  23. else:
  24. re_y = int(high)
  25. re_x = int(_im_x * re_y / _im_y)
  26. _im = _im.resize((re_x, re_y),resample=settings.RESIZE_IMAGE_MODE)
  27. return _im
  28. def pil_to_cv2(pil_image):
  29. # 将 PIL 图像转换为 RGB 或 RGBA 格式
  30. if pil_image.mode != 'RGBA':
  31. pil_image = pil_image.convert('RGBA')
  32. # 将 PIL 图像转换为 numpy 数组
  33. cv2_image = np.array(pil_image)
  34. # 由于 PIL 的颜色顺序是 RGB,而 OpenCV 的颜色顺序是 BGR,因此需要交换颜色通道
  35. cv2_image = cv2.cvtColor(cv2_image, cv2.COLOR_RGBA2BGRA)
  36. return cv2_image
  37. def cv2_to_pil(cv_img):
  38. return Image.fromarray(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB))
  39. def get_mini_crop_img(img):
  40. old_x, old_y = img.size
  41. x1, y1, x2, y2 = img.getbbox()
  42. goods_w, goods_h = x2 - x1, y2 - y1
  43. _w, _h = int(goods_w / 10), int(goods_h / 10) # 上下左右扩展位置
  44. new_x1, new_y1, new_x2, new_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h # 防止超限
  45. new_x1 = 0 if new_x1 < 0 else new_x1
  46. new_y1 = 0 if new_y1 < 0 else new_y1
  47. new_x2 = old_x if new_x2 > old_x else new_x2
  48. new_y2 = old_y if new_y2 > old_y else new_y2
  49. img = img.crop((new_x1, new_y1, new_x2, new_y2)) # 切图
  50. box = (new_x1, new_y1, new_x2, new_y2)
  51. return img, box
  52. def expand_mask(mask, expansion_radius=5, blur_radius=0):
  53. # 对蒙版进行膨胀处理
  54. mask = mask.filter(ImageFilter.MaxFilter(expansion_radius * 2 + 1))
  55. # 应用高斯模糊滤镜
  56. if blur_radius > 0:
  57. mask = mask.filter(ImageFilter.GaussianBlur(blur_radius))
  58. return mask
  59. def find_lowest_non_transparent_points(cv2_png):
  60. # cv2_png 为cv2格式的带有alpha通道的图片
  61. alpha_channel = cv2_png[:, :, 3]
  62. """使用Numpy快速查找每列的最低非透明点"""
  63. h, w = alpha_channel.shape
  64. # 创建一个掩码,其中非透明像素为True
  65. mask = alpha_channel > 0
  66. # 使用np.argmax找到每列的第一个非透明像素的位置
  67. # 因为是从底部向上找,所以需要先翻转图像
  68. flipped_mask = np.flip(mask, axis=0)
  69. min_y_values = h - np.argmax(flipped_mask, axis=0) - 1
  70. # 将全透明列的值设置为-1
  71. min_y_values[~mask.any(axis=0)] = -1
  72. return min_y_values
  73. def draw_shifted_line(image, min_y_values, shift_amount=15,
  74. one_line_pos=(0, 100),
  75. line_color=(0, 0, 0),
  76. line_thickness=20):
  77. """
  78. image:jpg cv2格式的原始图
  79. min_y_values 透明图中,不透明区域的最低那条线
  80. shift_amount:向下偏移值
  81. line_color:线颜色
  82. line_thickness:线宽
  83. """
  84. # 将最低Y值向下迁移20个像素,但确保不超过图片的高度
  85. # 创建空白图片
  86. image = np.ones((image.shape[0], image.shape[1], 3), dtype=np.uint8) * 255
  87. # 对线条取转成图片
  88. shifted_min_y_values = np.clip(min_y_values + shift_amount, 0, image.shape[0] - 1)
  89. # 使用Numpy索引批量绘制直线
  90. min_y_threshold = 50 # Y轴像素小于50的不处理
  91. valid_x = (shifted_min_y_values >= min_y_threshold) & (shifted_min_y_values != -1)
  92. # 对曲线取平均值
  93. # # 对曲线取平均值
  94. # min_y = np.max(min_y_values)
  95. # min_y_values_2 = min_y_values + min_y
  96. # min_y_values_2 = min_y_values_2 / 2
  97. # min_y_values_2 = min_y_values_2.astype(int)
  98. # shifted_min_y_values = np.clip(min_y_values_2 + shift_amount, 0, image.shape[0] - 1)
  99. x_coords = np.arange(image.shape[1])[valid_x]
  100. y_start = shifted_min_y_values[valid_x]
  101. y_end = y_start + line_thickness
  102. # 使用Numpy广播机制创建线条区域的索引
  103. for x, start, end in zip(x_coords, y_start, y_end):
  104. image[start:end, x, :3] = line_color # 只修改RGB通道
  105. # 计算整个图像的最低非透明点
  106. lowest_y = np.max(min_y_values[min_y_values != -1]) if np.any(min_y_values != -1) else -1
  107. # 绘制原最低非透明点处的线
  108. cv2.line(image, (one_line_pos[0], lowest_y + 5), (one_line_pos[1], lowest_y + 5), line_color,
  109. thickness=line_thickness)
  110. _y = lowest_y + 18
  111. if _y > image.shape[0]: # 超过图片尺寸
  112. _y = image.shape[0] - 5
  113. return image, _y
  114. def clean_colors(img):
  115. # 转成灰度图
  116. img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  117. return img
  118. def calculated_shadow_brightness(img: Image):
  119. # 打开图片并转换为灰度模式
  120. image = img.convert('L')
  121. # 将图片数据转为numpy数组
  122. image_data = np.array(image)
  123. # 创建布尔掩码以识别非白色区域
  124. non_white_mask = image_data < 252
  125. # 使用掩码提取非白色像素的亮度值
  126. non_white_values = image_data[non_white_mask]
  127. # print(len(non_white_values),len(image_data))
  128. # 如果存在非白色像素,则计算平均亮度;否则返回0
  129. if len(non_white_values) > 0:
  130. average_brightness = np.mean(non_white_values)
  131. else:
  132. average_brightness = 0 # 没有非白色像素时的情况
  133. return average_brightness
  134. def levels_adjust(img, Shadow, Midtones, Highlight, OutShadow, OutHighlight, Dim):
  135. # 色阶处理
  136. # img 为cv2格式
  137. # dim = 3的时候调节RGB三个分量, 0调节B,1调节G,2调节R
  138. if Dim == 3:
  139. mask_shadow = img < Shadow
  140. img[mask_shadow] = Shadow
  141. mask_Highlight = img > Highlight
  142. img[mask_Highlight] = Highlight
  143. else:
  144. mask_shadow = img[..., Dim] < Shadow
  145. img[mask_shadow] = Shadow
  146. mask_Highlight = img[..., Dim] > Highlight
  147. img[mask_Highlight] = Highlight
  148. if Dim == 3:
  149. Diff = Highlight - Shadow
  150. rgbDiff = img - Shadow
  151. clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
  152. outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
  153. data = np.array(outClRgb * 255, dtype='uint8')
  154. img = data
  155. else:
  156. Diff = Highlight - Shadow
  157. rgbDiff = img[..., Dim] - Shadow
  158. clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
  159. outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
  160. data = np.array(outClRgb * 255, dtype='uint8')
  161. img[..., Dim] = data
  162. return img
  163. def calculate_average_brightness_opencv(img_gray, rows_to_check):
  164. # 二值化的图片 CV对象
  165. # 计算图片亮度
  166. height, width = img_gray.shape
  167. brightness_list = []
  168. for row in rows_to_check:
  169. if 0 <= row < height:
  170. # 直接计算该行的平均亮度
  171. row_data = img_gray[row, :]
  172. average_brightness = np.mean(row_data)
  173. brightness_list.append(average_brightness)
  174. else:
  175. print(f"警告:行号{row}超出图片范围,已跳过。")
  176. return brightness_list