본문 바로가기

Robot/Robot Program - ROS

[R2R] 1-8 ROS2에서 Canny Edge Detector 구현하기

본 글은 제가 직접 쓴 글이 아니라, 저희 PinkLAB의 유투브 채널의 공개 강의 영상들을 읽고, 따라한 한 수강생의 글을 제 블로그에 공유한 내용입니다.

https://youtu.be/W-UjSR2Bv0I?feature=shared

안녕하세요,

오늘은 [ ROS2에서 Canny Edge Detector 구현하기 ] 라는 주제의 강의를 듣고 글 남겨봅니다.

우리는 Rush to Ros 실전 편 중에서 OpenCVROS를 어떻게 연결하는지 이야기를 하고 있어요.

그 중에서 오늘은 Canny Edge 이야기를 했어요.

지난번에는 카메라를 OpenCV로 열어서 토픽을 다루는 이야기를 했고,  

그러고 난 다음에 HSV 이야기를 했어요. 그러니까 이제 이걸 완성하고 싶은 거예요. 

이번에는 Canny Edge 하구요, 다음번에는 Cartoon Filter 이야기를 해 주신다 하셨답니다.

이제 Edge Detection 이야기를 해 볼게요.

Canny Edge 라고 부르는 아이가 있어요. 

OpenCV 에서 Edge Detection 하면

거의 끝판왕이 된다고 해요. 👑 

 

이 이미지는 위키백과에서 가지고 온 이미지구요,

일단 Canny Edge를 떠나서, Edge Detection 은 이렇게 외곽선을 따 주는 역할을 하는데요,

 

사람의 눈은 외곽선을 참 잘 따요. 무엇이 배경이고 무엇이 물체고 이런걸 금방 알아요.

근데 Edge를 Detection 하는게 그렇게 쉬운 일은 아니에요.

 

Pixel의 변화를 관찰 해서, 픽셀이 약간 평평하다가 갑자기 올라가면 그 부분이 경계선이지 않을까?
이런 것들을 Detection하는 여러 기법들이 있는데,

그 중에서 Canny Edge가 참 좋아요.

강사님께서도 개인 블로그에서 Canny Edge를 쓴 적이 있으시다 해요.

--> canny site:pinkwink.kr

 

 

Canny라고 검색을 해서 보시면

2020년 경 강사님께서 Python으로 OpenCV 이야기를 할 때 Canny Edge 이야기를 했던 적이 있다고 하셨어요. 

 

한 번 봐요. 이런 사진이 있을 때, 목표가 뭐냐면... 파란부분💙 을 선이라고 인식하게 하고싶은데, 그게 어려워요. 

그래서 여러 기법들 중에서 ,,

먼저 grayscale로 살짝 바꾸고

 

그 다음에 blur처리로 뭉개고,,

픽셀이 여기를 확대 해서 보면 


( 파란색 그림💙 ) 가다가 좀 끊어지다가 가고 이런단 말이에요.

이걸 블러 처리를 하면 뭉개져서 이렇게 샌드 처리하듯이 그렇게 되죠.

 

그 상태에서 Canny 함수를 통과시켜요. 

Canny Edge의 가장 큰 특징은 Threshold가 두 개예요.

그래서 이걸로 Detection을 하면 이렇게 Edge들만 나와요.

 

이 경계선들을 가지고 ROI( Range Of Interest, 관심 영역 ) 설정하고,

덮어씌우면 이렇게 선만 나와요.

이 상태에서 직선을 검출하는알고리즘이 하나 있어요.

[ Half Line 검출기 ] 라구. . . 그걸 통과시키면 

 

이렇게 직선이 만들어져요. 

( 강사님께서 예전에 블로그에 올렸던 적이 있다고 하셨어요.) 

 

Canny Edge의 개념이나 이런 걸 설명하는 게 아니라,

( 4구간으로 나누어 가지고 Threshold 2개 쓰고, 뭐 그런 이야기를 할 건 아니라고 하셨어요. )

Canny Edge라는 OpenCV 함수를 사용해서 Canny Edge Detection을 한 다음에 그걸 Ros Topic으로 발행하는 부분이에요.

전체 코드는 이렇게 구조를 잡고, main문 들어가고, if문 들어가고,

그 다음에 여기( class ) 부분이 핵심이에요.

class CannyEdgeDetector(Node):
    def __init__(self): -
    
    def parameter_callback(self, params): -
    
    def image_callback(self, msg): -

 

main문은 이렇게,

방금 전에 했던 CannyDetector를 불러오고,

ROS 스핀을 돌리고,

< Ctrl + C > 누르면 destroy_node 하고

shutdown 시키면서 꺼지도록 만들어 두셨어요. 

 

이제 전체 CannyEdgeDetector에서 __init__부분은 Node 상속 받고,

거기서 CannyEdgeDetector라고 Node이름을 잡아주었습니다. 

그리고 logger를 살짝 남겨줘요. 

그리고 Image_raw 토픽을 구독하도록 만들어뒀어요. 

그리고 결과,

엣지가 디텍션 된 결과는,

image_edge라는 이름의 토픽으로 발행하도록 publisher 선언 해 두었구요, 

 

그리고 아까 잠시 언급이 되었지만, threshold가 2개에요. 

Canny Edge는 그 2개의 threshold를 각각 Dynamic Reconfigure에서 쓸 수 있도록 이렇게 잡아줬어요. 

지난번의 HSV converter랑 조금 다른 것은, integer를 쓰고있다는 거예요.

IntegerRange라는 함수를 가져와서 쓰면 된답니다. 

그 다음에 이 부분에 get_parameter로 가지고 와야해요. 

그 다음에 parameter 변경에 반응하는 callback 함수를 또 만들어 뒀어요.

callback 함수의 역할화면에 logger를 남기는 것 뿐이라 하셨어요. 

변경된 logger 햠수를 프린트 해 주는 것, 딱 하나랍니다. 

 그리고 cv_bridge 만들어 두었어요. 

이게 핵심인데요, 

일단은 파란색 박스💙 속의 image_callback 함수는 image_raw라는 토픽이 들어 올 때마다 실행하는 거구요, 

그리고 image_raw가 들어왔을 때 threshold1, threshold2를 받아와요. 

이게 ros topic이니까, 이 토픽을 구독해서 OpenCV data로 바꾸게 된답니다.

8비트짜리 BGR로 바꾸는 거예요. (desired_encoding='bgr8')

 

그게 cv_image에요. 그래서 이 cv_image라는 변수는 OpenCV용 data예요. 

위 msg에서 던져준 아래 msgROS image type 인거구요, 

그걸 변환하는게 cv_bridge였어요.

 

그렇게 해 두고 cv_bridge를 가지고 와서 gray로 바꾸는 작업을 한 거예요. 

Edge Detection 은 gray 상태에서 하거든요. 그래서 gray로 꼭 바꿔야해요. 

 

그리고 gray로 바꾼 gray_image 이 아이를 threshold 두 개 여기서 받아 온 거예요. 

위 동그라미💙 속 threshold 두 개, 여기서 받아 온 threshold 두 개를 적용을 하고,

 

gray_image 를 적용을 해서, 

Canny라는 함수를 통과시킨거예요. 이게 전부랍니다!

Canny라는 함수를 통과시켰으니, 

아래 edges 이걸 갖구 

다시 cv2에서 ros 데이터 타입으로 바꾸는거예요. 

왜?

동그라미 💙속 edges 까지는 OpenCV data잖아요,

 

OpenCV 데이터를 가지고 와서 topic으로 발행을 하려면 

ros datatype으로 바꿔줘야해요. 

cv2_to_imgmsg를 이용해서 ros 데이터 타입으로 바꾸게 된답니다! 

ros 데이터 타입으로 바꾸는 데 성공했다면, 

성공했다면...

publish를 해 주면 된답니다! ( 너무 쉬운 이야기였다고 하셨어요! 글쓴이는 공부 더 열시미 해야겠어요 ! )

 

그리고 이제 launch 파일 하나 만들어줘야해요. 

edge_detection이나 launch 파일은 우리가 직접 만들어도 돼요. 

그런데 이 launch 파일은 어떻게 되어있냐면요..! 

 

보시듯이, cv_params.yaml 파일 에서 cv_parameter를 가지고 오도록 되어있구요,

그 다음에 img_pub 이게 뭐였냐면,

이 노드가 cv에서 바로 camera를 컨택 해서, camera를 읽어와서, image_raw라는 topic을 발행하는 아이였어요.

그래서 이걸 실행하고 그 다음에 방금 언급된 edge_detect를 실행하라는 뜻이에요. 

 

만약에 camerausb_cam 말고 다른 곳에서 실행 할 건데... 라고 한다면,

 

새로운 launch 파일 하나를 만들어서 빗금 친 부분은 안 넣고, 아래 괄호💙 부분만 넣으면 된답니다.

카메라 기동하는 launch 파일을 다시 쓰시겠다면,

 

우리 하나 만들어 뒀잖아요! bring_bringup_cv라는거 하나 만들어 뒀는데요, 여기가 카메라만 기동하는 아이였잖아요,

(launch 파일이)

bring_bringup_cv 이것만 실행하고, 따로 할 거라면,

x 부분💙 이 부분만 빼도 되고, 다시 빌드를 하던지

 

파일을 카피 하셔서 x부분💙을 빼고 저장!

하신 다음에 아래 괄호부분💙만 실행하도록 하셔도 된다고 해요. ( 2가지 방법! )

 

강사님께서는 이렇게 구성을 해 두신거고,

launch 파일이 따로 있다는 건, launch 파일은 항상 수정하고 쓰셔도 괜찮아서,

직접 수정해서 쓰셔도 된다고 하셨어요.

코드 실행하는 방법을 이제 이야기 해 볼게요.

 

여기에 이미 넣어두셨어요. 여기에서 조금씩 바뀔 수는 있어요.

opencv_tutorials_for_ROS2 라는 repository유튜브 일정에 맞춰서 계속 업데이트가 되고 있어요,

그래서 이 영상을 보고 찾아가신다면, 시점마다 조금씩 변경이 될 수는 있다고 하셨어요.

그 부분은 조금 감안 해 주세요..!! 😊

 

그래서 지금은 어디까지 들어가있냐면,

여기 보면 아직 영상 cartoons도 지금 들어가 있긴 있는 상태이긴 해요.

 

그리고 여길 찾아가는 방법은 Google 창에서 pinkwink github라고 검색을 하면 된답니다!

 

강사님의 개인 Repositories인데요, 

Repositories - opencv_tutorials_for_ROS2  로 찾아가시면 된답니다.

여기서 받으시면 되는데요, 

이건 왜 가이드를 해 주셨냐면..

이전 영상에서 이전 버전의 git 을 받으신 상태라면, 

싱크를 맞추려면,

먼저 my_opencv_tutorials 폴더로 가서 

sudo rm -r build install log src

 

build, install, log, src 폴더를 다 지워요. 다 지우고.. 

src 마저 다 지워버렸잖아요,

그러니까 다시 src 를 만들어요.

만들고 src 로 이동 한 다음에,  방금 전에 그 repositories 를 git clone 으로 가지고 오면 된답니다.

방금 전에 그 repositories 를 git clone 으로 가지고 오면 된답니다.

그러고 난 다음에 다시 workspace로 이동해서, 

colcon build 를 하면 돼요. 

지금까지의 과정을 보여드린 이유는 뭐냐면요, 

이전 영상, 바로 직전 영상을 실시간으로 보신 분들이라면, 코드가 바뀌었거든요, 

그래서 다시 가지고 오라고 하신거예요. 

연습하시느라 업데이트를 하는 것 보다는! 그냥 clone을 하실 거라면, 다 지우고 하시는게 어떠신가요~? 라는 뜻 이에요. 

 

그렇게 해 두고, 이건 alias 설정을 해 둔거였어요. 

install 폴더 안에는 local_setup.bash를 부르는 alias를 따로 세팅 해 두었단 말이에요, 

그래서 my_opencv_tutorials를 부르시고 난 다음에 ros2 launch my_opencv_tutorials의 edge_detect.launch.xml 하면 

아무것도 안떠요. 여기 글자들만 막 떠있어요. 

 

그러고 나면 또 다른 터미널에서 my_opencv_tutorials ( alias ) 부르시고, 환경을 부르시고, 그 다음에 rqt를 실행하시면 돼요.

 

그럼 이렇게 나와요! 짜잔! ( 10:42 ) 

그리고 이제 이 화면은 어떻게 나오는지 지난 영상에서 보셨으니 기억이 나실거예요.

plugins 들어가셔서 dynamic_reconfigure를 찾아요.

그러고 잘 안 나오면 refresh 하신 다음에 Canny Edge Detect 찾으시고,

 

threshold를 조금씩 받고 가 보면 화면이 바뀐답니다.

여기까지가 사용법 설명이었어요.

OpenCV에서 Canny 함수를 사용하는 건 그냥 쉬운 일이고,

Edge Detection도 잘 되는 편이에요.

그리고 특별한 진입장벽이 있지는 않아요.

ros package를 이용해서 Edge Detection을 어떻게 구현했는지를 보여주셨어요.

 

실제 코드가 어떻게 동작하는 지 보도록 해요.

Edge Detect라는 함수를 여기서 만들어두셨어요.

 

그 다음에 setup.py에 여기 Edge Detect 가 들어가있어야해요.

그리고 물론 다 돼 있어요. 여러분들이 Git Clone 받아보시면요. 

 

그리고 Edge Detect Launch 파일에 가 보면 이렇게 구성이 되어있어요. 이 상태에서 볼게요. 

ls에서 보면 my_opencv_tutorials가 여기 있단 말이죠, 여기에 이 상태에서 

 

만약 지운다고 하면,

sudo rm -r build/ install/ log/ src/

명령어로 build 폴더, install, 폴더, log 폴더, src 폴더를 다 지우라는 거예요. 

ls 해 보면 아무것도 없어요. 

 

이 사이트에서 주소 복사하시고,

그 다음에 mkdir 명령어로 src 폴더를 만드시고

그 쪽으로 넘어가서 Git Clone 명령어로 Ctrl + Shift + V 붙여 넣어서 코드를 받으시면 된답니다.

그렇게 하고 빌드는 워크스페이스에서 해야해요.

build 는 work space 로 가서 jazzy 를 부르시면 된답니다. 

 

우리는 alias 설정을 이렇게 했어요. 

humble에서도 이 코드는 동작을 해요.

우리 수업 입문 편을 보시면, humble 버전 기준으로, alias를 어떻게 만드는지 말씀을 드렸고, 

그 다음에 실전편을 시작하면서 jazzy 버전에서 alias를 어떻게 만드는지를 이야기 드렸어요. 

 

jazzy라는 alias는 어떻게 만들어진 거냐면요, 

alias | grep jazzy 이렇게 해서 보시면,

 

alias jazzy라는 것은 source 명령어로 

opt ros jazzy의 setup.bash를 부르도록 해둔 거예요.

 

ros_domain_id 설정 잡아주었고,

내가 무슨 (짓ㅋㅋ)을 했는지 프린트 당한거예요.

그래서 jazzy라고 부르면 이렇게 ROS_DOMAINID는 13번이었고, 

ROS2 jazzy를 활성화했다 라고 뜨는 거랍니다. 

이 상태에서 colcon build 되었어요.

빌드 완료 되었답니다. 이제 뭘 할까요 ?

빌드를 했으면 환경을 불러줘야해요. 

강사님께서는 alias 에서 my_open_cv란 alias를 만들어 두었단 말이에요.

그래서 여기서 alias 만들기 싫으신 분들은 source 명령으로 install 폴더에 local_setup.bash를 부르셔도 된답니다.

my_opencv_tutorials를 불렀고, 이제 build 했고, 환경도 불렀으니 실행 할 수 있는 거예요.

ros2 launch my_opencv_tutorials에서 edge_detect.launch.xml을 실행하는 거예요.

 

그러면 이렇게 log들이 남았구요,  

log들이 남았네요.

이제 또 다른 터미널을 열어서 역시 my_opencv_tutorials를 부르시고,

my_opencv_tutorials랑 똑같은 것은,

source 명령으로 opt/ros/humble이면 humble, ( jazzy면 opt/ros/jazzy)

= source /opt/ros/humble/setup.bash를 부르고, (jazzy면 source /opt/ros/jazzy/setup.bash)

source 명령어로 현재 폴더 workspace 기준이에요.

여기 ls에서 보시면, install 폴더가 있잖아요,

그래서 이거 기준으로 source 현재 폴더의 install 폴더에 있는 local_setup.bash도 부르고,,, (source ./install/local_setup.bash)

물론 이렇게만 할 거면 여기에 있는 setup.bash를 부르면 되지만,

강사님께서는 [ source /opt/ros/jazzy/setup.bash ] 와 [ source ./install/local_setup.bash ] 사이에서

ROS_DOMAINID도 설정을 하셨어요.

그래서 그 내용들이 맨 위의 [my_opencv_tutorials] 이랑 같이 붙어있는 거예요.

이제 이 상태에서 rqt를 실행하는 거예요. GO! ! 

 

강사님께서는 이미 셋팅을 다 해 두셔서 녹음하는 화면이 나와요.

짠 ! 아유 귀여워~~ (--->는 강사님께서 하신 멘트에요!!!!!!!!! 오늘도 웃음을 ㅋㅋ ) 

얼굴이 안 보이면 귀여우시다 합니다. (😂😂😂) 

여기에 이 Parameter Reconfigure는 어디에 있는 거냐면요,

여기 plugins의 Configuration Dynamic Reconfigure가 있어요. 

 

여기에서 간혹 우측 list가 보이지 않으면, Refresh를 눌러보세요. 그럼 나와요. 

여기서 threshold를 만져보면 뭔가가 바껴요.

이렇게 자잘하게 할 거냐, 

 

더 둔감하게 할 거냐, 그것도 조절 할 수 있어요. 

아까 설정이 더 귀여운 것 같으시대요. ㅋㅋㅋ

빵끗 웃어보시는......😊  라인만 나와서 자신감이 생기고 좋으시대요. ㅋㅋㅋㅋ

이 계기로 엣지 디텍션 해서 녹음을 하기 시작하신 듯 합니다!

이후 영상들은 대부분 라인을 따서 강의를 진행하고 계시니까요 ㅋ.ㅋ

너무너무 재밌는 시간이네요 ㅋㅋㅋㅋ 😂

키읔이 너무 많은 점 양해를 구해요

여러분도 같이....... 웃어요. 혼자 웃기 아까운...ㅋ_ㅋ (15:45)

여기멘트는 진짜 진짜 직접 들어봐요. 16:00 ^^^^^^

 

 

오늘도 고생 많으셨습니다, 

글을 쓰는 지금은 비가 많이 오는 시기랍니다... 모두모두  무사하시기를 바라며... 

다음시간에 건강하게 만나요 😊

반응형