import cv2 as cv
from matplotlib import pyplot as plt
import numpy as np
from numpy.linalg import inv
""" 求两直线交点 """
def intersection(line1, line2):
# [x1, y1, x2, y2]
a1 = line1[1] - line1[3] # a = y1 - y2
b1 = line1[2] - line1[0] # b = x2 - x1
c1 = line1[0] * line1[3] - line1[2] * line1[1] # c = x1 * y2 - x2 * y1
a2 = line2[1] - line2[3] # a = y1 - y2
b2 = line2[2] - line2[0] # b = x2 - x1
c2 = line2[0] * line2[3] - line2[2] * line2[1] # c = x1 * y2 - x2 * y1
A = np.array([[a1, b1], [a2, b2]])
B = np.array([[c1], [c2]])
pt = np.dot(inv(A), -B)
x = pt[0, 0]
y = pt[1, 0]
return [x, y]
src = cv.imread("images/2.png")
mat = src.copy()
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
blur = cv.blur(gray, (5, 5))
# plt.figure(1)
# plt.imshow(blur, cmap="binary")
kernel = np.ones((10, 10), np.int8)
dilate = cv.dilate(blur, kernel)
""" 二值化 """
ret, binary = cv.threshold(dilate, 100, 120, cv.THRESH_BINARY_INV)
# plt.figure(2)
# plt.imshow(binary, cmap="binary")
""" 求轮廓 """
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# print('len:', len(contours))
cnt = contours[0]
# cv.drawContours(src, [cnt], -1, (0, 0, 255), 2)
""" 找到满足周长条件的轮廓 """
for i in range(len(contours)):
cnt = contours[i]
perimeter = cv.arcLength(cnt, True)
if 2500 < perimeter < 3500:
print(perimeter)
# cv.drawContours(src, [cnt], -1, (0, 255, 255), 2)
break
# plt.figure(2)
# plt.imshow(src[:, :, ::-1])
""" 求凸包 """
hull = cv.convexHull(cnt)
img = np.ones((720, 1280, 3), dtype=np.uint8)
# print(type(gray)) # <class 'numpy.ndarray'>
# print(gray.shape) # (720, 1280)
# print(type(img)) # <class 'numpy.ndarray'>
# print(img.shape) # (720, 1280)
# cv.drawContours(src, [hull], -1, (255, 0, 0), 3)
# print(len(hull))
""" 在另一张图上画出凸包 """
cv.drawContours(img, [hull], -1, (0, 0, 255), 2)
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
""" 二值化 """
_, img_binary = cv.threshold(img_gray, 50, 100, cv.THRESH_BINARY)
plt.figure(3)
plt.imshow(img_binary, cmap="binary")
#### cv.imwrite("images/img.png", img_binary)
""" 霍夫线检测 """
lines = cv.HoughLines(img_binary, 1.0, np.pi/180, 250)
print(lines.shape) # (8, 1, 2)
lines = np.squeeze(lines)
print(lines.shape) # (8, 2)
""" K-means对四种线分类 """
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret,label,center = cv.kmeans(lines, 4, None, criteria, 10, cv.KMEANS_RANDOM_CENTERS)
# print(center.shape) # (4, 2)
line_point = []
for i in range(center.shape[0]):
rho, theta = center[i]
a = np.cos(theta)
b = np.sin(theta)
x0 = rho * a
y0 = rho * b
x1 = int(x0 + 2000 * (-b))
y1 = int(y0 + 2000 * a)
x2 = int(x0 - 2000 * (-b))
y2 = int(y0 - 2000 * a)
line_point.append([x1, y1, x2, y2])
cv.line(img, (x1, y1), (x2, y2), (255, 0, 255), 4)
# print(line_point)
""" 求4条线的4个交点 """
pt = []
for i in range(2):
pt.append(intersection(line_point[i], line_point[2]))
pt.append(intersection(line_point[i], line_point[3]))
print(pt)
points = np.array(pt, dtype=int)
print(points.shape) # (4, 2)
print(points)
# for i in range(points.shape[0]):
# cv.circle(img, (points[i, 0], points[i, 1]), 8, (0, 255, 0), -1)
""" 画出4个交点 """
for pt in points:
cv.circle(img, (pt[0], pt[1]), 6, (0, 255, 0), -1)
plt.figure(5)
plt.imshow(img)
# cv.imwrite("images/lines.png", img)
""" 对4个交点进行排序,因为分类的顺序是随机的 """
idx = np.lexsort([points[:, 0]])
tr_points = points[idx, :]
print(tr_points)
""" 利用找到的4隔点进行透射变换 """
dst_width = 800
dst_height = 600
pts1 = np.float32([tr_points[0], tr_points[3], tr_points[2], tr_points[1]])
pts2 = np.float32([[0, 0], [dst_width, 0], [dst_width, dst_height], [0, dst_height]])
M = cv.getPerspectiveTransform(pts1, pts2)
dst = cv.warpPerspective(mat, M, (dst_width, dst_height))
plt.figure(6)
plt.imshow(dst[:, :, ::-1])
cv.imwrite('images/dst_2.png', dst)
plt.show()
1.原图
2.凸包
3. 霍夫线检测与交点
4.透射变换