讨论数量:
先识别出轮廓,然后比大小,也可以换个思路,比面积
import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog
from skimage.filters import threshold_local # 确保已安装scikit-image库
def find_document(image_path):
image = cv2.imread(image_path)
if image is None:
print("Image not loaded.")
return None
# 转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
# Canny边缘检测,这里可以调整阈值
edged = cv2.Canny(gray, 75, 200)
# 轮廓检测
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
screenCnt = None
# 遍历轮廓
for c in contours:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 如果轮廓有四个点,我们认为找到了文档
if len(approx) == 4:
screenCnt = approx
break
if screenCnt is None:
print("No document contour found.")
# 在这里,您可以允许用户手动选择角点或返回
return None
# 如果找到了轮廓,应用透视变换
warped = four_point_transform(image, screenCnt.reshape(4, 2))
return warped
def order_points(pts):
# 初始化一个坐标点,按照左上,右上,右下,左下的顺序
rect = np.zeros((4, 2), dtype="float32")
# 左上点的坐标和右下点的坐标分别是x+y的最小值和最大值
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# 计算右上点和左下点的坐标,分别是x-y的最小值和最大值
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
# 返回排序后的坐标点
return rect
def four_point_transform(image, pts):
# 获取坐标点,并将它们分别排列成左上,右上,右下,左下的顺序
rect = order_points(pts)
(tl, tr, br, bl) = rect
# 计算输入的宽度和高度
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
# 计算输出图像的坐标点,并应用透视变换
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype="float32")
# 获取透视变换矩阵,并应用它
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
# 返回变换后的图像
return warped
def find_document(image_path):
image = cv2.imread(image_path)
if image is None:
print("Image not loaded.")
return None
# Convert to grayscale and blur the image slightly
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
# Perform edge detection
edged = cv2.Canny(gray, 75, 200)
# Find contours and sort them by size
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
screenCnt = None
# Loop over the contours
for c in contours:
# Approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# If our approximated contour has four points, then we
# can assume we have found the document
if len(approx) == 4:
screenCnt = approx
break
if screenCnt is None:
print("No document contour found.")
return None
# Apply a perspective transform to obtain the top-down view of the document
warped = four_point_transform(image, screenCnt.reshape(4, 2))
return warped
def process_image(file_path):
if file_path:
processed_image = find_document(file_path)
if processed_image is not None and processed_image.size > 0:
cv2.imshow("Processed Document", processed_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
save_path = file_path.rsplit('.', 1)[0] + '_processed.jpg'
cv2.imwrite(save_path, processed_image)
print(f"Processed image saved to {save_path}")
else:
print("图像处理失败或图像为空。")
def select_image():
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename()
root.destroy() # 关闭Tkinter窗口
process_image(file_path)
def main():
# 创建Tkinter窗口
root = tk.Tk()
root.title("选择文件")
# 创建一个按钮来选择图像文件
select_button = tk.Button(root, text="选择图片", command=select_image)
select_button.pack()
# 运行Tkinter事件循环
root.mainloop()
if __name__ == "__main__":
main()
推荐文章: