cv2.Canny
找物體的邊緣cv2.HoughLines
cv2.HoughLines:
lines = cv2.HoughLines(image, rho, theta, threshold)
image
: 二值化圖像,通常是由邊緣檢測算法(如Canny)生成的。rho
: 霍夫空間中極座標中的像素距離解析度。theta
: 霍夫空間中極座標中的角度解析度,常輸入np.pi / 180,
代表所有角度都偵測threshold
: 閾值,線條檢測的閾值,長度需超過多少才算有效線條,單位為像素。直線的極座標表示為 (rho, theta),其中 rho
是從原點到直線的距離,而 theta
是直線的角度。theta
的範圍通常被設置為 [0, 180] 度,這是因為直線的表示是對稱的,也就是說,同一條直線的兩個方向都被考慮到,角度的範圍因此被限制在 [0, 180] 度。
import cv2
import numpy as np
#旋轉圖片用
def rotate_image(image, angle):
# 取得影像中心點坐標
center = tuple(np.array(image.shape[1::-1]) / 2)
# 設定旋轉矩陣
rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
# 進行影像旋轉
rotated_image = cv2.warpAffine(image, rotation_matrix, image.shape[1::-1], flags=cv2.INTER_LINEAR)
return rotated_image
#算出旋轉角度並轉正
def calculate_rotation_angle(image_path):
# 讀取圖片
image = cv2.imread(image_path)
height, width = image.shape[:2]
# 將圖片轉換為灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 使用霍夫直線變換檢測直線
edges = cv2.Canny(gray, 100, 250, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi / 180, threshold=120)
#存圖分析用
edges_img = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
image_view = image.copy()
# 計算直線的平均角度
angles_horizontal = []
angles_vertical = []
for i , line in enumerate(lines):
print(f'line :{line}')
rho, theta = line[0]
angle = theta * 180 / np.pi
# 分類橫向和垂直直線
if 50 <= angle <= 130: # 橫向直線
angles_horizontal.append(angle)
elif 150 <= angle <= 190: # 垂直直線
angles_vertical.append(angle)
elif 0 <= angle <= 30: # 垂直直線
angle += 180
angles_vertical.append(angle)
print(angle)
line_length = max(height, width) # 畫出檢測到的直線
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + line_length * (-b))
y1 = int(y0 + line_length * (a))
x2 = int(x0 - line_length * (-b))
y2 = int(y0 - line_length * (a))
cv2.line(image_view, (x1, y1), (x2, y2), (0, 0, 255), 1)
#平均計算橫向與垂直直線
if angles_horizontal:
average_angle_horizontal = np.mean(angles_horizontal)
else:#假設沒偵測到指定數值
average_angle_horizontal = 90
if angles_vertical:
average_angle_vertical = np.mean(angles_vertical)
else:#假設沒偵測到指定數值
average_angle_vertical = 180
# 顯示包含檢測到的直線的圖片
cv2.imshow('Detected_Lines', image_view)
cv2.waitKey(0)
cv2.destroyAllWindows()
print(f"橫向直線的平均角度:{average_angle_horizontal} 度")
print(f"垂直直線的平均角度:{average_angle_vertical} 度")
# 算出相對應旋轉角度
angle_horizontal = 90 - average_angle_horizontal
angle_vertical = 180 - average_angle_vertical
# 計算平均角度
average_angle = np.mean([angle_horizontal, angle_vertical])
print(f'旋轉角度 : {average_angle}')
# 轉正
rotate = rotate_image(image, -average_angle)
# 顯示包含檢測到的直線的圖片
cv2.imshow('result Image', rotate)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 替換成你的圖片路徑
image_path = 'D:/CRABpy/Rotation/test2.png'
calculate_rotation_angle(image_path)
一條直線的兩個方向都被考慮到,就容易混淆到底算出來的直線角度是哪個方向。
以下利用不同旋轉角度的物體,來記錄不同的直線角度。
最後根據上面三個圖得到以下角度表,根據這角度表在來設定分類橫向與垂直直線的角度。
右半邊為0至90
但我實際在測試時有跑出過183度,雖然文件寫說偵測的出的直線角度範圍為[0,180]
左半邊為180至90