import numpy as np, cv2
def draw_bar(img, pt, w, bars):
pt = np.array(pt, np.int)
for bar in bars:
(x,y), h = pt, w*6
cv2.rectangle(img, (x, y, w, h), (0,0,0), -1)
if bar == 0:
y, h = y + w*3-w//4 , w//2
cv2.rectangle(img, (x, y, w, h), (255,255,255), -1)
pt += (int(w*1.5), 0)
c= 200
r, sr, c2, c4 = c//2, c//4, c*2, c*4
img = np.full((c4,c4,3), 255, np.uint8)
blue, red = (255,0,0), (0,0,255)
cv2.ellipse(img, (c2,c2), (r,r), 0,0 , 180, blue, -1)
cv2.ellipse(img, (c2,c2), (r,r), 180,0 , 180, red, -1)
cv2.ellipse(img, (c2+r-sr,c2), (sr,sr), 180,0 , 180, blue, -1)
cv2.ellipse(img, (c2 -sr,c2), (sr,sr), 0,0 , 180, red, -1)
left = (c2 -c * (18+8)/24, c2-sr)
right = (c2 +c * (18+0)/24, c2-sr)
draw_bar(img, left, c//12, (1,1,1))
draw_bar(img, right, c//12, (0,0,0))
angle = cv2.fastAtan2(2,3)
img = cv2.warpAffine(img, cv2.getRotationMatrix2D((c2,c2), -angle*2, 1), (c4,c4))
draw_bar(img, left, c//12, (1,0,1))
draw_bar(img, right, c//12, (0,1,0))
ang = cv2.getRotationMatrix2D((c2,c2), angle, 1)
img = cv2.warpAffine(img, ang, (c4,c4))
cv2.imshow('img', img[c2-c:c2+c, c2-r*3:c2+r*3])
cv2.waitKey(0)
import numpy as np, cv2
image = cv2.imread("images/translate.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 에러")
h,w = image.shape
flip1 = np.array([[-1,0,w], [0,1,0]], np.float32) # -x 변환 + w 평행이동
flip2 = np.array([[1,0,0], [0,-1,h]], np.float32) # -y 변환 + h 평행이동
flip3 = np.array([[-1,0,w], [0,-1,h]], np.float32) # -x, -y 변환 + w,h 평행이동
dst1 = cv2.warpAffine(image, flip1, (w,h))
dst2 = cv2.warpAffine(image, flip2, (w,h))
dst3 = cv2.warpAffine(image, flip3, (w,h))
cv2.imshow('image', image); cv2.imshow('flip1', dst1)
cv2.imshow('flip2', dst2); cv2.imshow('flip3', dst3)
cv2.waitKey(0)
직교좌표계에서 극좌표계로 정보 변환
기울기 m, 점(a,b) 지나는 직선 정보 -> 직선과 원점의 수직거리 ρ, 직선과 x축이 만나는 각도 Θ 정보로도 나타낼 수 있음 (ρ,Θ)
변환 이유: 직선 기울기 90도면 m 값 무한대라 숫자 에러남
극좌표계에서 누적행렬 구성
영상 크기에 맞춰서 극좌표계를 위한 행렬 구성, (ρ,Θ)으로 인덱싱해서 값을 누적할것임
영상화소의 직선 검사
입력영상은 이진화, 모폴로지 등의 전처리 수행해서 잡음 제거하고, 캐니에지 검출 한 걸로 씀, 입력영상의 조회좌표가 직선이면, 직선 누적행렬 좌표(ρ,Θ)에 1 추가
직선 좌표에 대한 극좌표 누적행렬 구성
두 점이 있을 때, 각 점에 대해 (ρ,Θ)의 값을 모두 카운팅하면 두점을 꿰뚫는 (ρ,Θ)만이 2번 카운팅 될 것임, 이 원리 이용하면 가장 많이 카운팅된 (ρ,Θ)이 진짜 직선이니까 이 직선으로 검출
누적행렬의 지역최댓값 선정
누적행렬에서 직선을 찾으려면 누적값이 임계값 이상인 좌표 찾음, 근데 특정위치에서 너무 많은 직선 검출되면, 어떤 위치의 직선은 임계값 이상임에도 검출순위에 밀려 검출 안될수도, 이를 해결하기 위해 누적행렬을 작은 블록으로 나누고 마스킹해서 지역최댓값만 남김 -> 직선 검출의 정확도 높아짐
직선 선별 - 임계값 이상인 누적값 선택 및 정렬
누적행렬 원소 중 임계값보다 큰 값을 선별하여 lines 행렬에 저장, 이때 긴 직선이 먼저 저장되도록 누적값 기준으로 내림차순 정렬
사용 예시)
lines = cv2.HoughLines(img, rho, theta, threshold, lines, srn=0, stn=0,
min_theta, max_theta)
img: 입력 이미지, 1 채널 바이너리 스케일
rho: 거리 측정 해상도, 0~1
theta: 각도, 라디안 단위 (np.pi/0~180)
threshold: 직선으로 판단할 최소한의 동일 개수 (작은 값: 정확도 감소, 검출 개수 증가 / 큰 값: 정확도 증가, 검출 개수 감소)
lines: 검출 결과, N x 1 x 2 배열 (r, Θ)
srn, stn: 멀티 스케일 허프 변환에 사용, 선 검출에서는 사용 안 함
min_theta, max_theta: 검출을 위해 사용할 최대, 최소 각도
멀티하네스: 전자제품에서 다중의 전선을 한번에 연결하는 케이블 커넥터
멀티하네스 객체의 기울어진 각도를 인식하고 가지런히 놓일 수 있도록 회전 보정하려면?
이미지 - 전처리(명암도,이진화,모폴로지) - 가장 큰 객체 검출 - 캐니에지 검출, 허프직선 검출 - 회전각 계산 - 중심점기준으로 역방향 회전행렬 계산
코너: 영상에서 객체를 추적할때, 영상과 영상을 매칭할 때, 참고할 수 있는 영상의 특정 정보
코너정보 중 영상의 왜곡에도 불변하는 특징을 가진 지점들이 영상 매칭에 유용
해리스코너 검출기로 그러한 지점을 찾을 수 있다.
기존에 갖고있는 데이터들을 일정한 규칙에 의해 분류된 상태에서 미지의 입력이 들어왔을 때 입력 데이터의 종류를 예측하는 분류 알고리즘
딥러닝 데이터 분류에 사용가능
import numpy as np, cv2, math
from Common.hough import accumulate, masking, select_lines
def houghLines(src, rho, theta, thresh):
acc_mat = accumulate(src, rho, theta) # 허프 누적 행렬 계산
acc_dst = masking(acc_mat, 7, 3, thresh) # 마스킹 처리 7행,3열
lines = select_lines(acc_dst, rho, theta, thresh) # 직선 가져오기
return lines
def draw_houghLines(src, lines, nline):
if len(src.shape) < 3:
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR) # 컬러 영상 변환
else:
dst = np.copy(src)
min_length = min(len(lines), nline)
for i in range(min_length):
rho, radian = lines[i, 0, 0:2] # 수직거리 , 각도 - 3차원 행렬임
a, b = math.cos(radian), math.sin(radian)
pt = (a * rho, b * rho) # 검출 직선상의 한 좌표 계산
delta = (-1000 * b, 1000 * a) # 직선상의 이동 위치
pt1 = np.add(pt, delta).astype('int')
pt2 = np.subtract(pt, delta).astype('int')
cv2.line(dst, tuple(pt1), tuple(pt2), (0, 255, 0), 1, cv2.LINE_AA)
return dst
#image = cv2.imread('images/hough.jpg', cv2.IMREAD_GRAYSCALE)
image = cv2.imread('images/hough2.jpg', cv2.IMREAD_COLOR) # 그레이말고 칼라로 읽어옴
if image is None: raise Exception("영상 파일 읽기 에러")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 일단 그레이로 저장
blur = cv2.GaussianBlur(gray, (5, 5), 2, 2) # 가우시안블러링
canny = cv2.Canny(blur, 50, 150, 5) # 캐니에지 검출
rho, theta = 1, np.pi / 180
# lines1 = houghLines(canny, rho, theta, 80)
lines2 = cv2.HoughLines(canny, rho, theta, 80) # 허프라인 생성
# dst1 = draw_houghLines(canny, lines1, 7)
# dst2 = draw_houghLines(canny, lines2, 7)
my_dst = draw_houghLines(canny, lines2, 20) # 캐니에지에 허프라인
dst2 = draw_houghLines(image, lines2, 20) # 이미지에 허프라인
cv2.imshow("image", image)
cv2.imshow("canny", canny)
cv2.imshow("my_dst", my_dst)
#cv2.imshow("detected lines", dst1)
cv2.imshow("detected lines_OpenCV", dst2)
cv2.waitKey(0)
카메라는 3차원의 실세계영상을 2차원의 평면영상으로 맺히게 하기 때문에 기하학적 왜곡 발생, 외부파라미터, 내부파라미터에 의한 왜곡 있음
캘리브레이션 : 내부 요인의 파라미터 값을 구하는 과정
카메라 캘리브레이션 수행하여 카메라 렌즈 왜곡 보정 가능