image.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import os
  2. from flask import request, logging, send_file, jsonify
  3. from app import app
  4. from .resp import success_resp, error_resp
  5. import numpy as np
  6. from .req import ReplaceForm, is_empty
  7. import tools
  8. import cv2
  9. from .file import get_upload_file_path, get_output_dir, file_url, get_output_file_path, get_file_id, get_file_id_path
  10. from utils import color
  11. import time
  12. log = logging.create_logger(app)
  13. @app.route("/image/seg", methods=['POST'])
  14. def seg():
  15. if 'fileId' not in request.values:
  16. return "请先上传图片!", 500
  17. file_id = request.values.get('fileId')
  18. file_path = get_upload_file_path(file_id)
  19. _, fg, _, path = tools.seg(file_path, get_output_dir())
  20. # filename = os.path.relpath(path, OUTPUT_DIR)
  21. return jsonify(success_resp({
  22. "fileId": file_id,
  23. "url": file_url(path, True)
  24. }))
  25. @app.route("/image/replace", methods=["POST"])
  26. def replace():
  27. form_data = request.form
  28. form = ReplaceForm(form_data)
  29. if form.validate() is False:
  30. return jsonify(error_resp("参数错误!"))
  31. img_path = get_file_id_path(form.file_id.data)
  32. exist, alpha_path, path = tools.has_seg(img_path, get_output_dir())
  33. if exist:
  34. alpha = cv2.imread(alpha_path)
  35. fg = cv2.imread(path)
  36. else:
  37. alpha, fg, _, path = tools.seg(img_path, get_output_dir())
  38. if is_empty(form.bg_file_id.data) and is_empty(form.background.data):
  39. return jsonify(success_resp({
  40. "fileId": form.file_id.data,
  41. "url": file_url(path, True)
  42. }))
  43. bg_path = form.background.data
  44. if is_empty(form.bg_file_id.data) is False:
  45. bg_path = get_upload_file_path(form.bg_file_id.data)
  46. if os.path.exists(bg_path) is False:
  47. bg_path = form.background.data
  48. bg = color.get_bg(bg_path, fg.shape)
  49. if bg is None:
  50. return jsonify(success_resp({
  51. "fileId": form.file_id.data,
  52. "url": file_url(path, True)
  53. }))
  54. alpha = alpha / 255.0
  55. alpha = alpha[:, :, np.newaxis]
  56. com = alpha * fg + (1 - alpha) * bg
  57. com = com.astype('uint8')
  58. filename = os.path.basename(img_path)
  59. names = os.path.splitext(filename)
  60. save_name = "{}_{}{}".format(names[0], time.time(), names[1])
  61. com_save_path = os.path.join(get_output_dir(), save_name)
  62. cv2.imwrite(com_save_path, com)
  63. return jsonify(success_resp({
  64. "fileId": get_file_id(com_save_path, True),
  65. "url": file_url(com_save_path, True)
  66. }))
  67. @app.route("/image/resize", methods=["POST", 'GET'])
  68. def resize():
  69. # flip: 翻转, 0 为沿X轴翻转,正数为沿Y轴翻转,负数为同时沿X轴和Y轴翻转
  70. # reset: 是否重头开始,否则从上一次的处理开始,默认为重头开始
  71. # resize: 重新设定尺寸
  72. # rect: 裁剪,left,top,right,bottom 四个参数
  73. reset = request.values.get("reset")
  74. file_id = request.values.get("fileId")
  75. width = request.values.get("width")
  76. height = request.values.get("height")
  77. rotate = request.values.get("rotate")
  78. flip = request.values.get("flip")
  79. rect = request.values.get('rect')
  80. save = request.values.get('onSave')
  81. download = request.values.get('download')
  82. save = is_empty(save) is False
  83. download = is_empty(download) is False
  84. if is_empty(reset):
  85. reset = True
  86. else:
  87. reset = False
  88. file_path = get_file_id_path(file_id)
  89. is_get = request.method.upper() == "GET"
  90. if os.path.exists(file_path) is not True:
  91. return "文件上传失败,请重新上传!" if is_get else jsonify(error_resp("文件上传失败,请重新上传")), 400
  92. out_file = get_output_file_path(file_id, "resize")
  93. if reset is False and os.path.exists(out_file):
  94. img = cv2.imread(out_file)
  95. else:
  96. img = cv2.imread(file_path)
  97. origin_h = img.shape[0]
  98. origin_w = img.shape[1]
  99. dst, r_w, r_h = crop(img, rect, origin_w, origin_h)
  100. change_size = True
  101. if is_empty(width) and is_empty(height):
  102. change_size = False
  103. if change_size:
  104. if is_empty(width):
  105. h = int(height)
  106. w = round(h * origin_w / origin_h)
  107. elif is_empty(height):
  108. w = int(width)
  109. h = round(w * origin_h / origin_w)
  110. else:
  111. w = int(width)
  112. h = int(height)
  113. origin = img if dst is None else dst
  114. dst = cv2.resize(origin, (w, h))
  115. r_w = w
  116. r_h = h
  117. if r_w is None:
  118. r_w = origin_w
  119. if r_h is None:
  120. r_h = origin_h
  121. if is_empty(flip) is not True:
  122. flip = int(flip)
  123. origin = img if dst is None else dst
  124. dst = cv2.flip(origin, flip)
  125. if is_empty(rotate) is False and int(rotate) != 0:
  126. origin = img if dst is None else dst
  127. dst, new_w, new_h = rot_degree(origin, float(rotate), w=r_w, h=r_h)
  128. if new_w is not None:
  129. r_w = new_w
  130. r_h = new_h
  131. result_path = file_path
  132. if dst is not None:
  133. cv2.imwrite(out_file, dst)
  134. result_path = out_file
  135. else:
  136. dst = img
  137. if save:
  138. result_path = get_output_file_path(file_id)
  139. cv2.imwrite(result_path, dst)
  140. if is_get:
  141. mimetype = 'application/octet-stream' if download else 'image/png'
  142. return send_file(result_path, mimetype=mimetype)
  143. return jsonify(success_resp({
  144. "fileId": get_file_id(result_path, True),
  145. "url": file_url(result_path, True),
  146. "width": r_w,
  147. "height": r_h,
  148. }))
  149. def crop(img, rect: str, w, h):
  150. # 裁剪,
  151. # 如果没有改变,返回None
  152. if is_empty(rect):
  153. return None, None, None
  154. r = rect.split(',')
  155. if len(r) != 4:
  156. return None, None, None
  157. left = int(r[0])
  158. top = int(r[1])
  159. right = int(r[2])
  160. bottom = int(r[3])
  161. if left < 0:
  162. left = 0
  163. if right > w:
  164. right = w
  165. if top < 0:
  166. top = 0
  167. if bottom > h:
  168. bottom = h
  169. if left == 0 and top == 0 and right == w and bottom == h:
  170. return None, None, None
  171. return img[top:bottom, left:right], right-left, bottom-top
  172. def rot_degree(img, degree, w, h):
  173. center = (w / 2, h / 2)
  174. M = cv2.getRotationMatrix2D(center, degree, 1)
  175. top_right = np.array((w - 1, 0)) - np.array(center)
  176. bottom_right = np.array((w - 1, h - 1)) - np.array(center)
  177. top_right_after_rot = M[0:2, 0:2].dot(top_right)
  178. bottom_right_after_rot = M[0:2, 0:2].dot(bottom_right)
  179. new_width = max(int(abs(bottom_right_after_rot[0] * 2) + 0.5), int(abs(top_right_after_rot[0] * 2) + 0.5))
  180. new_height = max(int(abs(top_right_after_rot[1] * 2) + 0.5), int(abs(bottom_right_after_rot[1] * 2) + 0.5))
  181. offset_x = (new_width - w) / 2
  182. offset_y = (new_height - h) / 2
  183. M[0, 2] += offset_x
  184. M[1, 2] += offset_y
  185. dst = cv2.warpAffine(img, M, (new_width, new_height))
  186. return dst, new_width, new_height