2024-02-28|閱讀時間 ‧ 約 29 分鐘

[OpenCV應用][Python]霍夫直線轉換偵測應用於旋轉補正

廢話不多說,先上成果圖。

成果圖

算出旋轉角度後轉正

算出旋轉角度後轉正


主要實現方法

1.灰階後利用cv2.Canny找物體的邊緣

2.找物件相對應的直線cv2.HoughLines

3.分類為橫向和垂直的直線角度,求得相對於物件的旋轉角度

4.根據算出的相對應旋轉角度將物件轉正


霍夫直線變換語法

cv2.HoughLines:

  • 用途:用於檢測圖像中的直線。
  • 返回值:返回檢測到的直線的極座標表示(rho, theta)。
  • 用法:
lines = cv2.HoughLines(image, rho, theta, threshold)
  • image: 二值化圖像,通常是由邊緣檢測算法(如Canny)生成的。
  • rho: 霍夫空間中極座標中的像素距離解析度。
  • theta: 霍夫空間中極座標中的角度解析度,常輸入np.pi / 180,代表所有角度都偵測
  • threshold: 閾值,線條檢測的閾值,長度需超過多少才算有效線條,單位為像素。
    假設門檻設為90,表示值線長度須超過90個像素。

直線的極座標表示 (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


以上為我實際應用的心得總結,不保證說明的內容完全正確,但實際上可以應用物體轉正,若有錯誤在留言讓我知道,謝謝:)












分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.