feat: fix pre_approx location & same point when moving

This commit is contained in:
Ting-Jun Wang 2023-12-16 19:26:50 +08:00
parent efaad29b78
commit 5ec9542cfe
Signed by: snsd0805
GPG Key ID: 48D331A3D6160354

156
test.py
View File

@ -1,4 +1,4 @@
import numpy as np
import cv2
# 設定連接到 Android 手機的相機
@ -6,48 +6,138 @@ cap = cv2.VideoCapture(0) # 0 表示第一個相機(通常是後置相機)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) # 設定寬度
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) # 設定高度
object_points = np.array([[0, 0, 0], [26, 0, 0], [0, 18.5, 0], [26, 18.5, 0]], dtype=np.float32)
while True:
ret, frame = cap.read() # 讀取影片幀
def get_new_approx(approx, previous_approx):
def distance(point, pre_point):
point = point[0]
pre_point = pre_point[0]
d = ((point[0]-pre_point[0]) ** 2) + ((point[1]-pre_point[1]) ** 2)
if not ret:
break
return np.sqrt(d)
# 預處理影像(例如:轉為灰度)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
new_approx = []
for pre_point in previous_approx:
min_d, min_index = 1e9, -100
for index, point in enumerate(approx):
d = distance(point, pre_point)
if d < min_d and d<=500:
min_d = d
min_index = index
if min_index != -100:
np.delete(approx, min_index)
new_approx.append(approx[min_index])
# 偵測邊緣
edges = cv2.Canny(gray, 100, 200)
if len(new_approx) == 4:
return new_approx
else:
return previous_approx
# 偵測輪廓
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
def initial_approx(approx):
distance = []
for point in approx:
x, y = point[0]
distance.append(x**2+y**2)
min_d, max_d = 1e9, -1
min_index, max_index = -100, -100
for index, d in enumerate(distance):
if d < min_d:
min_d = d
min_index = index
if d > max_d:
max_d = d
max_index = index
new_approx = []
# 找到最大的輪廓
max_contour = max(contours, key=cv2.contourArea)
remain_index = list(range(4))
remain_index.remove(max_index)
remain_index.remove(min_index)
# 找到輪廓的近似多邊形
epsilon = 0.05 * cv2.arcLength(max_contour, True)
approx = cv2.approxPolyDP(max_contour, epsilon, True)
if approx[remain_index[0]][0][0] > approx[remain_index[1]][0][0]: # remain 的第一個點的 x 大於第二個點的,代表他在右上角
second_index = remain_index[0]
third_index = remain_index[1]
else:
second_index = remain_index[1]
third_index = remain_index[0]
# 繪製多邊形
if len(approx) == 4: # 確保是四個角點
for point in approx:
print(point)
x, y = point[0]
cv2.circle(frame, (x, y), 5, (0, 0, 255), -1) # 在角點位置畫紅色圓圈
cv2.drawContours(frame, [approx], -1, (0, 255, 0), 2) # 繪製輪廓
print()
# 顯示結果
cv2.imshow('Paper Detection', frame)
# 按下 'q' 鍵退出迴圈
if cv2.waitKey(33) & 0xFF == ord('q'): # 等待 33ms (1秒 = 1000ms, 1秒顯示30幀)
break
new_approx.append(approx[min_index])
new_approx.append(approx[second_index])
new_approx.append(approx[third_index])
new_approx.append(approx[max_index])
return new_approx
if __name__ == '__main__':
cap.release()
cv2.destroyAllWindows()
previous_approx = []
while True:
ret, frame = cap.read() # 讀取影片幀
if not ret:
break
# 預處理影像(例如:轉為灰度)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
# 偵測邊緣
edges = cv2.Canny(gray, 30, 90)
dilate_kernel = np.ones((5, 5), np.uint8)
dilate_edges = cv2.dilate(edges, dilate_kernel, iterations=1)
# 偵測輪廓
contours, _ = cv2.findContours(dilate_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours != []:
# 找到最大的輪廓
max_contour = max(contours, key=cv2.contourArea)
# 找到輪廓的近似多邊形
epsilon = 0.05 * cv2.arcLength(max_contour, True)
approx = cv2.approxPolyDP(max_contour, epsilon, True)
# 繪製多邊形
if len(approx) == 4: # 確保是四個角點
if previous_approx == []:
print("INITIAL")
previous_approx = initial_approx(approx)
new_approx = get_new_approx(approx, previous_approx)
previous_approx = new_approx
x, y = new_approx[0][0]
cv2.circle(frame, (x, y), 15, (0, 0, 255), -1) # 在角點位置畫紅色圓圈
x, y = new_approx[1][0]
cv2.circle(frame, (x, y), 30, (0, 0, 255), -1) # 在角點位置畫紅色圓圈
x, y = new_approx[2][0]
cv2.circle(frame, (x, y), 15, (255, 0, 0), -1) # 在角點位置畫紅色圓圈
x, y = new_approx[3][0]
cv2.circle(frame, (x, y), 30, (255, 0, 0), -1) # 在角點位置畫紅色圓圈
cv2.drawContours(frame, [approx], -1, (0, 255, 0), 2) # 繪製輪廓
# 顯示結果
cv2.namedWindow('Paper Detection(edge)', 0)
cv2.imshow('Paper Detection(edge)', edges)
cv2.namedWindow('Paper Detection(dilate edge)', 0)
cv2.imshow('Paper Detection(dilate edge)', dilate_edges)
cv2.namedWindow('Paper Detection', 0)
cv2.imshow('Paper Detection', frame)
# 按下 'q' 鍵退出迴圈
if cv2.waitKey(33) & 0xFF == ord('q'): # 等待 33ms (1秒 = 1000ms, 1秒顯示幀)
break
if cv2.waitKey(33) & 0xFF == ord(' '):
print("Clear previous approxes")
previous_approx = []
cap.release()
cv2.destroyAllWindows()