对于上篇博客中的图像校正进行分析
http://t.csdnimg.cn/8MXkG
所有代码
import numpy as np
import cv2
import matplotlib.pyplot as plt
def get4points(img: np.ndarray, thed, n):
# 灰度和二值化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, thed, 255, cv2.THRESH_BINARY)
# 搜索轮廓
contours, hierarchy = cv2.findContours(
binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
len_list = []
for i in range(len(contours)):
len_list.append(len(contours[i]))
sy = np.argsort(np.array(len_list))[-n]
# 寻找顶点
sum_list = []
dif_list = []
for i in contours[sy]:
sum = i[0][0]+i[0][1]
sum_list.append(sum)
dif_list.append(i[0][0]-i[0][1])
id_lb = np.argsort(np.array(sum_list))
id_lb2 = np.argsort(np.array(dif_list))
lu_id , rd_id = id_lb[0], id_lb[-1]
ld_id , ru_id = id_lb2[0], id_lb2[-1]
points = np.array([contours[sy][lu_id][0], contours[sy][rd_id][0],
contours[sy][ld_id][0], contours[sy][ru_id][0]])
return points, contours, sy
def order_points(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)]
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))
# 构建新图片的4个坐标点
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 show_cmp_img(original_img, transform_img):
_, axes = plt.subplots(1, 2)
# 显示图像
axes[0].imshow(original_img)
axes[1].imshow(transform_img)
# 设置子标题
axes[0].set_title("original image")
axes[1].set_title("transform image")
plt.show()
# 读取图片
image = cv2.imread('D:/Pythonstudy/deeplearning/picture/8.jpg')
points, _, _ = get4points(image, 127, 1)
# 获取原始的坐标点
pts = np.array(points, dtype="float32")
# 对原始图片进行变换
warped = four_point_transform(image, pts)
show_cmp_img(image, warped)
以上就是所有代码,逐个分析函数的作用
获取原图的四个顶点
- 寻找最大轮廓的下标sy,根据最大轮廓的下标找到最大轮廓,计算最大轮廓中的所有y,x的和和差,挑出里面和最小的就是左上角,最大的就是右下角。
这段代码的目的是将一个包含四个点的数组(通常是一个矩形的四个顶点)重新排序,使得返回的数组按照矩形的左上角、右上角、右下角、左下角的顺序排列。这种排序方式在处理图像中的矩形或者进行几何计算时非常有用。下面是对这段代码的详细解释:
-
初始化坐标点数组:
rect = np.zeros((4, 2), dtype = "float32")
这行代码初始化了一个4x2的浮点数数组
rect
,用于存储排序后的四个点。每个点由两个浮点数表示(通常是x和y坐标)。 -
获取左上角和右下角坐标点:
s = pts.sum(axis = 1) rect[0] = pts[np.argmin(s)] rect[2] = pts[np.argmax(s)]
首先,通过对
pts
数组(假设为4x2,包含四个点的x和y坐标)的每一行(即每个点的x和y坐标)求和,得到s
数组。这个数组的每个元素代表了一个点的x和y坐标之和。由于矩形的左上角和右下角分别在所有点中拥有最小和最大的x+y和(假设x和y坐标都是非负的),因此通过np.argmin(s)
和np.argmax(s)
找到左上角和右下角的索引,并将对应的点存储在rect
数组的前两个位置。 -
计算左上角和右下角的离散差值:
diff = np.diff(pts, axis = 1)
这行代码计算了
pts
数组中每个点的x和y坐标的差值(即y-x)。注意,这里使用的是np.diff
,它默认沿着最后一个轴(在这里是列,即x和y坐标)计算差值,因此diff
的每一行代表了一个点的y坐标减去x坐标的结果。 -
确定右上角和左下角的坐标点:
rect[1] = pts[np.argmin(diff)] rect[3] = pts[np.argmax(diff)]
由于矩形的右上角和左下角的y-x差值(即y-x)在所有点中分别是最小和最大的(假设y坐标大于x坐标),因此通过
np.argmin(diff)
和np.argmax(diff)
找到右上角和左下角的索引,并将对应的点存储在rect
数组的后两个位置。
需要注意的是,这段代码假设了矩形的所有点都在第一象限(即x和y坐标都是非负的),并且矩形的边与坐标轴平行。如果矩形的点在其他象限或者矩形的边不与坐标轴平行,这段代码可能无法正确排序。此外,如果输入的pts
数组不包含恰好四个点,或者这四个点不构成一个矩形,这段代码的行为也是未定义的。