代码拉取完成,页面将自动刷新
同步操作将从 mynameisi/doc_scanner_homework 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
'''
"doc_scanner.py" 文件中的 DocScanner 类提供了文档扫描的核心功能,功能包括
- 加载图片
- 找到文档的角落
- 裁剪图片
- 通过将文档扫描功能封装在一个独立的类中,我们可以将其作为一个模块,方便在其他项目中重用。
- 这种模块化的设计使得代码更加模块化、可扩展和可测试。
- 它可以独立于其他部分进行开发、测试和维护,而不会对其他组件产生影响。
- 此外,将文档扫描功能单独放在一个文件中,使得代码结构更清晰、易于理解和维护。
- 通过将不同的功能分割到不同的文件中,我们可以更好地组织代码,减少文件的复杂性,并促进团队合作开发。
'''
import cv2 as cv # 导入 OpenCV 库,用于图片处理和计算机视觉任务
import numpy as np # 导入 numpy 库,用于进行数值计算
class DocScanner:
def __init__(self):
pass # DocScanner 的初始化方法,目前为空
def load_image(self, file_path):
"""加载图片并找到文档的四个角落。"""
img = cv.imread(file_path) # 读取图片
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 将图片转换为灰度图
# 对灰度图进行二值化,得到二值图
thresh, binary_img = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
# 找到二值图的所有轮廓
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") # 初始化排序后的点为全零
s = pts.sum(axis=1) # 计算每个点的坐标和
rect[0] = pts[np.argmin(s)] # 左上角的点坐标和最小的那个点
rect[2] = pts[np.argmax(s)] # 右下角的点坐标和最大的那个点
diff = np.diff(pts, axis=1) # 计算每个点的坐标差
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))
# 根据以上宽度和高度创建于原有四个点顺序对应的目标四个点的坐标
dst_points = np.array([
[0, 0],
[width - 1, 0],
[width - 1, height - 1],
[0, height - 1]], dtype="float32")
M = cv.getPerspectiveTransform(corners, dst_points) # 计算透视变换矩阵
dst = cv.warpPerspective(img, M, (width, height)) # 对图片进行透视变换
return dst # 返回展平后的图像
def get_image_dimensions(self, corners):
"""计算图片的宽度和高度。"""
top_left_corner = corners[0]
top_right_corner = corners[1]
bottom_right_corner = corners[2]
bottom_left_corner = corners[3]
width_top = np.linalg.norm(top_right_corner - top_left_corner) # 计算图片顶部的宽度
width_bottom = np.linalg.norm(bottom_right_corner - bottom_left_corner) # 计算图片底部的宽度
width = max(width_top, width_bottom) # 取顶部和底部宽度的最大值作为图片的宽度
height_right = np.linalg.norm(bottom_right_corner - top_right_corner) # 计算图片右侧的高度
height_left = np.linalg.norm(bottom_left_corner - top_left_corner) # 计算图片左侧的高度
height = max(height_right, height_left) # 取左侧和右侧高度的最大值作为图片的高度
return int(width), int(height) # 返回图片的宽度和高度
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。