반응형

Hough Line Transform 구현 원리에 대해서 다룹니다.







유튜브에서 사용한 코드입니다.


import cv2 as cv
import numpy as np
import math
import time


img_original = cv.imread('square.jpg', cv.IMREAD_COLOR)

img_gray = cv.cvtColor(img_original, cv.COLOR_BGR2GRAY)
img_edge = cv.GaussianBlur(img_gray, (5, 5), 0, 0)
img_edge = cv.Canny(img_edge, 50, 150, 3)

height = img_edge.shape[0]
width = img_edge.shape[1]
tmp = min(height, width)
hough_height = int(1.5 * tmp)


accumulator_width = 180
accumulator_height = hough_height * 2
accumulator_size = accumulator_height * accumulator_width


accumulator = np.zeros((accumulator_height, accumulator_width))
table_sin = np.zeros(180)
table_cos = np.zeros(180)
DEG2RAD = np.pi / 180


for angle in range(0,180):
   table_sin[angle] = math.sin(np.radians(angle))
   table_cos[angle] = math.cos(np.radians(angle))


start=time.clock()

for y in range(0,height):
   for x in range(0,width):
       if img_edge.item(y, x) > 0:
           for angle in range(0,180):
               r = int(x * table_cos[angle] + y * table_sin[angle])
               r = r + hough_height # r이 음수인 경우 때문 -r ~ r 범위를 0 ~ 2r 범위로 변경
               accumulator[r, angle] +=1

end=time.clock()
print(end - start)



# accumulator를 이미지화
img_accumulator = np.ones((accumulator_height, accumulator_width, 3), np.uint8)
img_accumulator = img_accumulator * 255

accumulator2 = cv.convertScaleAbs(accumulator,3,5)

start=time.clock()
for r in range(0,accumulator_height):
   for angle in range(0,accumulator_width):

       value = accumulator2[r, angle]

       if value > 0:
           img_accumulator.itemset(r, angle, 0, 255 - value)
           img_accumulator.itemset(r, angle, 1, 255 - value)
           img_accumulator.itemset(r, angle, 2, 255 - value)


end=time.clock()
print(end - start)


start=time.clock()
count = 0
for r in range(0, accumulator_height):
   for angle in range(0,180):

       if accumulator.item(r,angle) > 80: # Hough Line Transform Threshold

           #현재 위치가 local maxima인지 검사
           max = accumulator[r, angle]
           for y in range(-5,6):
               for x in range(-5,6):

                   new_r = r + y
                   new_angle = angle + x

                   if new_angle < 0:
                       new_angle = 180 + new_angle
                   elif new_angle >= 180:
                       new_angle = new_angle - 180

                   if new_r >= 0 and new_r < accumulator_height:
                       if accumulator[new_r, new_angle] > max:
                           max = accumulator[new_r, new_angle]
                           x = y = 6 #local maxima 아님. loop 종료

           if max > accumulator.item(r, angle):
               continue #현재 위치는 local maxima가 아님


           # r = x * cos(theta) + y * sin(theta)
           # x = (r - y * sin(theta)) / cos(theta) # 수직선인 경우
           # y = (r - x * cos(theta)) / sin(theta) # 수평선인 경우


           if angle >= 45 and angle <= 135: # 수직선
               x1 = 0
               x2 = width
               y1 = ((r - hough_height) - x1 * table_cos[angle]) / table_sin[angle]
               y2 = ((r - hough_height) - x2 * table_cos[angle]) / table_sin[angle]

           else: #수평선
               y1 = 0
               y2 = height
               x1 = ((r - hough_height) - y1 * table_sin[angle]) / table_cos[angle]
               x2 = ((r - hough_height) - y2 * table_sin[angle]) / table_cos[angle]


           x1 = int(x1)
           y1 = int(y1)
           x2 = int(x2)
           y2 = int(y2)

           cv.circle(img_accumulator, (angle, r), 5, (255, 0, 0),-1)
           cv.line(img_original, (x1, y1), (x2, y2), (255, 0, 0), 1)
           count += 1

           print("(%d,%d)-(%d,%d), angle=%d, r=%d, accmulator=%d" % (x1,y1,x2,y2,angle,r,accumulator.item(r, angle)))
end=time.clock()
print(end - start)

cv.imshow("img_result", img_original)
cv.imshow("img_gray", img_gray)
cv.imshow("img_edge", img_edge)
cv.imshow("img_accumulator", img_accumulator)
cv.imwrite("img_accumulator.jpg", img_accumulator)


cv.waitKey(0)





OpenCV에서 제공하는 함수 사용 예제입니다.


cv.HoughLinesP



import cv2 as cv
import numpy as np

img = cv.imread('hallway.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)

for line in lines:
   x1,y1,x2,y2 = line[0]
   cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)

cv.imshow("result", img)
cv.waitKey(0)



cv.HoughLines


import cv2 as cv
import numpy as np

img = cv.imread('hallway.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150)
lines = cv.HoughLines(edges,1,np.pi/180,200)

for line in lines:
   rho,theta = line[0]
   a = np.cos(theta)
   b = np.sin(theta)
   x0 = a*rho
   y0 = b*rho
   x1 = int(x0 + 1000*(-b))
   y1 = int(y0 + 1000*(a))
   x2 = int(x0 - 1000*(-b))
   y2 = int(y0 - 1000*(a))
   cv.line(img,(x1,y1),(x2,y2),(0,0,255),2)

cv.imshow("result", img)
cv.waitKey(0)



반응형

해본 것을 문서화하여 기록합니다.
부족함이 있지만 도움이 되었으면 합니다.


포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.


제가 쓴 책도 한번 검토해보세요 ^^

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기

댓글을 달아 주세요

">
  1. thumbnail
    익명
    2020.03.11 11:53

    비밀댓글입니다

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.03.11 13:04 신고

      허프로 직선을 구한후 원하는 한 점 근처를 지나는 직선만 필터링하면 됩니다.

  2. thumbnail
    익명
    2020.04.02 17:05

    비밀댓글입니다

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.02 17:08 신고

      img_original 변수에 이미지가 저장되지 않은겁니다. 이미지를 로드했다면 경로가 맞나 확인해보세요

  3. thumbnail
    아이우비
    2020.04.27 16:12

    안녕하세요 허프변환을 통해서 라인을 찾는 코딩을 짜는 도중에 영상을 통해 짜느라 이게 카메라가 급하게 이동할 때 허프 변환이 이루어지지못해서 에러가 뜹니다. 간단한 조건문 통해서 지나가고 싶은데 조언을 받을 수 있을까요 ?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.27 20:09 신고

      len(lines)가 0인지 체크해보면 될듯합니다.

    • thumbnail
      아이우비
      2020.04.27 21:09

      해결이 되질않습니다 ...

      대충 어디서 문제가 생기는지 알꺼같은데 제가 관심영역에 라인이있을때는 프로그램이 굉장히 잘돌아가다가 카메라가 갑자기 움직이거나 할때, 즉 라인형상이 잡히지 않을때 에러가 뜨는거같은데 계산하는 과정에서 에러가 생기고 이에러는 계산후에 생기는 과정인데 혹시 계산하는 과정을 이프문에 넣어서 확인을 할수있을까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.27 21:40 신고

      확인해보니 다음처럼 검사를 해야 하네요.

      if lines is not None:

    • thumbnail
      2020.04.27 22:01

      비밀댓글입니다

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.27 22:57 신고

      lines = cv.HoughLines(edges,1,np.pi/180,200) 결과가 없는 경우

      lines가 None이 되기때문에 위처럼 체크해보라고 한겁니다.

      원인을 찾아보시고 해결안되면 또 질문 남겨주세요

    • thumbnail
      아이우비
      2020.04.28 01:14

      라즈베리파이4를 이용하고있고 혹시 vnc를 통해서 연결을 하고있는데 hdmi선으로 연결하는거랑 기능을 수행하는데 차이가 있을까요? 제가 문제가있던부분은 크게 roi 범위를 벗어날때 생기는 오류고 영역을 벗어나거나 카메라가 흔들려 생기는 오류인것같습니다. 움직일때 라인을 찾는 속도도 생각보다 느린거같구요 제가 어차피 라인트레이싱을 하게되려면 라인을 찾는 속도가 좀 빨라야하는데 그과정이 아무래도 카메라가 흔들릴수밖에 없을꺼같아서 질문드립니다

    • thumbnail
      아이우비
      2020.04.28 04:01

      그리고 지금 print 문을 이용해서 에러가 왜 발생하는지 찾았습니다.
      일단 처음에 가정했던 hough 변환값이 없을때,
      그리고 제가 hough변환을 통해 라인들중 차선에 가깝다고 생각되는 라인을 찾는 코드가 있었거든요. 근데 비교대상이 없을때, 즉 라인이 1개밖에 그려지지않을때 이런 상황에서 오류가 발생하는것 같습니다.
      그래서 line_arr is not None (hough변환값이 없을때) and line_arr[2,1]!=0(2행1열이 없다 > x1,x2,y1,y2 값 밖에없다> 그려지는 라인이 2개이지만 제가 왼쪽 라인 오른쪽라인 둘다 검출하는 코딩을 짯기떄문에 나눠지면 왼쪽1개 오른쪽1개or왼쪽2개 or 오른쪽2개로 비교할 라인이 없거나 한쪽 라인이 아예없을떄 ):
      의 조건을 주어도 에러가 뜨길래 print 문을 보니 None 값이 떠도 아래의 if문으로 들어가서 에러가 뜨더라구요 ..
      코딩을 전반적으로 다시 짜봐야 할것같습니다. 일단 왼쪽 오른쪽 라인 구분없이 짜는거 한개의 라인이라도 검출할수있도록 짜보긴 할껀데 None 이라고 떳는데 왜 if문을 수행하는 것일까요 ㅠ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.28 20:31 신고

      hdmi로 연결하는 거에 비해 vnc로 작업하는게 느릴수 밖에 없습니다.

      line_arr is not None 조건문만 분리하고 이 후 나머지 조건을 검사해보세요.

  4. thumbnail
    미정
    2020.07.08 15:01

    안녕하세요 위에 있는 첫번째 코드를 따라 해 보니
    Traceback (most recent call last):
    File "test3.py", line 44, in <module>
    accumulator[r, angle] +=1
    IndexError: index 5832 is out of bounds for axis 0 with size 5832
    이런 문제가 생겼습니다
    혹시 휴대폰으로 찍은 것이 문제가 될까봐 파이 카메라로도 찍어 보았지만 그대로 였습니다
    사진파일은 square.jpg 로 하였는데 무슨 문제가 있는건지 궁금합니다