util.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import cv2
  2. import numpy as np
  3. from PIL import Image
  4. from io import BytesIO
  5. from typing import Union
  6. from flask import jsonify
  7. from random import randint
  8. from hmOCR import HuiMvOCR, Args
  9. from time import localtime, strftime
  10. __all__ = [
  11. "Response", "rand_str", "current_time", "get_ext_name", "is_image_ext",
  12. "str_include", "read_img", "compress_img", "crop_img", "rot_img", "save_img",
  13. "Engine"
  14. ]
  15. __StrBase = "qwertyuioplkjhgfdsazxcvbnm1234567890ZXCVBNMLKJHGFDSAQWERTYUIOP"
  16. __StrBaseLen = len(__StrBase) - 1
  17. __MaxImageSize = 3500 * 2000
  18. __BorderWidth = 5
  19. __AcceptExtNames = ["jpg", "jpeg", "bmp", "png", "rgb", "tif", "tiff", "gif"]
  20. Engine = HuiMvOCR(Args())
  21. def __isWhiteBack(img: "np.ndarray") -> "bool":
  22. row = np.concatenate([img[:__BorderWidth], img[-__BorderWidth:]], axis=0).reshape((__BorderWidth * 2, -1))
  23. col = np.concatenate([img[:, :__BorderWidth], img[:, -__BorderWidth:]], axis=1).reshape((__BorderWidth * 2, -1))
  24. full = np.concatenate([row, col], axis=1)
  25. return np.average(full) > 127
  26. def Response(message: "str" = None, data=None):
  27. if message is None:
  28. return jsonify(success=True, message="操作成功", data=data)
  29. return jsonify(success=False, message=message, data=data)
  30. def rand_str(size: "int" = 8) -> "str":
  31. return "".join([__StrBase[randint(0, __StrBaseLen)] for _ in range(size)])
  32. def current_time() -> "str":
  33. return strftime("%Y-%m-%d_%H-%M-%S", localtime())
  34. def get_ext_name(name: "str") -> "str":
  35. return name.split(".")[-1].lower()
  36. def is_image_ext(ext: "str") -> bool:
  37. return ext in __AcceptExtNames
  38. def str_include(str_long: "str", str_short: "str") -> "bool":
  39. for it in str_short:
  40. if it not in str_long:
  41. return False
  42. return True
  43. def read_img(content: "str") -> "np.ndarray":
  44. return cv2.imdecode(np.frombuffer(content, np.uint8), 1) # noqa
  45. def compress_img(img: "np.ndarray", tar_size: "int" = __MaxImageSize) -> "np.ndarray":
  46. cur_size = img.shape[0] * img.shape[1]
  47. if cur_size <= tar_size:
  48. return img
  49. image = Image.fromarray(img)
  50. output = BytesIO()
  51. image.save(output, format="JPEG", quality=int(tar_size / cur_size * 100))
  52. output.seek(0)
  53. compressed_image = Image.open(output)
  54. return np.array(compressed_image)
  55. def crop_img(image: "np.ndarray") -> "np.ndarray":
  56. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # noqa 将图像转换为灰度图像
  57. thresh_type = cv2.THRESH_BINARY # noqa
  58. if __isWhiteBack(gray):
  59. thresh_type = cv2.THRESH_BINARY_INV # noqa
  60. _, threshold = cv2.threshold(gray, 155, 255, thresh_type) # noqa 换为二值图像 => save: [150,255]
  61. contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # noqa 查找轮廓
  62. if not contours:
  63. return image
  64. max_contour = max(contours, key=cv2.contourArea) # noqa 找到最大的轮廓
  65. rect = cv2.minAreaRect(max_contour) # noqa 计算最小外接矩形
  66. box = cv2.boxPoints(rect) # noqa 获取矩形的四个角点
  67. box = np.intp(box)
  68. # 裁剪图像
  69. return image[min(box[:, 1]):max(box[:, 1]), min(box[:, 0]):max(box[:, 0])]
  70. def rot_img(img: "np.ndarray") -> "list[np.ndarray]":
  71. return [img, np.rot90(img), np.rot90(img, 2), np.rot90(img, 3)]
  72. def save_img(filename: "str", content: "Union[bytes, np.ndarray]"):
  73. if isinstance(content, np.ndarray):
  74. return cv2.imwrite(filename, content) # noqa
  75. with open(filename, "wb") as fp:
  76. fp.write(content)
  77. fp.close()