123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import cv2
- from time import time
- import numpy as np
- from compress import compress_image
- BorderWidth = 5
- def isWhiteBorder(img: "np.ndarray") -> "bool":
- row = np.concatenate([img[:BorderWidth], img[-BorderWidth:]], axis=0).reshape((BorderWidth * 2, -1))
- col = np.concatenate([img[:, :BorderWidth], img[:, -BorderWidth:]], axis=1).reshape((BorderWidth * 2, -1))
- full = np.concatenate([row, col], axis=1)
- return np.average(full) > 127
- def resize(img: "np.ndarray", height: "int" = None, width: "int" = None) -> "np.ndarray":
- if height is None and width is None:
- return img
- h, w = img.shape[:2]
- if height is not None:
- dim = int(w * height / h), height
- else:
- dim = width, int(h * width / w)
- return cv2.resize(img, dim, interpolation=cv2.INTER_AREA) # noqa
- def distance(pa: "list", pb: "list") -> "float":
- return np.sqrt((pa[0] - pb[0]) ** 2 + (pa[1] - pb[1]) ** 2)
- def rect_area(points: "np.ndarray") -> "float":
- return distance(points[0], points[1]) * distance(points[0], points[3])
- def transform(img: "np.ndarray", points: "np.ndarray") -> "np.ndarray":
- tl, bl, br, tr = points
- width = int(max(distance(tl, tr), distance(bl, br)))
- height = int(max(distance(tl, bl), distance(tr, br)))
- rect = np.array([tl, tr, bl, br], dtype="float32")
- dest = np.array(
- [[0, 0], [width - 1, 0],
- [0, height - 1], [width - 1, height - 1]],
- dtype="float32"
- )
- matrix = cv2.getPerspectiveTransform(rect, dest)
- return cv2.warpPerspective(img, matrix, (width, height))
- def preprocess(img: "np.ndarray") -> "np.ndarray":
- # img = compress_image(img, 1000 * 600)
- # img = resize(img, height=500)
- # RGB -> gray
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- # 二值化
- thresh_type = cv2.THRESH_BINARY
- if isWhiteBorder(gray):
- thresh_type = cv2.THRESH_BINARY_INV
- _, thresh = cv2.threshold(gray, 158, 255, thresh_type)
- # 边缘检测
- contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
- if not contours:
- return img
- max_contour = max(contours, key=cv2.contourArea) # noqa 找到最大的轮廓
- # 图像校正
- approx = cv2.approxPolyDP(max_contour, 0.02 * cv2.arcLength(max_contour, True), True)
- if len(approx) == 4: # 较为规则,可以校正
- return transform(gray, approx.reshape(4, 2))
- else: # 不太规则,尝试裁剪
- rect = cv2.minAreaRect(max_contour) # noqa 计算最小外接矩形
- box = np.intp(cv2.boxPoints(rect)) # noqa 获取矩形的四个角点
- if rect_area(box) * 5 < img.shape[0] * img.shape[1]:
- return img
- return img[min(box[:, 1]):max(box[:, 1]), min(box[:, 0]):max(box[:, 0])]
- def main():
- # TODO 10 18
- import os
- dd = r"C:\Users\huimv\Pictures\Saved Pictures"
- for name in os.listdir(dd):
- if name.endswith(".ini"):
- continue
- img = cv2.imread(rf"{dd}\{name}")
- st = time()
- deal = preprocess(img)
- print(name, time() - st)
- cv2.imshow(name, deal)
- if __name__ == '__main__':
- main()
|