123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- import math
- import cmath
- import traceback
- import numpy as np
- import cv2
- # 图片旋转
- from format_convert.judge_platform import get_platform
- def rotate_bound(image, angle):
- try:
- # 获取宽高
- (h, w) = image.shape[:2]
- (cX, cY) = (w // 2, h // 2)
- # 提取旋转矩阵 sin cos
- M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
- cos = np.abs(M[0, 0])
- sin = np.abs(M[0, 1])
- # 计算图像的新边界尺寸
- nW = int((h * sin) + (w * cos))
- # nH = int((h * cos) + (w * sin))
- nH = h
- # 调整旋转矩阵
- M[0, 2] += (nW / 2) - cX
- M[1, 2] += (nH / 2) - cY
- return cv2.warpAffine(image, M, (nW, nH),flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
- except Exception as e:
- print("rotate_bound", e)
- # 获取图片旋转角度
- def get_minAreaRect(image):
- try:
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
- ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
- if get_platform() == "Windows":
- cv2.imshow("binary", binary)
- cv2.waitKey(0)
- contours, hier = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
- # 绘制矩形
- cv2.drawContours(image, contours, 0, (255, 0, 255), 3)
- if get_platform() == "Windows":
- cv2.imshow("image", image)
- cv2.waitKey(0)
- for c in contours: #遍历轮廓
- rect = cv2.minAreaRect(c) #生成最小外接矩形
- box_ = cv2.boxPoints(rect)
- h = abs(box_[3, 1] - box_[1, 1])
- w = abs(box_[3, 0] - box_[1, 0])
- print("宽,高", w, h)
- # 只保留需要的轮廓
- if h > 3000 or w > 2200:
- continue
- if h < 2500 or w < 1500:
- continue
- # 计算最小面积矩形的坐标
- box = cv2.boxPoints(rect)
- # 将坐标规范化为整数
- box = np.int0(box)
- # 获取矩形相对于水平面的角度
- angle = rect[2]
- if angle > 0:
- if abs(angle) > 45:
- angle = 90 - abs(angle)
- else:
- if abs(angle) > 45:
- angle = (90 - abs(angle))
- print("轮廓数量", len(contours))
- return image, box, angle
- except Exception as e:
- print("get_minAreaRect", traceback.print_exc())
- return [-1], [-1], [-1]
- def get_table_line(image):
- # 二值化
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
- binary = cv2.adaptiveThreshold(~gray, 255,
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 203, -10)
- # cv2.imshow("cell", binary)
- # cv2.waitKey(0)
- # 轮廓
- kernel_row = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], np.float32)
- kernel_col = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], np.float32)
- # Sobel
- # kernel_row = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], np.float32)
- # kernel_col = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], np.float32)
- # binary = cv2.filter2D(binary, -1, kernel=kernel)
- binary_row = cv2.filter2D(binary, -1, kernel=kernel_row)
- binary_col = cv2.filter2D(binary, -1, kernel=kernel_col)
- # cv2.imshow("custom_blur_demo", binary)
- # cv2.waitKey(0)
- # rows, cols = binary.shape
- # scale = 20
- # # 识别横线
- # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (cols//scale, 1))
- # erodedcol = cv2.erode(binary_row, kernel, iterations=1)
- # cv2.imshow("Eroded Image", erodedcol)
- # cv2.waitKey(0)
- # dilatedcol = cv2.dilate(erodedcol, kernel, iterations=3)
- # cv2.imshow("Dilated Image", dilatedcol)
- # cv2.waitKey(0)
- #
- # # 识别竖线
- # scale = 20
- # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, rows//scale))
- # erodedrow = cv2.erode(binary_col, kernel, iterations=1)
- # cv2.imshow("Eroded Image", erodedrow)
- # cv2.waitKey(0)
- # dilatedrow = cv2.dilate(erodedrow, kernel, iterations=3)
- # cv2.imshow("Dilated Image", dilatedrow)
- # cv2.waitKey(0)
- #
- # # 标识表格
- # merge = cv2.add(dilatedcol, dilatedrow)
- # cv2.imshow("add Image", merge)
- # cv2.imwrite('table_outline.jpg', merge)
- # cv2.waitKey(0)
- return binary_row
- def detect_line(img):
- try:
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- edges = cv2.Canny(gray, 100, 1000)
- # cv2.imshow("edges", edges)
- # cv2.waitKey(0)
- lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
- if lines is None or len(lines) == 0:
- return 0
- angle_list = []
- for i in range(len(lines)):
- # 第一个元素是距离rho
- rho = lines[i][0][0]
- # 第二个元素是角度theta
- theta = lines[i][0][1]
- a = np.cos(theta)
- b = np.sin(theta)
- x0 = a*rho
- y0 = b*rho
- x1 = float(x0 + 1000*(-b))
- y1 = float(y0 + 1000*a)
- x2 = float(x0 - 1000*(-b))
- y2 = float(y0 - 1000*a)
- if x2-x1 == 0 or y2-y1 == 0 or x2-x1 <= 0.01 or y2-y1 <= 0.01:
- continue
- k = -(y2-y1) / (x2-x1)
- if abs(k) <= 5:
- # h = math.atan(k)
- # angle = math.degrees(h)
- angle = np.arctan(k) * (180/math.pi)
- # 调整
- angle_list.append(angle)
- # print(angle)
- # cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
- angle_sum = 0
- for a in angle_list:
- angle_sum += a
- angle_avg = angle_sum/len(angle_list)
- print("angle_avg", angle_avg)
- return angle_avg
- except Exception as e:
- print("detect_line", e)
- def get_rotated_image_old(image, output_path):
- try:
- angle = detect_line(image)
- if angle != 0:
- rotated = rotate_bound(image, angle)
- # cv2.putText(rotated, "angle: {:.3f} ".format(angle),
- # (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
- # show the output image
- # cv2.imshow("imput", image)
- # cv2.waitKey(0)
- # cv2.imshow("output", rotated)
- # cv2.waitKey(0)
- print("[INFO] angle: {:.3f}".format(angle))
- cv2.imwrite(output_path, rotated)
- return True
- else:
- print("angle", angle)
- return False
- except Exception as e:
- print("get_rotated_image", e)
- return False
- def rotate_bound(image, angle):
- # 获取宽高
- (h, w) = image.shape[:2]
- (cX, cY) = (w // 2, h // 2)
- # 提取旋转矩阵 sin cos
- M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
- cos = np.abs(M[0, 0])
- sin = np.abs(M[0, 1])
- # 计算图像的新边界尺寸
- nW = int((h * sin) + (w * cos))
- # nH = int((h * cos) + (w * sin))
- nH = h
- # 调整旋转矩阵
- M[0, 2] += (nW / 2) - cX
- M[1, 2] += (nH / 2) - cY
- return cv2.warpAffine(image, M, (nW, nH),flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
- # 获取图片旋转角度
- def get_minAreaRect(image):
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
- gray = cv2.bitwise_not(gray)
- thresh = cv2.threshold(gray, 0, 255,
- cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
- coords = np.column_stack(np.where(thresh > 0))
- return cv2.minAreaRect(coords)
- def get_rotated_image(image, output_path):
- try:
- image_temp, box, angle = get_minAreaRect(image)
- if angle == [-1]:
- return [-1]
- # angle = get_minAreaRect(image)[-1]
- if abs(angle) >= 15:
- angle = 0
- rotated = rotate_bound(image, angle)
- # cv2.putText(rotated, "angle: {:.2f} ".format(angle),
- # (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
- # show the output image
- # print("[INFO] angle: {:.3f}".format(angle))
- if not angle:
- cv2.imwrite(output_path, rotated)
- # cv2.imshow("input", image)
- # cv2.waitKey(0)
- # cv2.imshow("output", rotated)
- # cv2.waitKey(0)
- return True
- except cv2.error:
- traceback.print_exc()
- return [-3]
- except Exception as e:
- traceback.print_exc()
- return [-1]
- if __name__ == '__main__':
- temp_path = "temp/complex/8.png"
- # temp_path = "temp/92d885dcb77411eb914300163e0ae709/92d8ef5eb77411eb914300163e0ae709_pdf_page1.png"
- image = cv2.imread(temp_path)
- get_rotated_image(image, temp_path)
- # test()
|