제목에 쫄지 말자 그저 GUI의 Full Name일뿐😬
우선 오늘은 제목에 나와 있듯이 openCV에서 지원하는
GUI를 다뤄보면서 공부해보자
0. What Is Canny Edge?
코드를 보기 전에 Canny Edge가 뭔지 알아보자🤔
Canny Edge는 Edge를 찾을 때 가장 인기가 높은 알고리즘 중 하나이다
John F Canny가 만든 알고리즘으로 다단계 알고리즘으로 이루어져 있다.
1. 노이즈 제거
Image에서 Noise가 있으면 Edge를 제대로 찾는 것이 어려울 수 있습니다.
따라서 첫단계로 5x5 가우시안 필터(Gaussian Filter)를 이용해 Image의 Noise를 줄여줍니다.
2. Gradient 값이 높은 부분 찾기
가우시안 필터로 Noise가 제거된 이미지를 Sobel 커널을 수평방향, 수직방향으로 적용하여
각 방향의 gradient를 획득합니다 수평방향의 gradient를 Gx, 수직방향의 gradient를 Gy라고 한다
픽셀 (x, y)에서 edge gradient는 아래의 식으로 찾을 수 있다
수학을 못하는 나는 참고만 하겠다.
3단계 : 최대값이 아닌 픽셀의 값을 0으로 만들기
Gradient가 높은 곳을 찾았다면, Edge에 기여하지 못하는 Pixel을
제거하기 위해서 Full Image를 Scan한다.
Image를 scan하는 과정에서 gradient 방향으로 Scan Area에서
Maximum의 Gradient을 가진 Pixel을 찾는다.
그림에 대해서 약간 설명을 붙이자면
A는 Edge부분 위에 있는 Pixel이며 B,C는 Gradient Direction에 위치해있다.
A지점에서 Gradient값이 B, C보다 값이 큰지 아닌지 체크한다.
만약 A값이 나머지 두 Pixel보다 크다면 다음 단계로 넘어가고
작은 경우에는 A의 Pixel값을 0으로 만들어준다.
4단계 : Hyteresis Thresholding
4단계는 3단계를 거친 것들이 실제 Edge로 Detection 할 수 있을지
판별하는 단계에 속한다.
먼저 MaxVal와 MinVal을 잡아준다.
만약 Pixel의 값이 MaxVal을 넘긴다면 그 점은 확실한 Edge로 인식하며
MinVal보다 낮은 점은 Edge로 판별하지 않는다.
그럼 여기서 한가지 의문이 생긴다.
그럼 중간에 있는 Pixel은 뭔데요?
중간에 있는 Pixel들은 Pixel들의 Connectivity를 판별하여 Edge를 판단한다.
위 그림을 보면서 차근차근 이해해보자
A라는 Pixel은 MaxVal을 넘겼으므로 Edge로 판별하며
B, C는 MaxVal과 MinVal 사이에 존재하므로 Connectivity를 판별해야한다.
C는 A라는 확실한 Edge의 Pixel값과 하나의 Line으로 Connect 되어있으므로C도 Edge로 판별한다.
B는 A라는 Pixel과 떨어져 있어서 Edge로 판별하지 않는다.
1단계에서 4단계가 끝나면 Image에서 Edge로 판단된 부분만 남게 된다.
원본 docs.opencv.org/master/da/d22/tutorial_py_canny.html
OpenCV: Canny Edge Detection
Goal In this chapter, we will learn about Concept of Canny edge detection OpenCV functions for that : cv.Canny() Theory Canny Edge Detection is a popular edge detection algorithm. It was developed by John F. Canny in It is a multi-stage algorithm and we wi
docs.opencv.org
Canny_Edge 설명 끄-읕
😀
1. Deal_Canny_Edge_With_GUI
본격적으로 코드를 보면서 공부해보자
import cv2
# If Mediate THe TrackBar, CallBack Function
# You Can Insert openCV Function In here
# Dummy Function
def on_trackbar(x):
pass
cv2.namedWindow('Canny')
# openCV Provide GUI Function Of TrackerBar
# Argument = 1. Trackbar's Name, 2. Window's Name, 3.Trackbar's Minimum, 4. Trackbar's Maximum, 5. CallBack Function
cv2.createTrackbar('Low Threshold', 'Canny', 0, 1000, on_trackbar)
cv2.createTrackbar('High Threshold', 'Canny', 0, 1000, on_trackbar)
# Set Trackbar's Initial value
# draw close To Trackbar's Name, Window's Name
cv2.setTrackbarPos('Low Threshold', 'Canny', 50)
cv2.setTrackbarPos('High Threshold', 'Canny', 150)
# Input of Canny Edge is only GrayScale
img_gray = cv2.imread("Image_Sample.jpg", cv2.IMREAD_GRAYSCALE)
while (True):
# Bring The Now Trackbar's Position
low = cv2.getTrackbarPos("Low Threshold", 'Canny')
high = cv2.getTrackbarPos("High Threshold", "Canny")
# Modulate By Trackbar's Value
img_canny = cv2.Canny(img_gray, low, high)
# Show The Image
cv2.imshow('Canny', img_canny)
if (cv2.waitKey(1) & 0xFF == 27):
break
cv2.destroyAllWindows()
이 코드는 Image를 GUI를 이용해서 Canny Edge를 검출하는 코드이다.
# If Mediate THe TrackBar, CallBack Function
# You Can Insert openCV Function In here
# Dummy Function
def on_trackbar(x):
pass
만약 TrackBar을 사용하기 위해서는 Call Back 함수를 선언해줘야되는데
나는 Dummy Function을 선언했다.
# openCV Provide GUI Function Of TrackerBar
# Argument = 1. Trackbar's Name, 2. Window's Name, 3.Trackbar's Minimum, 4. Trackbar's Maximum, 5. CallBack Function
cv2.createTrackbar('Low Threshold', 'Canny', 0, 1000, on_trackbar)
cv2.createTrackbar('High Threshold', 'Canny', 0, 1000, on_trackbar)
# Set Trackbar's Initial value
# draw close To Trackbar's Name, Window's Name
cv2.setTrackbarPos('Low Threshold', 'Canny', 50)
cv2.setTrackbarPos('High Threshold', 'Canny', 150)
cv2.createTrackbar Function은 openCV에서 지원하는 GUI중 하나인 Trackbar을 Setting 해 주는거다.
Argument는 위에 주석으로 하나하나 적어뒀다
cv2.setTrackbarPos Function은 위에 설정한 Trackbar의 초기값을 잡아주는것이다.
이것도 주석을 잘 보면 도움이 많이 된다.
나름 열심히 달았어요
# Input of Canny Edge is only GrayScale
img_gray = cv2.imread("Image_Sample.jpg", cv2.IMREAD_GRAYSCALE)
이건 별거 아닌 코드이지만 Canny Edge를 다룰때는 중요해서 가져와봤다.
밑에서 나오는 Canny함수를 사용할때 Image의 입력값은 오로지 Grayscale이여야된다.
# Bring The Now Trackbar's Position
low = cv2.getTrackbarPos("Low Threshold", 'Canny')
high = cv2.getTrackbarPos("High Threshold", "Canny")
# Modulate By Trackbar's Value
img_canny = cv2.Canny(img_gray, low, high)
우선 cv2.getTrackbarPos는 TrackBar의 값을 가져오는 것이다.
cv2.Canny Function은 Canny Edge를 검출하는거다.
나는 트랙바를 이용해서 Canny의 Parameter(Threshold)를 조정할 수 있도록 했다.
그 밑의 코드는 쉬우니 생략한-다. 😑
[ Result ]
2. Using_Pressing_The_Key
import cv2
import sys
cap = cv2.VideoCapture(0)
if cap.isOpened() is False:
print("Camera Error")
sys.exit(1)
step = 1
while (True):
ret, img_frame = cap.read()
if (ret == False):
print("Fail To Capture")
break
if(step == 2):
img_frame = cv2.cvtColor(img_frame, cv2.COLOR_BGR2GRAY)
if(step == 3):
img_frame = cv2.Canny(img_frame, 30, 90)
cv2.imshow('result', img_frame)
key = cv2.waitKey(1)
if key == 27:
break
elif key == ord('1'):
step = 1
elif key == ord('2'):
step = 2
elif key == ord('3'):
step = 3
cap.release()
cv2.destroyAllWindows()
이 코드는 VideoCapture가 될 때
입력하는 Key Value마다 img_frame이 Original, GrayScale, Canny로 바뀌는 코드이다.
if(step == 2):
img_frame = cv2.cvtColor(img_frame, cv2.COLOR_BGR2GRAY)
if(step == 3):
img_frame = cv2.Canny(img_frame, 30, 90)
cv2.imshow('result', img_frame)
key = cv2.waitKey(1)
if key == 27:
break
elif key == ord('1'):
step = 1
elif key == ord('2'):
step = 2
elif key == ord('3'):
step = 3
어렵지 않다. 그저 key Value인 1,2,3을 입력함에 따라
변수에 Value를 넣고 특정 Value가 된다면
GrayScale과 Canny로 바꿔준다.
실행시켜보면 숫자를 누를때마다 자신의 얼굴이
바뀌는것을 볼 수 있을것이다 😐
3. Mouse_Event
이 코드는 Canny Edge와는 관련없지만
이번 글은 openCV에서 지원하는 GUI를 공부하자는 취지이므로
이 코드도 넣었다.
참고로 제일 길다.
import cv2
import numpy as np
import random
#Checking The Left Mouse Status
mouse_is_pressing = False
#Select The Draw Mode (Circle / Square)
drawing_mode = True
#Save The Value of Left Mouse Position
start_x, start_y = 1, -1
color = (255, 255, 255)
# Variable of Save The Image
img = np.zeros((512, 512, 3), np.uint8)
#If Mouse Event Trigger And Calling This Function
def mouse_callback(event, x, y, flags, param):
global color, start_x, start_y, drawing_mode, mouse_is_pressing
#If Moving The Mouse
if event == cv2.EVENT_MOUSEMOVE:
#If Pressing The Mouse And Moving
if mouse_is_pressing == True:
#Drawing Mode True == Drawing Square
if drawing_mode == True:
# Draw The Rectangle
cv2.rectangle(img, (start_x, start_y), (x, y), color, -1)
#Drawing Mode False == Drawing Circle
else:
cv2.circle(img, (start_x, start_y), max(abs(start_x - x), abs(start_y - y)) , color, -1)
# If Click The Left Mouse
elif event == cv2.EVENT_LBUTTONDOWN:
#Random Color
color = (random.randrange(256), random.randrange(256), random.randrange(256))
mouse_is_pressing = True
#Saving The Position
start_x, start_y = x, y
#If Release one's Hand
elif event == cv2.EVENT_LBUTTONUP:
mouse_is_pressing = False
#Drawing Rectangel Using Pressing Left Mouse And Release one's hand
if drawing_mode == True:
cv2.rectangle(img, (start_x, start_y), (x,y), color , -1)
else:
cv2.circle(img, (start_x, start_y), max(abs(start_x - x), abs(start_y - y)), color, -1)
elif event == cv2.EVENT_RBUTTONDOWN:
drawing_mode = 1 - drawing_mode
cv2.namedWindow("image")
cv2.setMouseCallback('image', mouse_callback)
while (True):
cv2.imshow("image", img)
key = cv2.waitKey(1)
if key == 27:
break
cv2.destroyAllWindows()
하나하나 뜯어보자
#If Moving The Mouse
if event == cv2.EVENT_MOUSEMOVE:
#If Pressing The Mouse And Moving
if mouse_is_pressing == True:
#Drawing Mode True == Drawing Square
if drawing_mode == True:
# Draw The Rectangle
cv2.rectangle(img, (start_x, start_y), (x, y), color, -1)
#Drawing Mode False == Drawing Circle
else:
cv2.circle(img, (start_x, start_y), max(abs(start_x - x), abs(start_y - y)) , color, -1)
조건을 하나하나 줬다.
1. 마우스가 움직이는가?
2. 마우스가 눌려있는가?
3. 원 / 사각형을 그릴것인가?
cv2.Event_MOUSEMOVE = 마우스가 움직였는지 체크해줌
cv2.rectangle = 사각형 그려주는 Function
cv2.circle = 원 그려주는 Function
# If Click The Left Mouse
elif event == cv2.EVENT_LBUTTONDOWN:
#Random Color
color = (random.randrange(256), random.randrange(256), random.randrange(256))
mouse_is_pressing = True
#Saving The Position
start_x, start_y = x, y
만약 마우스의 왼쪽 버튼을 눌렀을경우
도형의 색깔을 랜덤으로 주며, 마우스가 눌렸음을 True를 부여한다.
마우스가 눌린 위치 역시 필요하다.
#If Release one's Hand
elif event == cv2.EVENT_LBUTTONUP:
mouse_is_pressing = False
#Drawing Rectangel Using Pressing Left Mouse And Release one's hand
if drawing_mode == True:
cv2.rectangle(img, (start_x, start_y), (x,y), color , -1)
else:
cv2.circle(img, (start_x, start_y), max(abs(start_x - x), abs(start_y - y)), color, -1)
만약 왼쪽 마우스를 누르고 있다가 손을 뗀 경우에는 도형을 그려줘야하므로
마우스가 눌리지 않았음으로 표시하기 위해 False를 부여하며
(아까 누른 좌표 - 현재 좌표)까지 도형을 그려준다.
elif event == cv2.EVENT_RBUTTONDOWN:
drawing_mode = 1 - drawing_mode
도형을 무한정 그릴 수 없으니 오른쪽 버튼을 눌렀다면
False 혹은 True를 부여할 수 있도록 한다.
[ Result ]
오늘도 끄-읕😏
'openCV' 카테고리의 다른 글
[openCV] Draw Function (0) | 2021.02.06 |
---|---|
[ openCV ] Image Operation ( Blending, Operate Image Bit, ROI ) (0) | 2021.02.02 |
[openCV] Binarization (0) | 2021.01.23 |
[openCV] Numpy Array (1) | 2021.01.09 |
openCV - 기초부터 다지기 (0) | 2021.01.02 |