From ca9c39205383647bdf910493906096a2419e4aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E5=BF=97=E8=BF=9C?= <14347000+guan-zhiyuan2@user.noreply.gitee.com> Date: Sat, 29 Jun 2024 04:59:25 +0000 Subject: [PATCH] update doc_scanner.py. 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 关志远 <14347000+guan-zhiyuan2@user.noreply.gitee.com> --- doc_scanner.py | 67 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/doc_scanner.py b/doc_scanner.py index dd43090..5b79afc 100644 --- a/doc_scanner.py +++ b/doc_scanner.py @@ -1,15 +1,3 @@ -''' -"doc_scanner.py" 文件中的 DocScanner 类提供了文档扫描的核心功能,功能包括 - - 加载图片 - - 找到文档的角落 - - 裁剪图片 - -- 通过将文档扫描功能封装在一个独立的类中,我们可以将其作为一个模块,方便在其他项目中重用。 -- 这种模块化的设计使得代码更加模块化、可扩展和可测试。 -- 它可以独立于其他部分进行开发、测试和维护,而不会对其他组件产生影响。 -- 此外,将文档扫描功能单独放在一个文件中,使得代码结构更清晰、易于理解和维护。 -- 通过将不同的功能分割到不同的文件中,我们可以更好地组织代码,减少文件的复杂性,并促进团队合作开发。 -''' import cv2 as cv # 导入 OpenCV 库,用于图片处理和计算机视觉任务 import numpy as np # 导入 numpy 库,用于进行数值计算 @@ -19,20 +7,23 @@ class DocScanner: def load_image(self, file_path): """加载图片并找到文档的四个角落。""" - img = #TODO # 读取图片 - img_gray = #TODO # 将图片转换为灰度图 + img = cv.imread(file_path) # 读取图片 + img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 将图片转换为灰度图 # 对灰度图进行二值化,得到二值图 - thresh, binary_img = #TODO + thresh, binary_img = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU) # 找到二值图的所有轮廓 - contours, hierarchy = #TODO - - # 找到最大的周长的四边形的四个顶点 extreme_pnts - #TODO - + contours, hierarchy = cv.findContours(binary_img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + al_max = 0 # 初始化最大轮廓的周长为 0 + for c in contours: # 遍历所有轮廓 + al = cv.arcLength(c, True) # 计算轮廓的周长 + approx = cv.approxPolyDP(c, 0.1 * al, True) # 对轮廓进行多边形拟合 + if len(approx) == 4: # 如果拟合的多边形是四边形 + if al > al_max: # 如果周长大于当前的最大周长 + al_max = al # 更新最大周长 + extreme_pnts = approx # 保存四边形的四个顶点, 注意这四个顶点都是(y,x)即(h,w)的结果 corners = self.order_points(extreme_pnts.reshape(4, 2)) # 对四个顶点进行排序 return img, corners # 返回图片和排序后的顶点 - def order_points(self, pts): """对给定的四个点进行排序,返回排序后的点。""" rect = np.zeros((4, 2), dtype="float32") # 初始化排序后的点为全零 @@ -43,34 +34,42 @@ class DocScanner: rect[1] = pts[np.argmin(diff)] # 右上角的点坐标差最小的那个点 rect[3] = pts[np.argmax(diff)] # 左下角的点坐标差最大的那个点 - print(f"0:左上角:{rect[0]},因为x,y的坐标和是: np.min(s)={np.min(s)}") - print(f"1:右上角:{rect[1]},因为x,y的坐标差是: np.min(diff)={np.min(diff)}") - print(f"2:右下角:{rect[2]},因为x,y的坐标和是: np.max(s)={np.max(s)}") - print(f"3:左下角:{rect[3]},因为x,y的坐标差是: np.max(diff)={np.max(diff)}") - return rect # 返回排序后的点 - def crop_image(self, img, corners): """根据四个角落裁剪图片。""" - top_left_corner = corners[0] top_right_corner = corners[1] bottom_right_corner = corners[2] bottom_left_corner = corners[3] # 计算目标图片的宽度和高度 - width, height = self.get_image_dimensions((top_left_corner, top_right_corner, bottom_right_corner, bottom_left_corner)) + width, height = self.get_image_dimensions((top_left_corner, top_right_corner, bottom_right_corner, bottom_left_corner)) # 根据以上宽度和高度创建于原有四个点顺序对应的目标四个点的坐标 - dst_points = #TODO - + dst_points = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]], dtype=np.float32) + # 通过投影变换展平文档 - # TODO + matrix = cv.getPerspectiveTransform(np.array([top_left_corner, top_right_corner, bottom_right_corner, bottom_left_corner], dtype=np.float32), dst_points) + dst = cv.warpPerspective(img, matrix, (width, height)) + return dst # 返回展平后的图像 def get_image_dimensions(self, corners): """计算图片的宽度和高度。""" - #TODO + # 计算图片宽度为左上角到右上角的距离,图片高度为左上角到左下角的距离 + width = int(np.sqrt((corners[1][0] - corners[0][0]) ** 2 + (corners[1][1] - corners[0][1]) ** 2)) + height = int(np.sqrt((corners[3][0] - corners[0][0]) ** 2 + (corners[3][1] - corners[0][1]) ** 2)) + return width, height + + +if __name__ == "__main__": + scanner = DocScanner() + img_path = 'doc.jpg' # 替换为你的图片路径 + img, corners = scanner.load_image(img_path) + cropped_img = scanner.crop_image(img, corners) - \ No newline at end of file + # 可以将 cropped_img 显示出来或者进行其他后续处理 + cv.imshow('Cropped Image', cropped_img) + cv.waitKey(0) + cv.destroyAllWindows() -- Gitee