可以使用OpenCV实现的图像校正算法,包含透视校正和旋转校正的步骤,并附有详细注释。
具体如下:
import cv2
import numpy as np
def order_points(pts):
"""
将四个点按左上、右上、右下、左下顺序排列
"""
rect = np.zeros((4, 2), dtype="float32")
# 按x坐标排序,分左右两组
x_sorted = pts[np.argsort(pts[:, 0]), :]
left = x_sorted[:2, :]
right = x_sorted[2:, :]
# 左组按y坐标排序(左上,左下)
left = left[np.argsort(left[:, 1]), :]
(tl, bl) = left
# 右组按y坐标排序(右上,右下)
right = right[np.argsort(right[:, 1]), :]
(tr, br) = right
return np.array([tl, tr, br, bl], dtype="float32")
def perspective_correction(img):
"""
透视校正:检测图像中的四边形并进行透视变换
"""
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 自适应阈值处理增强边缘
edged = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 11, 2)
# 查找轮廓
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5] # 取面积前5的轮廓
for contour in contours:
peri = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.02 * peri, True)
if len(approx) == 4: # 检测到四边形
ordered_pts = order_points(approx.reshape(4, 2))
# 计算目标图像尺寸
(tl, tr, br, bl) = ordered_pts
width_top = np.linalg.norm(tr - tl)
width_bottom = np.linalg.norm(br - bl)
height_left = np.linalg.norm(bl - tl)
height_right = np.linalg.norm(br - tr)
max_width = max(int(width_top), int(width_bottom))
max_height = max(int(height_left), int(height_right))
# 目标四点坐标
dst = np.array([
[0, 0],
[max_width - 1, 0],
[max_width - 1, max_height - 1],
[0, max_height - 1]], dtype="float32")
# 计算变换矩阵并应用
M = cv2.getPerspectiveTransform(ordered_pts, dst)
warped = cv2.warpPerspective(img, M, (max_width, max_height))
return warped
return None # 未找到四边形
def rotate_correction(image):
"""
旋转校正:检测直线角度并旋转图像
"""
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi / 180, 200) # 霍夫变换检测直线
if lines is None:
return image
angles = []
for line in lines:
rho, theta = line[0]
# 计算直线角度(转换为度数)
angle = np.degrees(theta) - 90 # 转换为相对于垂直线的角度
angles.append(angle)
median_angle = np.median(angles)
# 仅在校正角度超过阈值时旋转
if abs(median_angle) > 0.5:
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, median_angle, 1.0)
corrected = cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_REPLICATE)
return corrected
return image
def main(image_path):
# 读取图像
img = cv2.imread(image_path)
if img is None:
print("Error: 无法读取图像")
return
# 可选:镜头畸变校正(需提供相机参数)
# img = cv2.undistort(img, camera_matrix, dist_coeffs)
# 透视校正
perspective_img = perspective_correction(img)
if perspective_img is not None:
# 旋转校正
final_img = rotate_correction(perspective_img)
else:
# 直接旋转校正原图
final_img = rotate_correction(img)
# 显示结果
cv2.imshow("Original", img)
if perspective_img is not None:
cv2.imshow("Perspective Corrected", perspective_img)
cv2.imshow("Final Corrected", final_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print("Usage: python image_correction.py <image_path>")
else:
main(sys.argv[1])
算法说明:
透视校正:
- 通过自适应阈值处理和轮廓检测找到图像中的四边形区域
- 使用透视变换将四边形区域转换为正视图
- 适用于文档、标牌等包含明显四边形结构的图像
旋转校正:
- 使用Canny边缘检测和霍夫变换检测直线
- 计算直线角度的中位数作为图像倾斜角度
- 根据倾斜角度旋转图像实现水平校正
畸变校正:
- 代码中已预留镜头畸变校正接口(需取消注释并提供相机标定参数)
- 使用
cv2.undistort()
函数实现径向和切向畸变校正
使用说明:
- 安装依赖:
pip install opencv-python numpy
- 运行命令:
python image_correction.py <图片路径>
- 按任意键关闭窗口
该算法能有效校正大多数文档类图像的透视畸变和旋转问题,实际效果取决于图像中的特征检测质量,可通过调整阈值参数优化结果。