123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- import os
- import numpy as np
- import cv2
- def is_empty(s: str):
- return s is None or len(str(s)) == 0
- def to_int(s: str):
- if isinstance(s, (int, float)):
- return s
- if is_empty(s):
- return None
- return int(str(s))
- def to_size_int(s: str):
- v = to_int(s)
- if v is None:
- return v
- if v < 1:
- return None
- return v
- class NotImageError(Exception):
- def __init__(self):
- super().__init__("File Is Not Image")
- class ProcessorParams:
- def __init__(self, width, height, rotate, flip, rect, out_dir, path):
- self.width = width
- self.height = height
- self.rotate = rotate
- # 翻转, 0 为沿X轴翻转,正数为沿Y轴翻转,负数为同时沿X轴和Y轴翻转
- self.flip = flip
- # 裁剪,left,top,right,bottom 四个参数
- self.rect = rect
- # 保存的文件夹
- self.out_dir = out_dir
- self.path = path
- def set_path(self, path, out_dir):
- self.path = path
- self.out_dir = out_dir
- def processor(params: ProcessorParams):
- file_path = params.path
- if os.path.exists(file_path) is not True:
- raise FileNotFoundError('Need to give the source path.')
- if not os.path.exists(params.out_dir):
- os.makedirs(params.out_dir)
- img = cv2.imread(file_path)
- if img is None:
- raise NotImageError()
- origin_h = img.shape[0]
- origin_w = img.shape[1]
- dst, r_w, r_h = crop(img, params.rect, origin_w, origin_h)
- width = to_size_int(params.width)
- height = to_size_int(params.height)
- change_size = True
- if width is None and height is None:
- change_size = False
- if change_size:
- if width is None:
- h = height
- w = round(h * origin_w / origin_h)
- elif height is None:
- w = width
- h = round(w * origin_h / origin_w)
- else:
- w = width
- h = height
- origin = img if dst is None else dst
- dst = cv2.resize(origin, (w, h))
- r_w = w
- r_h = h
- if r_w is None:
- r_w = origin_w
- if r_h is None:
- r_h = origin_h
- flip = params.flip
- if is_empty(flip) is not True:
- flip = to_int(flip)
- origin = img if dst is None else dst
- dst = cv2.flip(origin, flip)
- rotate = params.rotate
- if is_empty(rotate) is False and to_int(rotate) != 0:
- origin = img if dst is None else dst
- dst, new_w, new_h = rot_degree(origin, float(rotate), w=r_w, h=r_h)
- origin_filename = os.path.basename(file_path)
- out_file = os.path.join(params.out_dir, origin_filename)
- if dst is not None:
- cv2.imwrite(out_file, dst)
- return True
- return False
- def crop(img, rect: str, w, h):
- # 裁剪,
- # 如果没有改变,返回None
- if is_empty(rect):
- return None, None, None
- r = rect.split(',')
- if len(r) != 4:
- return None, None, None
- left = int(r[0])
- top = int(r[1])
- right = int(r[2])
- bottom = int(r[3])
- if left < 0:
- left = 0
- if right > w:
- right = w
- if top < 0:
- top = 0
- if bottom > h:
- bottom = h
- if left == 0 and top == 0 and right == w and bottom == h:
- return None, None, None
- return img[top:bottom, left:right], right - left, bottom - top
- def rot_degree(img, degree, w, h):
- center = (w / 2, h / 2)
- M = cv2.getRotationMatrix2D(center, degree, 1)
- top_right = np.array((w - 1, 0)) - np.array(center)
- bottom_right = np.array((w - 1, h - 1)) - np.array(center)
- top_right_after_rot = M[0:2, 0:2].dot(top_right)
- bottom_right_after_rot = M[0:2, 0:2].dot(bottom_right)
- new_width = max(int(abs(bottom_right_after_rot[0] * 2) + 0.5), int(abs(top_right_after_rot[0] * 2) + 0.5))
- new_height = max(int(abs(top_right_after_rot[1] * 2) + 0.5), int(abs(bottom_right_after_rot[1] * 2) + 0.5))
- offset_x = (new_width - w) / 2
- offset_y = (new_height - h) / 2
- M[0, 2] += offset_x
- M[1, 2] += offset_y
- dst = cv2.warpAffine(img, M, (new_width, new_height))
- return dst, new_width, new_height
|